Better way to set distance between flexbox items

Viewed 1987970

To set the minimal distance between flexbox items I'm using margin: 0 5px on .item and margin: 0 -5px on container. For me it seems like a hack, but I can't find any better way to do this.

#box {
  display: flex;
  width: 100px;
  margin: 0 -5px;
}

.item {
  background: gray;
  width: 50px;
  height: 50px;
  margin: 0 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

40 Answers

CSS gap property:

There is a new gap CSS property for multi-column, flexbox, and grid layouts that works in newer browsers now! (See Can I use link 1; link 2). It is shorthand for row-gap and column-gap.

#box {
  display: flex;
  gap: 10px;
}

CSS row-gap property:

The row-gap CSS property for both flexbox and grid layouts allows you to create a gap between rows.

#box {
   display: flex;
   row-gap: 10px;
}

CSS column-gap property:

The column-gap CSS property for multi-column, flexbox and grid layouts allows you to create a gap between columns.

#box {
  display: flex;
  column-gap: 10px;
}

Example:

#box {
  display: flex;
  flex-wrap: wrap;
  width: 200px;
  background-color: red;
  gap: 10px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
  border: 1px black solid;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Flexbox and css calc with multiple rows support

Hello, below is my working solution for all browsers supporting flexbox. No negative margins.

Fiddle Demo

   
.flexbox {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
}

.flexbox > div {
  /*
    1/3  - 3 columns per row
    10px - spacing between columns 
  */
  box-sizing: border-box;
  margin: 10px 10px 0 0;
  outline: 1px dotted red;
  width: calc(1/3*100% - (1 - 1/3)*10px);
}

/*
  align last row columns to the left
  3n - 3 columns per row
*/
.flexbox > div:nth-child(3n) {
  margin-right: 0;
}

.flexbox::after {
  content: '';
  flex: auto;
}

/*
  remove top margin from first row
  -n+3 - 3 columns per row 
*/
.flexbox > div:nth-child(-n+3) {
  margin-top: 0;
}
<div class="flexbox">
  <div>col</div>
  <div>col</div>
  <div>col</div>
  <div>col</div>
  <div>col</div>
</div>

Take a note this code can be shorter using SASS

Update 2020.II.11 Aligned columns on the last row to the left

Update 2020.II.14 Removed margin-bottom in the last row

I often use the + operator for such cases

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
}
.item + .item {
    margin-left: 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

You could use the new property gap. I copy paste the explanation I found in this article, as well as more information

CSS grid layout has had gap (previously grid-gap) for some time. By specifying the internal spacing of a containing element rather than the spacing around child elements, gap solves many common layout issues. For example, with gap, you don't have to worry about margins on child elements causing unwanted whitespace around the edges of a containing element:

Unfortunately right now, only FireFox supports gap in flex layouts.

@use postcss-preset-env {
  stage: 0;
  browsers: last 2 versions
}

section {
  width: 30vw;
  
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(12ch, 1fr));
  
  &[flex] {
    display: flex;
    flex-wrap: wrap;
  }
  
  margin-bottom: 3rem;
}

.tag {
  color: white;
  background: hsl(265 100% 47%);
  padding: .5rem 1rem;
  border-radius: 1rem;
}

button {
  display: inline-flex;
  place-items: center;
  gap: .5rem;
  background: hsl(265 100% 47%);
  border: 1px solid hsl(265 100% 67%);
  color: white;
  padding: 1rem 2rem;
  border-radius: 1rem;
  font-size: 1.25rem;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
<section>
  <h1>Grid</h1> 
  <div class="tag">Awesome</div>
  <div class="tag">Coo</div>
  <div class="tag">Rad</div>
  <div class="tag">Math</div>
</section>
<br>
<section flex>
  <h1>Flex</h1>
  <div class="tag">Awesome</div>
  <div class="tag">Coo</div>
  <div class="tag">Rad</div>
  <div class="tag">Math</div>
</section>

Columnify - A solo class for N columns

Flexbox and SCSS

.columnify {
  display: flex;

  > * {
    flex: 1;

    &:not(:first-child) {
      margin-left: 2rem;
    }
  }
}

Flexbox and CSS

.columnify {
  display: flex;
}

.columnify > * {
  flex: 1;
}

.columnify > *:not(:first-child) {
  margin-left: 2rem;
}
<div class="columnify">
  <div style="display: inline-block; height: 20px; background-color: blue;"></div>
  <div style="display: inline-block; height: 20px; background-color: blue"></div>
  <div style="display: inline-block; height: 20px; background-color: blue"></div>
</div>

Play with it on JSFiddle.

Just use .item + .item in selector to match from second .item

#box {
  display: inline-flex;
  margin: 0 -5px;
}
.item {
  background: gray;
  width: 10px;
  height: 50px;
}

#box .item + .item {
  margin-left: 10px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

Assuming:

  • You want 4 column grid layout with wrapping
  • The number of items is not necessarily a multiple of 4

Set a left margin on every item except 1st, 5th, 9th item and so on; and set fixed width on each item. If the left margin is 10px then each row will have 30px margin between 4 items, the percentage width of item can be calculated as follows:

100% / 4 - horizontal-border - horizontal-padding - left-margin * (4 - 1) / 4

This is a decent workaround for issues involving last row of flexbox.

.flex {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  margin: 1em 0;
  background-color: peachpuff;
}

.item {
  margin-left: 10px;
  border: 1px solid;
  padding: 10px;
  width: calc(100% / 4 - 2px - 20px - 10px * (4 - 1) / 4);
  background-color: papayawhip;
}

.item:nth-child(4n + 1) {
  margin-left: 0;
}

.item:nth-child(n + 5) {
  margin-top: 10px;
}
<div class="flex">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
</div>
<div class="flex">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
</div>
<div class="flex">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
</div>

There is indeed a nice, tidy, CSS-only way to do this (that one may consider "better").

Of all the answers posted here, I only found one that uses calc() successfully (by Dariusz Sikorski). But when posed with: "but it fails if there are only 2 items in the last row" there was no solution expanded.

This solution addresses the OP's question with an alternative to negative margins and addresses the problem posed to Dariusz.

notes:

  • This example only demonstrates a 3-column layout
  • It uses calc() to let the browser do math the way it wants -- 100%/3 (although 33.3333% should work just as well), and (1em/3)*2 (although .66em should also work well).
  • It uses ::after to pad the last row if there are fewer elements than columns

.flex-container {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
}
.flex-container:after {
  content: "";
}
.flex-container > div,
.flex-container:after {
  box-sizing: border-box;
  width: calc((100%/3) - ((1em/3)*2));
}
.flex-container > :nth-child(n + 4) {
  margin-top: 1em;
}

/* the following is just to visualize the items */
.flex-container > div,
.flex-container:after {
  font-size: 2em;
}
.flex-container {
  margin-bottom:4em;
}
.flex-container > div {
  text-align: center;
  background-color: #aaa;
  padding: 1em;
}
.flex-container:after {
  border: 1px dashed red;
}
<h2>Example 1 (2 elements)</h2>
<div class="flex-container">
  <div>1</div>
  <div>2</div>
</div>

<h2>Example 2 (3 elements)</h2>
<div class="flex-container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>

Also at https://codepen.io/anon/pen/rqWagE

You could use the following equation

.container {
  max-width: 960px;
  margin: 0 auto;
  padding: 4rem 0;
}

.flex {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}
.flex:after {
  content: "";
  max-width: calc(100% * var(--col) / 12 - var(--gap));
  width: 100%;
}
@media (max-width: 960px) {
  .flex:after {
    max-width: calc(100% * var(--colTablet) / 12 - var(--gap));
  }
}
@media (max-width: 680px) {
  .flex:after {
    max-width: calc(100% * var(--colMobile) / 12 - var(--gap));
  }
}
.flex .item {
  max-width: calc(100% * var(--col) / 12 - var(--gap));
  width: 100%;
}
@media (max-width: 960px) {
  .flex .item {
    max-width: calc(100% * var(--colTablet) / 12 - var(--gap));
    margin-bottom: 1rem;
  }
  .flex .item:last-child {
    margin-bottom: unset;
  }
}
@media (max-width: 680px) {
  .flex .item {
    max-width: calc(100% * var(--colMobile) / 12);
  }
}
.flex .item .card {
  background: #eee;
  text-align: center;
  padding: 2rem;
}
<div class="flex container" style="--col: 3; --colTablet: 6; --colMobile: 12; --gap: 2%">
  <div class="item" style="--col: 3; --colTablet: 6; --colMobile: 12; --gap: 2%">
    <div class="card">
      <h2>Hello world</h2>
    </div>
  </div>
  <div class="item" style="--col: 3; --colTablet: 6; --colMobile: 12; --gap: 2%">
    <div class="card">
      <h2>Hello world</h2>
    </div>
  </div>
  <div class="item" style="--col: 3; --colTablet: 6; --colMobile: 12; --gap: 2%">
    <div class="card">
      <h2>Hello world</h2>
    </div>
  </div>
</div>

The negative margin trick on the box container works just great. Here is another example working great with order, wrapping and what not.

.container {
   border: 1px solid green;
   width: 200px;
   display: inline-block;
}

#box {
  display: flex;
  flex-wrap: wrap-reverse;
  margin: -10px;
  border: 1px solid red;
}
.item {
  flex: 1 1 auto;
  order: 1;
  background: gray;
  width: 50px;
  height: 50px;
  margin: 10px;
  border: 1px solid blue;
}
.first {
  order: 0;
}
<div class=container>
<div id='box'>
  <div class='item'>1</div>
  <div class='item'>2</div>
  <div class='item first'>3*</div>
  <div class='item'>4</div>
  <div class='item'>5</div>
</div>
</div>

I set the spacing on flex items only in the direction stablished by their container. E.g. if a flex container is set to flow from left to right (flex-direction:row) I will only set the right margin on its children, except for the last one:

.flex-lr{
    display:flex;
    flex-direction:row;
}

.flex-lr > *:not(:last-child){
    margin-right:5px;
}

This might seem to work at a first glance but wait! this shouldn't be done when justify-content is set to a value other that start or end, since all other values are already distributing the space on their own.

And what if the items wrap? Then we should add space to the proper cross axis side as well. But, how to know if a container is allowing its children to wrap? And what about wrap-reverse?

All this considerations made me think that this is not a trivial task and it requires a small step beyond.

My approach is based on the build of a brief set of classes that acts as a wrapper of flexbox. This has some benefits:

  1. It allows to "centralize" all vendor prefixes in a single point and forget about that.
  2. It allows to group flexbox properties into a single class, or even rename some of the wording used by flexbox, that sometimes may seem not much intuitive (IMHO).
  3. If I use these classes, I will be able to write other classes based on the flex properties values that they rely on. E.g. I would be able to set the spacing based on the flow direction, the cross axis alignment, wrapping, etc.

I ended up building a flexbox designer to play around with all this, to help understand myself (and others) how flexbox works and to realize how wonderful flexbox is. Plese feel free to use it following the link below:

http://algid.com/Flex-Designer

So, below you will find and abstract of the classes I use and the spacing (margin) utlity for one flow direction. You'll be able to infer the others or find them in the link provided above. Vendor prefixes have been ommited here for brevety.

/* Flex container definition */
.flex-lr{display:flex; flex-direction:row;}
.flex-tb{display:flex; flex-direction:column;}
.flex-rl{display:flex; flex-direction:row-reverse;}
.flex-bt{display:flex; flex-direction:column-reverse;}

/* Wrapping */
.wrap{flex-wrap:wrap;}
.nowrap{flex-wrap:nowrap;}
.wrap-rev{flex-wrap:wrap-reverse;}

/* Main axis alignment */
.align-start{justify-content:flex-start;}
.align-end{justify-content:flex-end;}
.align-center{justify-content:center;}
.align-between{justify-content:space-between;}
.align-around{justify-content:space-around;}
.align-evenly{justify-content:space-evenly;}

/* Cross axis alignment */
.cross-align-start{align-items:flex-start;}
.cross-align-end{align-items:flex-end;}
.cross-align-center{align-items:center;}
.cross-align-stretch{align-items:stretch;}
.cross-align-baseline{align-items:baseline;}

/* Cross axis alignment when content is wrapped */
.wrap-align-start{align-content:flex-start;}
.wrap-align-end{align-content:flex-end;}
.wrap-align-center{align-content:center;}
.wrap-align-stretch{align-content:stretch;}
.wrap-align-between{align-content:space-between;}
.wrap-align-around{align-content:space-around;}

/* Item alignment */
.item-cross-align-start{align-self:flex-start;}
.item-cross-align-end{align-self:flex-end;}
.item-cross-align-center{align-self:center;}
.item-cross-align-stretch{align-self:stretch;}
.item-cross-align-baseline{align-self:baseline;}
.item-cross-align-auto{align-self:auto;}

And now the thing that brought us here: the space between the items:

/* Flow margin (left to right) */
.flex-lr.fm-0 > *:not(:last-child){margin-right:0;}
.flex-lr.fm-1 > *:not(:last-child){margin-right:3px;}
.flex-lr.fm-2 > *:not(:last-child){margin-right:7px;}
.flex-lr.fm-3 > *:not(:last-child){margin-right:15px;}
.flex-lr.fm-4 > *:not(:last-child){margin-right:32px;}

/* Cross axis */
.flex-lr.wrap.fm-0:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap.fm-0.wrap-align-stretch.cross-align-stretch > * {margin-bottom:0;}
.flex-lr.wrap.fm-1:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap.fm-1.wrap-align-stretch.cross-align-stretch > * {margin-bottom:3px;}
.flex-lr.wrap.fm-2:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap.fm-2.wrap-align-stretch.cross-align-stretch > * {margin-bottom:7px;}
.flex-lr.wrap.fm-3:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap.fm-3.wrap-align-stretch.cross-align-stretch > * {margin-bottom:15px;}
.flex-lr.wrap.fm-4:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap.fm-4.wrap-align-stretch.cross-align-stretch > * {margin-bottom:32px;}

/* wrap reverse */
.flex-lr.wrap-rev.fm-0:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap-rev.fm-0.wrap-align-stretch.cross-align-stretch > * {margin-top:0;}
.flex-lr.wrap-rev.fm-1:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap-rev.fm-1.wrap-align-stretch.cross-align-stretch > * {margin-top:3px;}
.flex-lr.wrap-rev.fm-2:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap-rev.fm-2.wrap-align-stretch.cross-align-stretch > * {margin-top:7px;}
.flex-lr.wrap-rev.fm-3:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap-rev.fm-3.wrap-align-stretch.cross-align-stretch > * {margin-top:15px;}
.flex-lr.wrap-rev.fm-4:not(.wrap-align-stretch):not(.wrap-align-between):not(.wrap-align-around) > *, .flex-lr.wrap-rev.fm-4.wrap-align-stretch.cross-align-stretch > * {margin-top:32px;}

Finally, this is how the markup would look like:

<div class="flex-lr cross-align-center fm-3">
    <div>
        Some content here...
    </div>
    <div>
        A bit more stuff here...
    </div>
    <div class="flex-tb fm-3">
        <div>
            Now vertical content
        </div>
        <div>
            etc.
        </div>
    </div>
</div>

This is what I call code out loud.

You can try CSS3's :not selector

Eg:

#box {
  display: flex;
  width: 100px;
  border: 1px red solid;
}

.item {
  background: gray;
  width: 10px;
  height: 100px;
  flex: 1 1 auto;
}

.item:not(:last-child) {
  margin-right: 5px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

I used another approach. Used negative margin on the container, which needs to be the same as each child so for example 10px. Then for each child reduced the width by the total margin each side using calc(), which in this case is 20px.

Here is an example: https://codepen.io/anon/pen/KJLZVg

This helps when doing things responsively as you don't need to target specific nth-child to keep it flush on each side of the container when it wraps.

.parent {
    padding: 0 10px;
}
.container {
    display: flex;
    margin: 0 -10px;
    flex-wrap: wrap;
    width: 100%;
    max-width: 500px;
    margin: 0 auto;
}
.child {
    margin: 0 10px 25px 10px;
    flex: 0 0 calc(25% - 20px);
    height: 40px;
    background: red;
}

<div class="parent">
<div class="container">
    <div class="child"></div>
    <div class="child"></div>
    <div class="child"></div>
    <div class="child"></div>
    <div class="child"></div>
    <div class="child"></div>
    <div class="child"></div>
</div>

Also using flex: 0 0 (width) it helps with IE browser.

Simple way of doing this is by adding margin-left and margin-right to the children div and adjust the margin value accordingly

<div class="a">
  <div class="b"></div>
  <div class="b"></div>
  <div class="b"></div>
</div>

css:

.a{
   display: flex;
   justify-content: center;
   background-color: black;
}

.b{
  height: 25px;
  width: 25px;
  background-color: grey;
  margin-left: 5px;
  margin-right: 5px;
}

tl;dr

$gutter: 8px;

.container {
  display: flex;
  justify-content: space-between;

  .children {
    flex: 0 0 calc(33.3333% - $gutter);
  }
}

Well, the simplest solution regarding to your CSS, imo, is to add spacers into HTML:

<div id='box'>
  <div class='item'></div>
  <div style='width: 5px;'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

so, you may control it with inline-style or class names.. sometimes, it's also possible to do spacing with padding.

here is the example

OK, now you have a gap so you may use that, but good ol' techs are still unavoidable, like <div><div></div></div> wrapping for constructing unique items with unique gaps (use padding for gapping! and ofc new gap property)

Related