Margin collapsing in flexbox
CssFlexboxCss Problem Overview
Typically, in CSS, when a parent and its last child have a margin, the margins collapse to create a single margin. E.g.
article {
margin-bottom: 20px
}
main {
background: pink;
margin-bottom: 20px;
}
footer {
background: skyblue;
}
<div id="container">
<main>
<article>
Item 1
</article>
<article>
Item 2
</article>
</main>
<footer>Footer</footer>
</div>
As you can see, even though a margin of 20px
is specified on both the article
and the main
tags, you only get a 20px
margin between the last article and footer.
When using flexbox, however, we get a 40px
margin between the last article and footer — a full 20p
x margin from the article to main, and another 20px
from main to footer.
#container {
display: flex;
flex-direction: column;
}
article {
margin-bottom: 20px
}
main {
background: pink;
margin-bottom: 20px;
}
footer {
background: skyblue;
}
<div id="container">
<main>
<article>
Item 1
</article>
<article>
Item 2
</article>
</main>
<footer>Footer</footer>
</div>
Is there a way to make flexbox margins behave the same way as the non-flexbox ones?
Css Solutions
Solution 1 - Css
Margin collapsing is a feature of a block formatting context.
There is no margin collapsing in a flex formatting context.
> 3. Flex Containers: the flex
and inline-flex
display
> values
>
> A flex container establishes a new flex formatting context for its
> contents. This is the same as establishing a block formatting context,
> except that flex layout is used instead of block layout. For example,
> floats do not intrude into the flex container, and the flex
> container’s margins do not collapse with the margins of its contents.
Solution 2 - Css
though margin collapse is not possible with flexbox, you can use gap
to achieve the same result:
.parent {
display: flex;
flex-wrap: wrap;
flex-direction: row;
column-gap: 5px;
row-gap: 15px;
max-width: 70px;
outline: 1px solid #440;
}
.parent > div {
background: #8ff;
width: 20px;
height: 20px;
}
<div class="parent">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
Solution 3 - Css
NOTE: This is not a way to make margins behave in a flex box layout the same way as they do in a block layout; however, this may help resolve the margin problem in some cases.
Instead of relying on collapsing margins, you can use pseudo selectors to get the effect you want:
main{
display: flex;
flex-direction: column;
margin-bottom: 20px;
}
article{
margin-bottom: 20px;
background: #eee;
}
article:last-child{
margin-bottom: 0;
}
footer{
background: #eef;
}
<main>
<article>
This is article number 1
</article>
<article>
This is article number 2
</article>
<article>
This is article number 3
</article>
</main>
<footer>
This is the footer of the page
</footer>
Solution 4 - Css
margin-trim
is likely to be added to the css specifications, which will deal with these type of situations. More details are found in the https://developer.mozilla.org/en-US/docs/Web/CSS/margin-trim. Browser support can be viewed here: https://caniuse.com/mdn-css_properties_margin-trim
Solution 5 - Css
The accepted answer explains why it doesn't work, but does not provide a solution. Here's a way to make the flexbox elements align just like the non-flexbox example.
#container {
display: flex;
flex-direction: column;
}
main {
background: pink;
margin-bottom: 20px;
}
main > article + article {
margin-top: 20px
}
footer {
background: skyblue;
}
<div id="container">
<main>
<article>
Item 1
</article>
<article>
Item 2
</article>
</main>
<footer>Footer</footer>
</div>