loading...

CSS Margin Collapse

ziizium profile image Habdul Hazeez Updated on ・6 min read

Margin collapse is one of the tricky things about margins in CSS and it's a foundational concept in understanding the CSS Box model. Not knowing when a margin collapse, can be a point of frustration and when they do you just have to deal with it. This post will attempt to introduce and treat this concept in a beginner-friendly approach with code snippets and images from the browser Developer Tools.

From the previous post, we learned that the margin property applies to block level element and it's a shorthand for four other properties:

  • margin-top
  • margin-right
  • margin-bottom
  • margin-left

Now, when the margin-top and margin-bottom of this element combine into a single margin whose size is the largest of the individual margins (or just one of them, if they are equal). This behavior is known as margin collapsing and it usually occurs in three cases:

  • Adjacent siblings
  • No content separating parent and descendants
  • Empty blocks

ADJACENT SIBLINGS

From the Mozilla Developer Network (emphasis mine):

The margins of adjacent siblings are collapsed (except when the latter sibling needs to be cleared past floats).

This translates to: If you have one or more block-level elements appearing one after the other from the top of the page i.e vertically, their margin will collapse.

Let's explain with code.

Don't forget to create your HTML and CSS files to follow along, and remember all HTML snippets will be in the body tag.

Given the code snippet below:

<div class="parent">
  <div class="child"></div>
  <div class="child two"></div>
</div>
/* cosmetics*/
.parent {
  margin-top: 32px;
  margin-right: auto;
  margin-left: auto;
  margin-bottom: 32px;
  background-color: rgb(200,200,200);
  width: 500px;
}

/*
 * The real deal is the margin-bottom value, the rest
 * are cosmetics.
*/
.child {
  margin-top: 30px;
  margin-right: 20px;
  margin-bottom: 50px;
  margin-left: 20px;
  width: 100px;
  height: 100px;
  background-color: #1560bd;
}

.child.two {
  margin-top: 20px;
  background-color: red;
}

From the snippet above, the margin-bottom of the child element is 50px and we gave the adjacent box a margin-top of 20px. Normal intuition will tell you that these values should add up since they are block-level element's and the space between .child and .child.two should be 70px, but that's not the case.

Save your files and load the HTML in your browser, Use "Inspect Element" on the blue box, Navigate to the Layout tab and click on the Box Model, you will realize that the space between the blue box and the red box is still 50px even though the red box has a margin-top value of 20px, the browser did not take this value into consideration. When something like this happens, the margin is said to have collapsed.

Margin Collapse in CSS

But what happens if we have one negative margin value? This will cause a slight deviation in the behavior of margin collapsing and the positive and negative margins will be added together to reach the final margin.

This means if our blue box has a margin-bottom of 50px and the red box has a margin-top of -20px, the browser will calculate the margin between them as:

  • 50 + (-20) => 50 - 20 => 30

The value gotten from the above calculation will be the space between the boxes.

Change the margin-top of the .child.two CSS rule (the red box) to a negative value:

.child.two {
  margin-top: -20px; /* Add this */
  background-color: red;
}

Save your CSS file, and refresh your browser. The red box will now move up a little bit and will occupy part of the bottom margin of the blue box.

Margin Collapse in CSS

NO CONTENT SEPARATING PARENT AND DESCENDANT

The title says it all, but Mozilla Developer Network has more:

If there is no border, padding, inline part, block formatting context created, or clearance to separate the margin-top of a block from the margin-top of one or more of its descendant blocks; or no border, padding, inline content, height, min-height, or max-height to separate the margin-bottom of a block from the margin-bottom of one or more of its descendant blocks, then those margins collapse. The collapsed margin ends up outside the parent.

Update your CSS and HTML with the code below:

<h1>This is the header</h1>
<div class="parent">
  <p class="child">Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
.parent {
  margin-top: 50px;
  margin-right: 0;
  margin-bottom: 25px;
  margin-left: 0;
  outline: 5px solid red;
}

.child {
  margin-top: 20px;
  margin-right: 0;
  margin-bottom: 0;
  margin-left: 0;
  background: #1560bd;
  color: #ffffff;
}

Save your files and refresh your browser, you will notice that the browser did not render the margin-top property of the child element because the .parent has a higher margin-top value of 50px, but the browser knows the margin-top value of the child. How? Perform the following steps:

  • Use "Inspect element" on the paragraph
  • Navigate to the Layout tab
  • Click on the Box Model

You will notice that the browser actually recognized the 20px.

Margin Collapse in CSS

And if you hover your mouse (or pointing device) over the margin value in the box model, the browser will highlight (in yellow) where the margin should have occupied in the web page, but, the margin is not rendered because it collapsed with the parent margin.

Margin Collapse in CSS

EMPTY BLOCKS

Empty blocks are block level element with no content. And If there is no border, padding, inline content, height, or min-height to separate these block's margin-top from its margin-bottom, then its top and bottom margins collapse.

Update your CSS and HTML to match the following snippet.

<div class="box"></div>
.box {
  background: red;
  width: 120px;
  margin-top: 20px;
  margin-bottom: 50px;
}

Save your files and refresh your browser. Use the Developer Tools to view the Box Model, hover your mouse over the yellow area of the Box Model you will notice that the margin bottom is not rendered but the browser acknowledge its value in the box model (highlighted in the image).

Margin Collapse in CSS

However, if you give the empty block a height or min-height, it will not collapse.

.box {
  background: red;
  width: 120px;
  margin-top: 20px;
  height: 120px; /* Add this */
  margin-bottom: 50px;
}

Margin Collapse in CSS

The question now is How can we stop margins from collapsing?

PREVENTING MARGIN COLLAPSE

From previous explanation we can realize that only consecutive elements can collapse into each other. Putting an element with a non-zero height between our elements forces them to display their margins. This element can be a border or a padding.

Let's demonstrate.

Refer to the code snippet under NO CONTENT SEPARATING PARENT AND DESCENDANT, add a border declaration to the CSS .parent rule:

.parent {
  margin-top: 50px;
  margin-right: 0;
  margin-bottom: 25px;
  margin-left: 0;
  outline: 5px solid red;
  border-top: 1px solid #000; /*Add this*/
}

Save your file and refresh your browser. The margin will now take effect.

Preventing Margin Collapse

Now delete the border declaration you just added to the .parent CSS rule, and add the following to your HTML just before the paragraph with the .child class:

<div style='padding-top: 1px'></div>

Save your file and refresh your browser, if you've done everything right you will get the same result similar to when you applied a border with CSS.

Another way to avoid margin collapsing is to consider applying only top margin or bottom margin to elements

Note that the margins of floating and absolutely positioned elements never collapse.

Speaking of Positioning. That's Next.

Posted on by:

ziizium profile

Habdul Hazeez

@ziizium

I teach and write code with interests in Web Development, Computer Security, and Artificial Intelligence.

Discussion

pic
Editor guide