Margin Collapsing in Flexbox

Margin collapsing in flexbox

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.

flexbox margin collapsing between children

Margins does not collapse when one use display: flex. If you want to know more about collapse margins in general, here is a couple of articles to start with:

  • https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing
  • https://css-tricks.com/what-you-should-know-about-collapsing-margins/

As a workaround, to make it behave similar to display: block, you could do something like this, where you add a flex class to container's that has display: flex, to target only h1 and p.

And if you can't do that manually, a script could do that work for you.

.wrapper {  width: 50%;  margin: 0 auto;}.container {  display: flex;  /* display: block; */  flex-flow: column nowrap;  background-color: green;}h1 {  background-color: #777;  margin-bottom: 20px;}p {  background-color: #ccc;  margin-top: 15px;}

/* custom classes to remove margin */.container.flex h1:first-child { margin-top: 0;}.container.flex p:last-child { margin: 0;}
<div class="wrapper">  <div class="container flex">    <h1>header h1</h1>    <p>plain text</p>  </div></div>

Collapsing margin on Flexbox children

It's a bit of a hack, but you can add a negative margin on the flex container to cancel out the items' margins along the edges, and then move its "background" styling to a parent wrapper-element.

Updated JSBin

Updated CSS (SASS):

.wrapper
background: #eef
border: 1px solid darkgray

.container
display: flex
flex-wrap: wrap
margin: -1em

.item
flex-grow: 1
margin: 1em
border: 1px solid black
padding: 1em
min-width: 6em

Why are margins not collapsing?

Flex items' margins won't collapse. When flex items wrap, they create their own row, and the individual margins on the flex items won't collapse between rows. Only normal, adjacent block elements stacked will margin collapse the way you're intending. This is a good reference - https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing

You can create the same layout by removing the top margin from the li's and making that a padding-top on the ul instead, then only the bottom margin will be applied between li's when the flex row wraps.

ul {  list-style-type: none;  padding-left: 0px;}
a { text-decoration: none;}
main { background-color: #F1F4F5; padding: 30px 0px;}
.main-wrapper { max-width: 800px; margin: auto;}
.tags ul { display: flex; justify-content: center; align-items: center; flex-wrap: wrap; margin: 0; padding-top: 20px;}.tags li { margin: 0 10px 20px; display: block;}.tags a { display: block; justify-content: center; color: #3A4250; background-color: #e6e6e6; border-radius: 20px; padding: 7px 20px; transition: background-color 0.3s ease, color 0.3s ease;}.tags a:hover { color: #FFFFFF; background-color: #FC575E; transition: background-color 0.3s ease, color 0.3s ease;}
<main>  <div class="main-wrapper">    <div class="tags">      <ul>        <li>          <a href="#">ELEMENT 1</a>        </li>        <li>          <a href="#">ELEMENT 2</a>        </li>        <li>          <a href="#">ELEMENT 3</a>        </li>        <li>          <a href="#">ELEMENT 4</a>        </li>        <li>          <a href="#">ELEMENT 5</a>        </li>      </ul>    </div>  </div></main>

Collapsing margin on Flexbox grid in Edge and Firefox

Margin using percent doesn't work cross browsers on flex items, so if your margin's is more related to the viewport, use viewport units (vh or vw), else you can combine px with CSS calc() (i.e. width: calc(33.333% - 20px)) to match an equal gutter between the items.

Updated codepen

body {  padding: 1.5%;  background-color: #333;}
.container { //background-color: black; max-width: 964px; margin: 0 auto; display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; -webkit-box-flex-flow: row wrap; -moz-box-flex-flow: row wrap; -webkit-flex-flow: row wrap; -ms-flex-flow: row wrap; flex-flow: row wrap;}
.item { position: relative; width: 97%; color: #fff; background-color: #4286f4; padding: 0 20px 40px; margin: 1.5vh; box-sizing: border-box;}
@media only screen and (min-width:420px){ .item { width: 47%; }}
@media only screen and (min-width:768px){ .item { width: 30.333%; }}
a { position: absolute; bottom: 20px; left: 20px;}
<div class="container">  <div class="item item-1">    <h2>Item one</h2>    <p>Pellentesque convallis turpis nec enim consequat, vitae pellentesque purus tempus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis blandit elit vel lacus gravida, nec imperdiet ligula ornare.</p>    <a href="#">Read more</a>  </div>  <div class="item item-2">    <h2>Item two</h2>    <p>Pellentesque convallis turpis nec enim consequat, vitae pellentesque purus tempus.</p>    <a href="#">Read more</a>  </div>  <div class="item item-3">    <h2>Item three</h2>    <p>Pellentesque convallis turpis nec enim consequat, vitae pellentesque purus tempus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae.</p>    <a href="#">Read more</a>  </div>  <div class="item item-4">    <h2>Item four</h2>    <p>Pellentesque convallis turpis nec enim consequat.</p>    <a href="#">Read more</a>  </div>  <div class="item item-5">    <h2>Item five</h2>    <p>Pellentesque convallis turpis nec enim consequat.</p>    <a href="#">Read more</a>  </div>  <div class="item item-6">    <h2>Item six</h2>    <p>Pellentesque convallis turpis nec enim consequat.</p>    <a href="#">Read more</a>  </div></div>

Better way to set distance between flexbox items

  • Flexbox doesn't have collapsing margins.
  • Flexbox doesn't have anything akin to border-spacing for tables (edit: CSS property gap fulfills this role in newer browsers, Can I use)

Therefore achieving what you are asking for is a bit more difficult.

In my experience, the "cleanest" way that doesn't use :first-child/:last-child and works without any modification on flex-wrap:wrap is to set padding:5px on the container and margin:5px on the children. That will produce a 10px gap between each child and between each child and their parent.

Demo

.upper {
margin: 30px;
display: flex;
flex-direction: row;
width: 300px;
height: 80px;
border: 1px red solid;

padding: 5px; /* this */
}

.upper > div {
flex: 1 1 auto;
border: 1px red solid;
text-align: center;

margin: 5px; /* and that, will result in a 10px gap */
}

.upper.mc /* multicol test */ {
flex-direction: column;
flex-wrap: wrap;
width: 200px;
height: 200px;
}
<div class="upper">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>

<div class="upper mc">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>


Related Topics



Leave a reply



Submit