TLDR: In CSS, when you specify margin height using a percentage, that height is calculated using that percentage against the width of the parent object.
The only workaround that I have found (as of June 2014), assuming you want the margin to be set to a percentage of the height of the parent object, is to use JavaScript.
CSS Margin Height In Percent is Calculated Using the Width of the Parent Object
Here we have an inner div and an outer div. The outer div has a height of 100 pixels and a width of 200 pixels with a red background color.
The inner div has a height and width of 90% and a 5% margin. Using simple grade school math, you can see that 5% margin on the left plus 90% plus 5% on the right equals 100% and that is correct. There is no horizontal scroll bar.
The weirdness comes into play when you try to do the math on the height. 5% on the top, plus 90%, plus 5% on the bottom should equal 100% but it obviously doesn't as we have a scroll bar. The problem here is that CSS computes margin height as a percentage of the parent object width.
Assuming that you want to have a top and bottom margin that are based on the height of your object, the only solution that I have found is to fall back to JavaScript. My sample code requires jQuery.
The following function returns a function that computes and sets margins on elements to be whatever the passed-in percentage is set to.
function SetMarginHeightPercent(percent, edge) { if (edge === undefined) { edge = "both"; } return function () { var self = $(this); var fivePercent = self.parent().height() * percent / 100; var css = {};if (edge !== "top") { css["marginBottom"] = fivePercent + "px"; } if (edge !== "bottom") { css["marginTop"] = fivePercent + "px"; } self.css(css); }
}
This function is called like this:
$(".marginHeight") .resize(SetMarginHeightPercent(5)) .each(SetMarginHeightPercent(5));
where the selector ".marginHeight" is any valid jQuery selector for an object that you want to adjust the vertical margins on and 5 is the percentage of parent's height that you want to set the margin to.
The ".each" command runs the function immediately on all of the affected objects and the ".resize" command runs any time that object is resized so that you percentage will be constantly maintained.
If you wish to set the top and bottom margin to different percentages, you can call the function like this:
$(".marginHeight") .resize(SetMarginHeightPercent(3,"top")) .resize(SetMarginHeightPercent(7,"bottom")) .each(SetMarginHeightPercent(3,"top")) .each(SetMarginHeightPercent(7,"bottom"));
Generally, I prefer not to use JavaScript for styling. It is more appropriate to learn how to do styling in CSS. However, there are occasions when CSS is either very complex for a simple JavaScript task or where something just isn't possible in CSS. In that case, it is nice to know that you can pull out the JavaScript and get the page styled the way you want.