Table2CSS logo Table2CSS is a tool that can convert your table-based websites to tableless layouts, replace deprecated HTML tags with modern CSS and reformat your HTML code. Click here for more information

Vertical margin collapsing in modern web browsers

What are CSS margins?

Margins are a way to specify in CSS that the web browser should leave a specified amount of space around some HTML elements when laying out the page. After CSS became the standard for styling of HTML pages, web designers started using margins for defining the spacing between HTML elements and thus controlling the layout of web pages. Indeed in many cases it is much easier to specify the element spacing by using the CSS margin properties instead of using absolute or relative positioning.

How to use CSS margins for spacing and positioning of elements?

Let's say that we want to position two boxes on the page leaving 30 pixels of vertical space between them like the ones on the image below: Example of using margins In order to achieve this kind of spacing positioning we will use CSS margin-top property. The HTML and CSS code that we use is:

<div style="background-color: #00CCFF; width: 145px; height: 83px;"></div>
<div style="background-color: #FFA200; width: 145px; height: 83px; margin-top: 30px;"></div>

After testing our sample code we see that it performs just as we expected, creating a blue box and a green one below with 30 pixels of space between them.

What undersired effects can be caused by margin collapsing?

The above simple example worked pretty well, so now let's try something more complex, e.g. to nest a smaller box inside the second one and to offset it vertically from the top of the second box, like the ones on the image below: Expected result So we write the following code and try it in our web browser:

<div style="background-color: #00CCFF; width: 250px; height: 114px;"></div>
<div style="background-color: #FFA200; width: 250px; height: 300px; margin-top: 30px;">
	<div style="background-color: #42DB14; width: 190px; height: 81px; margin-top: 50px; margin-left: auto; margin-right: auto;"></div>
</div>

However after we test the code in our browser we see that it doesn't look exactly like with expected it. The top of the green box is aligned with the top of the brown one and the space between the blue and brown boxes is 50 pixels instead of 30. Our code seems correct, so there is something else that is causing this effect. Actual result

The culprit causing this problem is the so-called "vertical margin collapsing". The CSS 2.1 specification states: "Two or more adjoining vertical margins of block boxes in the normal flow collapse. The resulting margin width is the maximum of the adjoining margin widths... The top margin of an in-flow block-level element is adjoining to its first in-flow block-level child's top margin if the element has no top border, no top padding, and the child has no clearance. The bottom margin of an in-flow block-level element with a 'height' of 'auto' and 'min-height' less than the element's used height and 'max-height' greater than the element's used height is adjoining to its last in-flow block-level child's bottom margin if the element has no bottom padding or border."

Basically what the above text says is that if we have nested block elements (in our example these are the brown box which contains the little green box) and the parent element (the brown box) has no top border and no top padding, then the top margin of the first child box (the green box) will become the top margin of the parent (the brown box).

Same goes for the bottom margin - it is possible for the bottom margin of the parent container to merge with the bottom margin of its last child if the parent has neither bottom padding nor bottom border.

Please note that this kind of margin collapsing it present only with block elements that don't have vertical padding and borders. Inline and inline block elements are not susceptible to this problem. Same goes for left and right margins of block elements - they never collapse.

This kind of margin collapsing can lead to problems even when we are not explicitly trying to create vertical space between block elements. Let's say that we have two adjacent blocks and the second one has a nested <h1> element. We would expect the result to look like this: Expected result when using H1 However what we actually get is: Actual result when using H1 Again this difference is caused by the vertical margin collapsing. The top margin of the brown box collapses with the top margin of the <h1> element causing the problem.

How do different browsers handle vertical margin collapsing?

This kind of vertical margin collapsing is performed by all modern browsers including IE7 and newer. Please note that IE6 does not collapse vertical margins in this way.

How to avoid the undesired vertical margin collapsing?

Remember that margin collapsing happens only when the parent element doesn't have any border or padding? Knowing this gives us an easy workaround instead of positioning the inner block elements by giving them margin, we will give non-zero top/bottom padding to the parent container. Here is a diagram showing the idea behind this workaround: Workaround method 1 This is the code that implements this workaround:

<div style="background-color: #00CCFF; width: 250px; height: 114px;"></div>
<div style="background-color: #FFA200; width: 250px; height: 300px; margin-top: 30px; padding-top: 50px;">
	<div style="background-color: #42DB14; width: 190px; height: 81px; margin-left: auto; margin-right: auto;"></div>
</div>

Another variation of the workaround with the padding is to give the parent container a minimal 1 pixel top padding just to disable the margin collapsing. Here is how we would do it in the case with the <h1> tag:

<div style="background-color: #00CCFF; width: 250px; height: 114px;"></div>
<div style="background-color: #FFA200; width: 250px; height: 300px; margin-top: 30px; padding-top: 1px;">
	<h1>Some text</h1>
</div>

In cases where we cannot or don't want to use padding, we can just give the top container a transparent top/bottom border. Here is an diagram explaining the idea: Workaround method 2 If we are to solve the problem with the <h1> tag using the border-top workaround it will look like this:

<div style="background-color: #00CCFF; width: 250px; height: 114px;"></div>
<div style="background-color: #FFA200; width: 250px; height: 300px; margin-top: 30px; border-top: 1px solid transparent;">
	<h1>Some text</h1>
</div>

Conclusion

The vertical margin collapsing of block elements can lead to some unexpected effects with the layout of your HTML pages. However it is relatively easy to work-around this issue at the cost of a some extra CSS code.