Table of contents
Margin collapse is an interesting concept in CSS margins that you should know, understand and be conscious of. It is the process where you apply a margin of 10px on top, the bottom of an element, apply another 10px on top, the bottom of the next element, and end up having a 10px space between the two-element instead of 20px.
The space between p
elements above is supposed to be 20px because 10+10=20 right? But then it's 10px. Why? How? This is margin collapse and in this article, I want to show you why, how, and help you master it in less than 7 minutes.
A good way to visualize the code examples in this article (like this one above) is to open op your devTools and inspect the elements (i.e p), hover over the element and the margins of the elements will pop up in a light orange color. Let's experiment with the example above:
Open up your web dev tools
Click on the "arrow" icon at the top right of the dev tools or simply type
ctrl+shift+c
Click on any of the
p
elements in the document, try clicking "Hello World"In the element's dev tools section, hover over the element, and a light orange color will pop up; that is the margin
Hover over the other p element, and the same thing will happen, but you'd notice that it seems like the light orange color of the first element you hovered on is at the same position of the second; this is the effect of margin collapsing.
Use this method to go over the examples that will be used in this article.
First, let's make a quick recap of what margins are and their usefulness. Margin is an important aspect of styling elements in CSS, it allows us to add spaces between elements, or as some might say gives breathing room to the element applied. Apart from the margin, there is also another guy in the box model padding that does the same thing as margin. But they are different and should be applied differently
Margin vs Padding
One key difference is that Margin was designed for creating spaces between sibling elements whereas Padding was designed for creating spaces between a child and parent element. Understanding this changes everything.
It is not that margins cannot be used to create spaces between a child and parent element (you may have probably done that) but you would have unexpected issues when margins start collapsing. Here is one of these issues
Now that we have that setup, let's try to increase the space between the h1
element and the .box
element using the margin-top
property. Change the value from 0
to 20px
and see what happens.
Now it looks like we're pushing down the whole of the .box
element, and we still don't see the space between the h1
and .box
elements. Try increasing it from 20px
to 200px
. Still no spaces? How? This is what happens when you use margin for creating spaces between a parent and a child element, they collapse, and then the purpose of margin is actualized between the .empty
and .box
elements. I will explain later.
One other difference that will also be useful in the course of this article is the order of the box model. In the box model, we have in ascending order
- the height and width of the element
- the padding
- the border
- the margin
This is one other thing that makes creating spaces between a child and parent element is more suitable with padding. Borders are the limit of an element, if you want to create a space between a child and parent element, whether you want to apply a border or not (to the parent element now) you should respect the border limit and create spaces between the border limits. And the only guy you can use to create spaces within the border limits is padding, not margin.
Think of it this way, every country in the world has
- the residential areas (height and width of element)
- the spaces between residential areas and the border of the country (passing)
- the border of the country (border)
- and the spaces between the border of country A and border of country B (margin) - this can be 0 in some cases like North Korea and South Korea.
So if a leader of country A wants to create more spaces between his/her country's residential areas and country B, the solution is not to increase the margin - because that may lead to a world war rather the solution is to increase the padding. As such country B will have no business with the leader because he/she is respecting its country's border limits.
So try to hold on to the order of the box model, I will come back to it later.
So now that we've gone through what margins are, let's jump right into margin collapse.
Margin Collapse
Margin collapse happens when element A's margin overlaps element B's margin or vice versa based on some conditions or rules. Just two years ago we were all asked to maintain social distancing by maintaining a 6ft gap between you and every other person. Now what this means is that one person should have a 6ft margin around him/her.
If John, for example, meets with Doe for a talk, though they have a 6ft personal space it doesn't mean that they must have a 12ft gap as per the social distancing. Social distancing says at least 6ft, so they can easily overlap their personal space to maintain a 6ft gap. This way I believe they can hear each other well enough.
This is the way margin collapse works, it lets us establish the necessary amount of space between two elements. So now as a CSS developer, our role is to understand when we need our margins to collapse, when we should expect our margins to collapse, and when we shouldn't expect our margins to collapse.
It's not as easy as "Oh cool, all margins collapse, really cool." No, not at all, there are times when margins don't collapse. So we might just expect two margins to collapse and give us 10px
, and all of a sudden we get 20px
. On the bright side, we can know when margins will and will not collapse.
As such it won't be a matter of trial and error, but we'd be sure if it will collapse or not. There are some conditions/rules that margins rely on before they can collapse. We will quickly go over these conditions as
When Do Margins Collapse
1. When Vertical
Only vertical margins collapse. The left and right margins of the two horizontal elements will not collapse.
You'd notice that the margins between the li
elements are 20px each, vertically this would not happen, because it will collapse to give us 10px:
NOTE: You should note that when two margins collapse the bigger margin always wins, from the example above if we make the middle li
to have a margin of 20px, we will end up with both the first and last li
having a margin of 20px in the bottom and top respectively.
2. When the parent element is in flow layout
Margins of nested elements whose parent is not in flow layout will not collapse. There are multiple layouts on the web, that is flow layout, grid layout, flex layout.
Just like from the example above, the parent element ul
is in a flow layout, so the margins of the child elements will collapse. Even if the parent element is body
, it will collapse because body
is also in flow layout
But this will not be the case if we set the parent element to flex
or grid
.
So basically from conditions 1 to 2, we've seen that only margins of block elements will collapse.
3. When an element is not absolutely positioned or floating
When an element is absolutely positioned or floating, its margin will not collapse. It will also not collapse if the element is not fixed.
{% codepen codepen.io/elijah-trillionz/pen/RwjzKaM default-tab=html,css editable=true %}
Also when an element is floating, margin collapse is disregarded
4. When siblings are adjacent and not obstructed
So far we've been seeing sibling elements collapse or not collapse based on some predefined style on the parent or child element. But margins of two or more elements can be stopped from collapsing when there obstructing elements like hr
or br
.
Even the tiniest bit of height for an empty element can obstruct margin collapsing.
So the elements have to be adjacent (touching) for it to collapse.
5. When you do the weird thing
I know you must be curious to find out what this weird thing is, well I already made mention of it earlier. The weird thing is using margin to create spaces between child and parent elements instead of padding. Now it is only weird to me, it can be totally fine with you as long as you know the maneuverings of it.
And yeah, that's what am going to talk about here in this section, how to maneuver your way to using margins for creating spaces between child and parent elements without having the problem we had earlier. That is:
We said if you increase the margin-top
of the h1
tag, rather than it creating a visible space between the parent and child element, it creates more space between the .box
and .empty
element. This is because the child element (h1
) which has the margin, collapsed with the parent element' (.box
) margin.
Think of it as the child element passing its margin to its parent element. But when it passes its margin to the parent element it doesn't add to the parent element's margin, rather it collapses it. By default, the .box
element has a margin of 0 just like every other element, but if we increase it to 5px
and increase the child element's margin-top
to 10px
, the margin between .empty
and .box
would not be 15px
rather it would be 10px
- because the bigger margin wins when collapsing occurs right?
It's not confusing, trust me. All we are saying here is that margins of nested elements can collapse with the margin of their parent element.
<style>
.box {
margin-top: 15px;
}
h1 {
margin-top: 5px;
}
</style>
<body>
<div class="box">
<h1>I am not empty</h1>
</div>
</body>
Here is a visual illustration
So no matter the margin you use for the child element, it is just going to collapse it with that of the parent and end up creating more space between the parent element and its sibling (if any). But some things can prevent this from happening
Padding
When we add padding to the parent element we can hinder the margin of the child element from collapsing with that of the parent.
<style>
.box {
margin-top: 15px;
padding-top: 10px;
}
h1 {
margin-top: 15px;
}
</style>
<body>
<div class="box">
<h1>I am not empty</h1>
</div>
</body>
For the margin to not collapse the parent element should have padding that is in the same direction as the margin to collapse. This means if you change the padding-top
to padding-bottom
it will not stop the margins from collapsing because the padding is in the opposite direction.
So if you want to specifically hinder only the top of an element's margin from collapsing with its child, you'd have to use the corresponding padding for it. Then, to hinder the all-around margin from not collapsing you just apply padding all-round.
.box {
margin: 15px;
padding: 3px;
}
h1 {
margin: 15px;
}
The size of the padding doesn't really matter it could be as tiny as 1px
, it would still stop the margins from collapsing. You might ask "can't we use padding on the child elements too?", I will answer that in the next section.
Border
Borders do the same thing as padding in this regard. Using any size of border on the parent element will prevent collapsing.
When we add another element to act as a sibling to .box
, neither the padding nor border of .box
will stop the margins from collapsing with the new element
This is because the padding and margin rule only applies to the nested elements of that element. Neither padding nor border can stop the margins of two sibling elements from collapsing simply because they don't have the access to the margins of the element.
Recall that in the box model, we had padding, before border, and finally before margin. The only way padding or border can stop two margins from collapsing is if the padding or border is in between the two margins. And that only occurs between parent and child elements.
Here we have a parent element with a border, the border of this parent element is now above the margin of the child element, while still under the margin of the parent element. So already it's in between the two margins, it won't let them collapse. The illustration below will make it a little clearer.
This is not the case for sibling elements, because the border or padding of any of the elements is not superseding the margins of the other, this is the way it looks in sibling elements.
Gap
One other thing that can cause the margin of a parent element from collapsing with that of its child is when there is a gap between them. This occurs when the height/width of the parent's element is beyond that of its child.
<style>
.box {
margin-right: 15px;
width: 400px;
}
h1 {
margin-right: 15px;
width: 250px;
}
</style>
<body>
<div class="box">
<h1>I am not empty</h1>
</div>
</body>
6. Negative margins can collapse too
Alright, now let's talk about negative margins. Two or more negative margins can collapse together. Just like we've seen with positive margins, the biggest negative margin is used over the smallest.
Negative margins can also collapse with positive margins, as such the margins will be added together. From our example above, if the margin-top of other-box
is 15px, then we'd have a -15px
margin between the two elements.
Conclusion.
It would save you a lot of stress and confusion if you just understand how it works, do some practice on it to make it stick. People who think margin collapse is not a big deal are those who wind up increasing margin size unnecessarily. When you know where you need your margins to collapse you can easily benefit from its benefits, then when you don't need it to collapse you can stop it from collapsing.
Alright, that's it for this article, let me know what you think about margins collapsing in the comment section. Also, remember you can hit me up on Twitter @elijahtrillionz if you need me, and please try to follow. Thanks for reading, see you next time.