How do I set distance between flexbox items?
Asked Answered
T

40

1507

To set the minimal distance between flexbox items I'm using margin: 0 5px on .item and margin: 0 -5px on container. This seems like a hack. Is there another property or method intended to accomplish this goal?

#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>
Towering answered 17/12, 2013 at 5:35 Comment(2)
It's not a hack - it's one of the intended methods for aligning items. There are other properties though. See w3.org/TR/css3-flexbox/#alignmentStrut
Yeah, I'm understand. But for example there is column-gap property what gives us ability to control distance from container: w3.org/TR/css3-multicol/#column-gapTowering
M
680

Before ~20202, Flexbox didn't have anything akin to border-spacing for tables. The answer below is from that time. Now, the gap property fulfills this role and is recommended for this application.


Flexbox doesn't have collapsing margins1. 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.

JSFiddle 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>
Melanson answered 18/12, 2013 at 8:31 Comment(7)
This doesn't accomplish the same thing as the question asks, you will have a 10px indent on the far left and right, which I'm assuming they don't intend to have. Hence, the negative margins in the original question.Vuillard
What about if order property set? :first-child/:last-child will not work as expected.Earthquake
Isn't this a worse answer than the original question? This method requires that you have space around the container and the guttering must always be an even number.Asteriated
justify-content: space-aroundReeva
@Reeva Yes, if there is space around to distribute. Meaning that the minimal margin width you get is zero. CSS is a mess.Prehuman
@Flimm's answer is valid. You can simply adjust the padding and margin to get the desired 5px spacing like so padding: 5px 0 0 5px; and margin: 0 5px 5px 0;. See here: jsfiddle.net/sandraqu/na32wbyuDinnage
@Dinnage Yes but then you're right back to using stuff like first/last-child to select these. Really confused by this entire answer as it doesn't accomplish the goal.Chemist
M
1002

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>
Mcquiston answered 21/9, 2019 at 15:40 Comment(10)
It doesn't work on my Windows 10 + Chrome 90.0.4430. It acts like margin and the fourth element go to a new line. Please check a screenshot of your own snippet on my display i2.paste.pics/a1f42d884cb5a64ddf80632e87178869.pngTinkling
@MarcoPanichi the result you are seeing is the intended result. Notice how there is no red margin before the first item in each line. If you don't want wrapping, you can turn it off: flex-wrap: nowrap. You also might want to try: justify-content: space-betweenMcquiston
One limitation I am facing with this approach is that, if there are two columns that require different gap than rest of the columns, then you cannot achieve it.Hudibrastic
@Hudibrastic Flex layouts don't have columns per se. If you need features like different gaps for different columns, then I recommend CSS grid, not flex.Mcquiston
I wouldn´t use "gap" on flex box (correct me if im wrong, but it´s more suited for display: grid) since it makes columns wrap prematurely. Better to stick to old margin/padding solution. Example: jsfiddle.net/wmtz8dch/1Powwow
@Powwow I'm not sure what you mean that gap on flexbox causes columns to wrap prematurely. For the margin/padding solution, that's the one described by this answer and it has the problems mentioned in the comments to that answer.Mcquiston
@Mcquiston If you look the example on jsfiddle i provided you´ll see 2 examples. Both of them have columns set to 25%, meaning 4 in a row. Gaps doesn´take width into account, that´s what i mean by premature wrap (maybe not the best word to describe though). Sure you can write calc() rules, but then you´d need to do it with every different gap size you are using, while with margin/padding you don´t have to.Powwow
@Powwow The JS Fiddle has the expected result. You've enabled box-sizing: border-box. That means width: 25% is applied to the width of the element including padding and border. If the flex container is 100px wide, that means each element gets 25px width (including padding and border), which is what happens. If you add a gap between these elements, of course there isn't enough room to have four 25px-wide elements in a 100px container with a gap in between, so of course it wraps (presuming flex-wrap: wrap is enabled). The same would be true if you had added margin on the elements.Mcquiston
@Mcquiston not sure I can follow your last comment. Do you say its possible to use flex, gap and percentage widht at the same time somehow? For example, if I have boxes with widht 50% how can I get a 2-column list using gap property? jsfiddle.net/9yo125ft/4Helman
@Helman If I've understood you correctly, it's possible to do it like this: jsfiddle.net/rz05mdw9 - If you set the child flex property to 49% the parent will never have enough room to house more than 2 flex children, but there will be enough room to allow the gap property to do its work.Marcille
M
680

Before ~20202, Flexbox didn't have anything akin to border-spacing for tables. The answer below is from that time. Now, the gap property fulfills this role and is recommended for this application.


Flexbox doesn't have collapsing margins1. 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.

JSFiddle 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>
Melanson answered 18/12, 2013 at 8:31 Comment(7)
This doesn't accomplish the same thing as the question asks, you will have a 10px indent on the far left and right, which I'm assuming they don't intend to have. Hence, the negative margins in the original question.Vuillard
What about if order property set? :first-child/:last-child will not work as expected.Earthquake
Isn't this a worse answer than the original question? This method requires that you have space around the container and the guttering must always be an even number.Asteriated
justify-content: space-aroundReeva
@Reeva Yes, if there is space around to distribute. Meaning that the minimal margin width you get is zero. CSS is a mess.Prehuman
@Flimm's answer is valid. You can simply adjust the padding and margin to get the desired 5px spacing like so padding: 5px 0 0 5px; and margin: 0 5px 5px 0;. See here: jsfiddle.net/sandraqu/na32wbyuDinnage
@Dinnage Yes but then you're right back to using stuff like first/last-child to select these. Really confused by this entire answer as it doesn't accomplish the goal.Chemist
J
262

This same technique is also used by Bootstrap and its grid layout system. Though, instead of margin, Bootstrap uses padding for its columns.

.row {
  margin:0 -15px;
}
.col-xx-xx {
  padding:0 15px;
}
Jarad answered 19/12, 2014 at 9:52 Comment(4)
The only issue with this method are maintaining equal height items with background colors. Absolute positioning with height:100%; width:100% ignores the item's padding.Livvyy
The problem here is with IE10 and 11. flex-basis values do not account for box-sizing: border-box, so a child with any padding or border will overflow the parent (or wrap in this case). SourceWeber
There is another problem with this approach: adjusting the margin like this can expand the page width. Demo: jsfiddle.net/a97tatf6/1Gatling
@Weber would it not be an option to disable box-sizing: border-box on just that div?Adventuresome
S
167

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

Statutory answered 4/10, 2016 at 22:30 Comment(5)
I like this solution but it fails if there are only 2 items in the last row. The items aren't stacked together due to the justify-content.Easygoing
to fix the two item issue just change to justify-content: space-evenly; or justify-content: space-around;.Urushiol
@PaulRooney On site with multiple lists you might not always know the number of items, if the lists are generated by a CMS.Freehold
Unfortunately this solution isn't responsive, whereas the negative margins one is.Noddle
The width: calc(1/3*100% - (1 - 1/3)*10px); was the "secret" formula I was looking for, thanks! You don't even have to use justify-content: space-between; when you provide margins.Poly
W
162

You can use & > * + * as a selector to emulate a flex-gap (for a single line):

#box { display: flex; width: 230px; outline: 1px solid blue; }
.item { background: gray; width: 50px; height: 100px; }

/* ----- Flexbox gap: ----- */

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

If you need to support flex wrapping, you can use a wrapper element:

.flex { display: flex; flex-wrap: wrap;  }
.box { background: gray; height: 100px; min-width: 100px; flex: auto; }
.flex-wrapper {outline: 1px solid red; }

/* ----- Flex gap 10px: ----- */

.flex > * {
  margin: 5px;
}
.flex {
  margin: -5px;
}
.flex-wrapper {
  width: 400px; /* optional */
  overflow: hidden; /* optional */
}
<div class='flex-wrapper'>
  <div class='flex'>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
    <div class='box'></div>
  </div>
</div>
Witty answered 12/2, 2018 at 18:17 Comment(2)
One point to note though is that the * operator does not increase specificity as you might expect. So depending on your exisiting css you may need to either increase the specificity on the .flex > * selector or add !important to the rule if there are other selectors applying margin to that element.Homozygous
this won't work if you have that buttons width:100% on mobileDanelledanete
A
106

You can use transparent borders.

I have contemplated this issue while trying to build a flex grid model which can fallback to a tables + table-cell model for older browsers. And Borders for column gutters seemed to me the best appropriate choice. i.e. Table-cells don't have margins.

e.g.

.column{
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 10px solid transparent;
}

Also note that you need min-width: 50px; for flexbox. The flex model will not handle fixed sizes unless you do flex: none; on the particular child element you want as fixed and therefore excluded from being "flexi". http://jsfiddle.net/GLpUp/4/ But all columns together with flex:none; is no longer a flex model. Here is something closer to a flex model: http://jsfiddle.net/GLpUp/5/

So you can actually use margins normally if you don't need the table-cell fallback for older browsers. http://jsfiddle.net/GLpUp/3/

Setting background-clip: padding-box; will be necessary when using a background, as otherwise the background will flow into the transparent border area.

Assured answered 20/12, 2013 at 2:33 Comment(9)
great answer. margins are used differently in flexbox's ( like to absorb extra space ) so transparent borders provide an excellent solution to evenly spaced elements that can wrap with a margin-like behaviorBjork
except when you use background color, your background exceeds your desired bounds.Boulevardier
@Boulevardier Well with different background colors, you can use white or the adequate color depending on which way is the background.Assured
Specifying the border color to match the container's background in order to make the illusion of a border... I suppose that works. It seems a bit hacky, but it should be more maintainable with sass or less color variables. Thanks for pointing this out!Boulevardier
@ahnbizcad: If you don't need IE8 support, this is a better solution: background-clip: padding-boxOnwards
Albin's comment here needs more votes! This is the best solution. Transparent borders, in combination with background-clip: padding-box (and negative margins on the container, if needed, for proper edge alignment) is a perfect solution. IE8 doesn't support flexbox anyway so its lack of support for background-clip shouldn't matter.Paisa
@Assured - but this doesn't address the extra space on the left and right of the flex container, does it?Comeon
@Comeon i don't think it does, and using :last-child and/or :first-child ends up with that first/last child being larger than the others.Anibalanica
I ended up getting this working with adjacent child selector, and it works beautifully if you don't need to cater for flex ORDER, which ruins the fix that the adjacent child selectors applies. Same is the case with :first-child/:last-child unfortunately.Anibalanica
B
94

This solution will work for all cases even if there are multiple rows or any number of elements. But the count of the section should be same you want 4 in first row and 3 is second row it won't work that way the space for the 4th content will be blank the container won't fill.

We are using display: grid; and its properties.

#box {
  display: grid;
  width: 100px;
  grid-gap: 5px;
  /* Space between items */
  grid-template-columns: repeat(4,1fr);
  /* Decide the number of columns(4) and size(1fr | 1 Fraction | you can use pixels and other values also) */
}

.item {
  background: gray;
  width: 100%;
  /* width is not necessary only added this to understand that width works as 100% to the grid template allocated space **DEFAULT WIDTH WILL BE 100%** */
  height: 50px;
}
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

The Downside of this method is in Mobile Opera Mini will not be supported and in PC this works only after IE10.

Note for complete browser compatability including IE11 please use Autoprefixer


OLD ANSWER Don't think of it as an old solution, it's still one of the best if you only want single row of elements and it will work with all the browsers.

This method is used by CSS sibling combination, so you can manipulate it many other ways also, but if your combination is wrong it may cause issues also.

.item+.item{
  margin-left: 5px;
}

The below code will do the trick. In this method, there is no need to give margin: 0 -5px; to the #box wrapper.

A working sample for you:

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 22px;
  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>
Bilander answered 13/2, 2018 at 9:44 Comment(2)
I've edited your grid-based answer to demonstrate that it does work correctly, even if the final row has fewer items. To prove it works in that case. (Feel free to revert if you don't like this change.)Consumerism
As per this question they have only asked to fill the space properly with the child elements without a hack, that what I did, using grid we can manage as per the grid-template-columns we define not dynamically. So if you give the value to 1fr 1fr 1fr 1fr then it will split the div into 4fractions and try to fill the child elements in each fractions, in my knowledge thats the only way in grid. What I have stated in the answer is that if the user needs to split the div into 4 and use them with many elements even for multiple rows, the gid will help.Bilander
L
37

Let's say if you want to set 10px space between the items, you can just set .item {margin-right:10px;} for all, and reset it on the last one .item:last-child {margin-right:0;}

You can also use general sibling ~ or next + sibling selector to set left margin on the items excluding the first one .item ~ .item {margin-left:10px;} or use .item:not(:last-child) {margin-right: 10px;}

Flexbox is so clever that it automatically recalculates and equally distributes the grid.

body {
  margin: 0;
}

.container {
  display: flex;
}

.item {
  flex: 1;
  background: gray;
  height: 50px;
}

.item:not(:last-child) {
  margin-right: 10px;
}
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

If you want to allow flex wrap, see the following example.

body {
  margin: 0;
}

.container {
  display: flex;
  flex-wrap: wrap;
  margin-left: -10px;
}

.item {
  flex: 0 0 calc(50% - 10px);
  background: gray;
  height: 50px;
  margin: 0 0 10px 10px;
}
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>
Legacy answered 12/3, 2016 at 23:9 Comment(2)
This wouldn't work if the items are wrapped, since :last-child does not affect every last child at the end of a line, correct?Mcquiston
@Mcquiston I added an approach to work with flex wrap, see the second part above.Legacy
C
35

Update: gap for flexbox is now supported in all modern browsers (Edge/Chrome/Opera/Samsung Internet/Safari/Firefox)

Eventually they will add the gap property to flexbox. Until then you could use CSS grid instead which already has the gap property, and just have a single row. Nicer than dealing with margins.

Chishima answered 15/2, 2018 at 0:28 Comment(2)
Discussion here: github.com/w3c/csswg-drafts/issues/1696 — they will also streamline the naming, across CSS Grid, Flexbox and CSS Columns.Perjured
It's probably fine to just mention Chromium instead of Edge/Chrome/Opera. Also, Samsung Internet is a major browser? Wut? Anyway it's also Chromium-powered.Nikos
Z
17

I have found a solution that is based on the general sibling selector, ~, and allows infinite nesting.

See this code pen for a working example

Basically, inside of column containers, every child that is preceded by another child gets a top margin. Likewise, inside every row container, every child that is preceded by another gets a left margin.

.box {
  display: flex;
  flex-grow: 1;
  flex-shrink: 1;
}

.box.columns {
  flex-direction: row;
}

.box.columns>.box~.box {
  margin-left: 5px;
}

.box.rows {
  flex-direction: column;
}

.box.rows>.box~.box {
  margin-top: 5px;
}
<div class="box columns">
  <div class="box" style="background-color: red;"></div>
  <div class="box rows">
    <div class="box rows">
      <div class="box" style="background-color: blue;"></div>
      <div class="box" style="background-color: orange;"></div>
      <div class="box columns">
        <div class="box" style="background-color: yellow;"></div>
        <div class="box" style="background-color: pink;"></div>
      </div>
    </div>
    <div class="box" style="background-color: green;"></div>
  </div>
</div>
Zantos answered 12/4, 2015 at 16:5 Comment(2)
This results in different sized items due to the margins not being globally applied.Livvyy
You will also need to add some extra CSS to handle smaller screens as it looks a bit weird on mobile, I would apply the .box ~ .box rule to larger screens and for smaller screens set the .box class to have a max-width of 100% and a margin bottom.Wearproof
G
17

According to #ChromeDevSummit there's an implementation of the gap property for Flexbox in Firefox and Chromium-based browsers.

Here's a Live Demo

Gaddis answered 14/11, 2019 at 12:23 Comment(0)
R
15

Moving on from sawa's answer, here's a slightly improved version that allows you to set a fixed spacing between the items without the surrounding margin.

http://jsfiddle.net/chris00/s52wmgtq/49/

Also included is the Safari "-webkit-flex" version.

.outer1 {
    background-color: orange;
    padding: 10px;
}

.outer0 {
    background-color: green;
    overflow: hidden;
}

.container
{
    display: flex;
    display: -webkit-flex;
    flex-wrap: wrap;    
    -webkit-flex-wrap: wrap;
    background-color: rgba(0, 0, 255, 0.5);
    margin-left: -10px;
    margin-top: -10px;
}

.item
{
    flex-grow: 1;
    -webkit-flex-grow: 1;
    background-color: rgba(255, 0, 0, 0.5);
    width: 100px;
    padding: 10px;
    margin-left: 10px;
    margin-top: 10px;
    text-align: center;
    color: white;
}

<div class="outer1">
    <div class="outer0">
        <div class="container">
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
            <div class="item">text</div>
        </div>
    </div>
</div>
Regina answered 12/11, 2014 at 10:59 Comment(1)
Isn't this essentially the same as the example given in the question?Coachwork
B
11

I have used this for wrapped and fixed width columns. The key here is calc()

SCSS sample

$gap: 10px;

dl {
  display: flex;
  flex-wrap: wrap;
  padding: $gap/2;

  dt, dd {
    margin: $gap/2;}

  dt { // full width, acts as header
    flex: 0 0 calc(100% - #{$gap});}

  dd { // default grid: four columns 
    flex: 0 0 calc(25% - #{$gap});}

  .half { // hall width columns
    flex: 0 0 calc(50% - #{$gap});}

}

Full Codepen sample

Bharal answered 23/12, 2014 at 14:5 Comment(4)
This still adds a gutter before the first and after the last item, which OP prevents using negative margins.Rael
Flexbox doesn't support calc() inside "flex" item in IE 11.Burris
Cant be always used. imagine if there is also border needed for direct childsDecarbonate
padding is not a good choiceDanford
B
11

A flex container with -x (negative) margin and flex items with x (positive) margin or padding both lead to the desired visual result: Flex items have a fixed gap of 2x only between each other.

It appears to be simply a matter of preference, whether to use margin or padding on the flex items.

In this example, the flex items are scaled dynamically in order to preserve the fixed gap:

.flex-container { 
  margin: 0 -5px;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}

.flex-item {
  margin: 0 5px; // Alternatively: padding: 0 5px;
  flex: 1 0 auto;
}
Benue answered 9/11, 2015 at 16:28 Comment(3)
Sorry, I didn't get it. What new does your answer introduce that is not said directly in the question?Incompetence
Firstly, i wanted to sum up that both, margin and padding on the flex-item lead to the desired result, because existing answers only mention one or the other. Secondly, i wanted to give an example, where gaps are preserved by scaling the flex-items themselves.Benue
here's a codepen example showing this effect. codepen.io/dalgard/pen/DbnusMyosotis
S
8

Using Flexbox in my solution I've used the justify-content property for the parent element (container) and I've specified the margins inside the flex-basis property of the items. Check the code snippet below:

.container {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-around;
  margin-bottom: 10px;
}

.item {
  height: 50px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #999;
}

.item-1-4 {
  flex-basis: calc(25% - 10px);
}

.item-1-3 {
  flex-basis: calc(33.33333% - 10px);
}

.item-1-2 {
  flex-basis: calc(50% - 10px);
}
<div class="container">
  <div class="item item-1-4">1</div>
  <div class="item item-1-4">2</div>
  <div class="item item-1-4">3</div>
  <div class="item item-1-4">4</div>
</div>
<div class="container">
  <div class="item item-1-3">1</div>
  <div class="item item-1-3">2</div>
  <div class="item item-1-3">3</div>
</div>
<div class="container">
  <div class="item item-1-2">1</div>
  <div class="item item-1-2">2</div>
</div>
Shemikashemite answered 29/8, 2017 at 19:15 Comment(1)
nice oneeeeeeeeCony
S
6

With flexbox, creating gutters is a pain, especially when wrapping is involved.

You need to use negative margins (as shown in the question):

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

... or alter the HTML (as shown in another answer):

<div class='flex-wrapper'>
  <div class='flex'>
    <div class='box'></div>
    <div class='box'></div>
            ...
  </div>
</div>

... or something else.

In any case, you need an ugly hack to make it work because flexbox doesn't provide a "flex-gap" feature (at least for now).

The issue of gutters, however, is simple and easy with CSS Grid Layout.

The Grid spec provides properties that create space between grid items, while ignoring the space between items and the container. These properties are:

  • grid-column-gap
  • grid-row-gap
  • grid-gap (the shorthand for both properties above)

Recently, the spec has been updated to conform with the CSS Box Alignment Module, which provides a set of alignment properties for use across all box models. So the properties are now:

  • column-gap
  • row-gap
  • gap (shorthand)

However, not all Grid-supporting browsers support the newer properties, so I'll use the original versions in the demo below.

Also, if spacing is needed between items and the container, padding on the container works just fine (see the third example in the demo below).

From the spec:

10.1. Gutters: the row-gap, column-gap, and gap properties

The row-gap and column-gap properties (and their gap shorthand), when specified on a grid container, define the gutters between grid rows and grid columns. Their syntax is defined in CSS Box Alignment 3 §8 Gaps Between Boxes.

The effect of these properties is as though the affected grid lines acquired thickness: the grid track between two grid lines is the space between the gutters that represent them.

.box {
  display: inline-grid;
  grid-auto-rows: 50px;
  grid-template-columns: repeat(4, 50px);
  border: 1px solid black;
}

.one {
  grid-column-gap: 5px;
}

.two {
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

.three {
  grid-gap: 10px;
  padding: 10px;
}

.item {
  background: lightgray;
}
<div class='box one'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

<hr>

<div class='box two'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

<hr>

<div class='box three'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>

More information:

Swenson answered 12/2, 2018 at 20:39 Comment(0)
S
6

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>
Splendid answered 7/1, 2020 at 11:45 Comment(2)
gap was already recommended in an answer here https://mcmap.net/q/45216/-how-do-i-set-distance-between-flexbox-items Also, this is not CSS.Nikos
gap still not supported in SafariElectropositive
M
5

Why not do it like this:

.item + .item {
    margin-left: 5px;
}

This uses the adjacent sibling selector, to give all .item elements, except the first one a margin-left. Thanks to flexbox, this even results in equally wide elements. This could also be done with vertically positioned elements and margin-top, of course.

Maxilliped answered 17/4, 2016 at 14:44 Comment(1)
This would work as long as the flex items are always in a single row. If wrapping is allowed then it probably won't be sufficient.Frank
J
5

Here's my solution, that doesn't require setting any classes on the child elements:

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

.flex-inline-row.flex-spacing-4px > :not(:last-child) {
    margin-right: 4px;
}

Usage:

<div class="flex-inline-row flex-spacing-4px">
  <span>Testing</span>
  <span>123</span>
</div>

The same technique can be used for normal flex rows and columns in addition to the inline example given above, and extended with classes for spacing other than 4px.

Jerold answered 19/1, 2017 at 14:17 Comment(1)
But it doesn't work with flex-wrapDanford
A
5

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>
Avaria answered 25/5, 2018 at 20:10 Comment(0)
J
4

I find the easiest way of doing this is with percentages and just allowing the margin to tally up your width

This means you end up with something like this if you where using your example

#box {
   display: flex;
}

.item {
   flex: 1 1 23%;
   margin: 0 1%;
}

Does mean your values are based on the width though which might not be good for everybody.

Josephson answered 11/8, 2014 at 11:9 Comment(1)
Just came across this solution and yep, it's very nice. Works in my case, at least (a pen for those who could find it to be interesting: codepen.io/rishatmuhametshin/pen/XXjpaV).Esque
D
3

Here's a grid of card UI elements with spacing completed using flexible box:

enter image description here

I was frustrated with manually spacing the cards by manipulating padding and margins with iffy results. So here's the combinations of CSS attributes I've found very effective:

.card-container {
  width: 100%;
  height: 900px;
  overflow-y: scroll;
  max-width: inherit;
  background-color: #ffffff;
  
  /*Here's the relevant flexbox stuff*/
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: flex-start;
  flex-wrap: wrap; 
}

/*Supplementary styles for .card element*/
.card {
  width: 120px;
  height: 120px;
  background-color: #ffeb3b;
  border-radius: 3px;
  margin: 20px 10px 20px 10px;
}
<section class="card-container">
        <div class="card">

        </div>
        <div class="card">

        </div>
        <div class="card">

        </div>
        <div class="card">

        </div>
      </section>

Hope this helps folks, present and future.

Dynatron answered 3/8, 2017 at 6:44 Comment(1)
Update: This spacing is in effective for mobile rendering HTML elements that need a certain alignment (e.g. center, left, etc.). If you find yourself using flex box for mobile development, I've found relief in switching to purely margin-based alignment.Dynatron
B
3

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.

Botulin answered 10/11, 2017 at 10:8 Comment(0)
T
1

It won't work in every case but if you have flexible child widths (%) and know the number of items per row you can very cleanly specify the margins of the necessary elements by using nth-child selector/s.

It depends largely on what you mean by "better". This way doesn't require additional wrapper markup for child elements or negative elements - but those things both have their place.

.container {
  align-content: flex-start;
  align-items: stretch;
  background-color: #ccc;
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-start;
  width: 100%;
}

.child-item {
  background-color: #c00;
  margin-bottom: 2%;
  min-height: 5em;
  width: 32%;
}

.child-item:nth-child(3n-1) {
  margin-left: 2%;
  margin-right: 2%;
}
<div class="container">
    <div class="child-item"></div>
    <div class="child-item"></div>
    <div class="child-item"></div>
    <div class="child-item"></div>
    <div class="child-item"></div>
    <div class="child-item"></div>
    <div class="child-item"></div>
</div>
Townsfolk answered 9/3, 2016 at 3:53 Comment(2)
Not responsive. Works only for fixed width parent.Haunting
The OP doesn't ask for a responsive solution and their example uses a fix width. Given that this uses % values it's easy to argue that this is responsive since the items will adapt to the size of the parent which is set by percentage.Townsfolk
A
1

#box {
  display: flex;
  width: 100px;
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
}
/* u mean utility */
.u-gap-10 > *:not(:last-child) {
  margin-right: 10px;
}
<div id='box' class="u-gap-10">
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
</div>
Allies answered 16/2, 2017 at 3:35 Comment(0)
T
1

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>
Tanka answered 11/1, 2018 at 22:37 Comment(0)
L
1

I found a hack because i really need this my self.

/* grid */
.container {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}

.container::after, /* this makes sure odd element goes left and not space between */
.item {
  content:"";
  width: calc(33.3333% - 20px);
  margin-bottom: 40px;
}

/* extra styling - not important */
.item {
  height: 100px;
  background: #787878;
}
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

Here's a post grid with nice flex grow categories also. I think you'd like it. See Codepen

Lop answered 12/4, 2018 at 7:2 Comment(0)
P
1

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>
Phoenicia answered 4/7, 2018 at 22:37 Comment(0)
K
1

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

Kentiggerma answered 7/10, 2018 at 18:4 Comment(0)
S
1

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>
Semination answered 9/1, 2022 at 7:38 Comment(0)
M
0

I came across the same issue earlier, then stumbled upon the answer for this. Hope it will help others for future reference.

long answer short, add a border to your child flex-items. then you can specify margins between flex-items to whatever you like. In the snippet, i use black for illustration purposes, you can use 'transparent' if you like.

#box {
  display: flex;
  width: 100px;
  /* margin: 0 -5px; *remove this*/
}
.item {
  background: gray;
  width: 50px;
  height: 50px;
  /* margin: 0 5px; *remove this*/
  border: 1px solid black; /* add this */
}
.item.special{ margin: 0 10px; }
<div id='box'>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item'></div>
  <div class='item special'></div>
</div>
Maccarone answered 8/12, 2016 at 7:11 Comment(0)
S
0

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>
Studhorse answered 9/2, 2018 at 18:44 Comment(0)
B
0

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.

Blamed answered 5/8, 2018 at 22:41 Comment(0)
M
-1

I posted my flexbox approach here:

One idea I rejected was to remove the padding from the outer columns with something like this:

div:nth-child(#{$col-number}n+1) { padding-left: 0; }
div:nth-child(#{$col-number}n+#{$col-number}) { padding-left: 0; }

But, like other posters here, I prefer the negative margin trick. My fiddle also has responsiveness for anyone is looking for a Sass-based solution. I basically use this approach in place of a grid.

https://jsfiddle.net/x3jvfrg1/

Mumps answered 23/7, 2016 at 4:57 Comment(0)
S
-1

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>
Surplice answered 23/4, 2018 at 5:49 Comment(0)
I
-1

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.

Ipoh answered 21/2, 2019 at 15:8 Comment(2)
negative margins has already been suggested in answers here. Please be sure to read all existing answers (not just the top one or two!) before posting your own, to avoid duplication.Nikos
Hey this solution works better when you stacking sections and want a different background colour on the child box. Whereas the other solution dont have that method with the property flex-wrap being applied.Ipoh
L
-1

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;
}
Latrell answered 31/5, 2019 at 15:8 Comment(0)
C
-2

 :root{
  --inner: 20px;
  --gap: 10px; /* same as gutter */
  
  /* flex-flow in row 
  ---------------------*/
  --row-wrap: row wrap;
  --row-nowrap: row nowrap;
  
  /* flex-flow in col 
  ---------------------*/
  --col-wrap: column wrap;
  }
  
  .row {
  display: flex;
  flex-direction: var(--flex-row);
}
/* additional wrapping classes (if needed)
-------------------------------------------*/
.nowrap {
  display: flex;
  flex-flow: var(--row-nowrap);
}
.wrap {
  display: flex;
  flex-flow: var(--col-wrap);
}
/*----------------------------------------*/
[class*="col-"] {
  border: 1px solid #ccc;
  margin: var(--gap);
  padding: var(--inner);
  height: auto;
  background: #333;
  flex: 1 0 auto;
}
.col-3 {
  flex: 3;
}
<div class="row">
  <div class='col-3'></div>
  <div class='col-3'></div>
  <div class='col-3'></div>
  <div class='col-3'></div>
</div>

Also you can view this example.

Carpentaria answered 8/4, 2018 at 5:32 Comment(0)
L
-4

tl;dr

$gutter: 8px;

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

  .children {
    flex: 0 0 calc(33.3333% - $gutter);
  }
}
Labonte answered 26/1, 2018 at 18:55 Comment(1)
Please expand your answer with an explanation.Cassius
L
-6

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)

Laird answered 31/1, 2019 at 0:43 Comment(2)
The main question was asking about the Flexbox technique, your answer is not answering "in topic". Also your solution is very old style (even if it is doing the job).Pieplant
you dont understand the primitives. they will always be, no matter the hype. flexbox has it's definition and if it doesn't say about precise spacing - there is no spacing. Also, these elements author shows are empty bars (treat them as visible spacers) - if there would be content, it could be spaced inside with wrapper paddings.Laird

© 2022 - 2024 — McMap. All rights reserved.