97

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 20px 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?

vsync
  • 118,978
  • 58
  • 307
  • 400
Coffee Bite
  • 4,956
  • 5
  • 33
  • 38

5 Answers5

121

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.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 94
    nnnnnooooooooooooooo don't tell me this! how do I get rid of my extra space between modules? – Tom Roggero Nov 21 '17 at 01:40
  • 3
    @TomRoggero maybe add a wrapper for that content to work in block formatting context? The wrapper then exists in a flex formatting context, but not its content — I would guess. However, wrapping tends to breaks good, nice, semantic markup. – Jonas Carlbaum Dec 21 '17 at 16:36
  • 35
    It's so annoying we don't have a way to toggle margin collapse on/off as we see fit – vsync Aug 25 '18 at 13:19
  • 2
    To clarify something that wasn't clear to me: It's the *flex items* (rather than the *flex container* itself) that don't get collapsing margins. Here is an example: https://jsfiddle.net/tup8nxqo/ You will notice that the flex items A, B, C have a 50px margin each, but are 100px apart. The two flex containers have 100px margin each, and those margins collapse. – Henrik N Jun 17 '19 at 12:18
  • 5
    @HenrikN, just to be clear -- because you mentioned the relative margins of A, B and C -- margin collapsing only applies to vertical margins. [Horizontal margins never collapse.](https://www.w3.org/TR/CSS22/box.html#collapsing-margins) – Michael Benjamin Jun 21 '19 at 16:45
  • Thank you, @Michael_B! Good catch. This is an updated example that uses `flex-direction: column`: https://jsfiddle.net/9qenzs2L/ As with the first example, the adjacent flex items don't have their (now vertical) margins collapse. – Henrik N Jun 26 '19 at 11:42
  • 1
    Why do all good things must come with some flaw ? – Buksy Sep 25 '22 at 19:46
  • In practice, if you want margin collapse -like effect, you have to use margin for the flex *container* and `gap` for the flex items. Unfortunately, with `gap` you can only set one value for both horizontal and vertical directions so it's much less flexible (pun intented) than true margin collapse. Also note that the visitors will need pretty recent version of Safari because Apple took forever to support `gap` and without support for it, the actual rendering will look like you had set `gap:0` everywhere. – Mikko Rantalainen Dec 09 '22 at 11:09
20

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>

https://coryrylan.com/blog/css-gap-space-with-flexbox

Phil
  • 5
  • 4
oriadam
  • 7,747
  • 2
  • 50
  • 48
  • No Safari support as of April 2021 – Sean Apr 15 '21 at 15:54
  • Now in Safari (14.1+ as of April 25, 2021) https://caniuse.com/mdn-css_properties_row-gap_flex_context – jgawrych Jun 15 '21 at 22:57
  • If you use `gap`, you should be aware that it took ages for Apple to support this. If you have to support old (unsupported by Apple!) Apple devices, it may not safe to use `gap` even today. If you can get Apple users to install iOS 15 or greater, there will be no problems with `gap`. – Mikko Rantalainen Dec 09 '22 at 10:59
7

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>
Trevor
  • 13,085
  • 13
  • 76
  • 99
2

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

ivanji
  • 169
  • 1
  • 10
  • Two years later `margin-trip` is still implemented in zero browsers so I wouldn't expect this to happen anytime soon. Also note that `margin-trip` would be different feature from hypothetical `margin-collapse` which is the feature asked in the question. The `margin-trim` is about setting logical margin value to zero for some edge cases whereas `margin-collapse` would be overlapping margin areas. – Mikko Rantalainen Dec 09 '22 at 11:05
  • Now supported in Safari (but nowhere else yet) – thelem Mar 31 '23 at 15:11
0

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>
marcvangend
  • 5,592
  • 4
  • 22
  • 32
  • 1
    this wouldn't work well with wrapped elements though – oriadam Mar 31 '21 at 09:50
  • You probably should use the `gap` property if you want space between the items within the flexbox. I still think it would awesome to be able to toggle margin-collapse on and off at will but this is not supported for flex items. – Mikko Rantalainen Dec 09 '22 at 11:07
  • @MikkoRantalainen you are correct. That said, browser support for `gap` was not the same in 2020. Stack Overflow answers should always be read in the context of their post date. – marcvangend Dec 12 '22 at 16:05
  • I think the intent of the Stack Overflow is to update the answers in the long run, or at least allow comments that explain the current situation. The Edit and Comment features do not get disabled even for old content unlike e.g. Reddit – and this is exactly to allow fixing historical answers. – Mikko Rantalainen Dec 12 '22 at 16:34