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 {_x000D_
display: flex;_x000D_
width: 100px;_x000D_
margin: 0 -5px;_x000D_
}_x000D_
.item {_x000D_
background: gray;_x000D_
width: 50px;_x000D_
height: 50px;_x000D_
margin: 0 5px;_x000D_
}
_x000D_
<div id='box'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
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;
}
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>
You can use & > * + *
as a selector to emulate a flex-gap
(for a single line):
#box { display: flex; width: 230px; outline: 1px solid blue; }_x000D_
.item { background: gray; width: 50px; height: 100px; }_x000D_
_x000D_
/* ----- Flexbox gap: ----- */_x000D_
_x000D_
#box > * + * {_x000D_
margin-left: 10px;_x000D_
}
_x000D_
<div id='box'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
If you need to support flex wrapping, you can use a wrapper element:
.flex { display: flex; flex-wrap: wrap; }_x000D_
.box { background: gray; height: 100px; min-width: 100px; flex: auto; }_x000D_
.flex-wrapper {outline: 1px solid red; }_x000D_
_x000D_
/* ----- Flex gap 10px: ----- */_x000D_
_x000D_
.flex > * {_x000D_
margin: 5px;_x000D_
}_x000D_
.flex {_x000D_
margin: -5px;_x000D_
}_x000D_
.flex-wrapper {_x000D_
width: 400px; /* optional */_x000D_
overflow: hidden; /* optional */_x000D_
}
_x000D_
<div class='flex-wrapper'>_x000D_
<div class='flex'>_x000D_
<div class='box'></div>_x000D_
<div class='box'></div>_x000D_
<div class='box'></div>_x000D_
<div class='box'></div>_x000D_
<div class='box'></div>_x000D_
</div>_x000D_
</div>
_x000D_
You can try CSS3's :not selector
Eg:
#box {_x000D_
display: flex;_x000D_
width: 100px;_x000D_
border: 1px red solid;_x000D_
}_x000D_
_x000D_
.item {_x000D_
background: gray;_x000D_
width: 10px;_x000D_
height: 100px;_x000D_
flex: 1 1 auto;_x000D_
}_x000D_
_x000D_
.item:not(:last-child) {_x000D_
margin-right: 5px;_x000D_
}
_x000D_
<div id='box'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
I often use the + operator for such cases
#box {_x000D_
display: flex;_x000D_
width: 100px;_x000D_
}_x000D_
.item {_x000D_
background: gray;_x000D_
width: 50px;_x000D_
height: 50px;_x000D_
}_x000D_
.item + .item {_x000D_
margin-left: 5px;_x000D_
}
_x000D_
<div id='box'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
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 {_x000D_
margin: 0;_x000D_
}_x000D_
_x000D_
.container {_x000D_
display: flex;_x000D_
}_x000D_
_x000D_
.item {_x000D_
flex: 1;_x000D_
background: gray;_x000D_
height: 50px;_x000D_
}_x000D_
_x000D_
.item:not(:last-child) {_x000D_
margin-right: 10px;_x000D_
}
_x000D_
<div class="container">_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
</div>
_x000D_
If you want to allow flex wrap, see the following example.
body {_x000D_
margin: 0;_x000D_
}_x000D_
_x000D_
.container {_x000D_
display: flex;_x000D_
flex-wrap: wrap;_x000D_
margin-left: -10px;_x000D_
}_x000D_
_x000D_
.item {_x000D_
flex: 0 0 calc(50% - 10px);_x000D_
background: gray;_x000D_
height: 50px;_x000D_
margin: 0 0 10px 10px;_x000D_
}
_x000D_
<div class="container">_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
</div>
_x000D_
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:
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).::after
to pad the last row if there are fewer elements than columns.flex-container {_x000D_
display: flex;_x000D_
justify-content: space-between;_x000D_
flex-wrap: wrap;_x000D_
}_x000D_
.flex-container:after {_x000D_
content: "";_x000D_
}_x000D_
.flex-container > div,_x000D_
.flex-container:after {_x000D_
box-sizing: border-box;_x000D_
width: calc((100%/3) - ((1em/3)*2));_x000D_
}_x000D_
.flex-container > :nth-child(n + 4) {_x000D_
margin-top: 1em;_x000D_
}_x000D_
_x000D_
/* the following is just to visualize the items */_x000D_
.flex-container > div,_x000D_
.flex-container:after {_x000D_
font-size: 2em;_x000D_
}_x000D_
.flex-container {_x000D_
margin-bottom:4em;_x000D_
}_x000D_
.flex-container > div {_x000D_
text-align: center;_x000D_
background-color: #aaa;_x000D_
padding: 1em;_x000D_
}_x000D_
.flex-container:after {_x000D_
border: 1px dashed red;_x000D_
}
_x000D_
<h2>Example 1 (2 elements)</h2>_x000D_
<div class="flex-container">_x000D_
<div>1</div>_x000D_
<div>2</div>_x000D_
</div>_x000D_
_x000D_
<h2>Example 2 (3 elements)</h2>_x000D_
<div class="flex-container">_x000D_
<div>1</div>_x000D_
<div>2</div>_x000D_
<div>3</div>_x000D_
</div>
_x000D_
:root{_x000D_
--inner: 20px;_x000D_
--gap: 10px; /* same as gutter */_x000D_
_x000D_
/* flex-flow in row _x000D_
---------------------*/_x000D_
--row-wrap: row wrap;_x000D_
--row-nowrap: row nowrap;_x000D_
_x000D_
/* flex-flow in col _x000D_
---------------------*/_x000D_
--col-wrap: column wrap;_x000D_
}_x000D_
_x000D_
.row {_x000D_
display: flex;_x000D_
flex-direction: var(--flex-row);_x000D_
}_x000D_
/* additional wrapping classes (if needed)_x000D_
-------------------------------------------*/_x000D_
.nowrap {_x000D_
display: flex;_x000D_
flex-flow: var(--row-nowrap);_x000D_
}_x000D_
.wrap {_x000D_
display: flex;_x000D_
flex-flow: var(--col-wrap);_x000D_
}_x000D_
/*----------------------------------------*/_x000D_
[class*="col-"] {_x000D_
border: 1px solid #ccc;_x000D_
margin: var(--gap);_x000D_
padding: var(--inner);_x000D_
height: auto;_x000D_
background: #333;_x000D_
flex: 1 0 auto;_x000D_
}_x000D_
.col-3 {_x000D_
flex: 3;_x000D_
}
_x000D_
<div class="row">_x000D_
<div class='col-3'></div>_x000D_
<div class='col-3'></div>_x000D_
<div class='col-3'></div>_x000D_
<div class='col-3'></div>_x000D_
</div>
_x000D_
Also you can view this example.
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.
tl;dr
$gutter: 8px;
.container {
display: flex;
justify-content: space-between;
.children {
flex: 0 0 calc(33.3333% - $gutter);
}
}
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
, andgap
propertiesThe
row-gap
andcolumn-gap
properties (and theirgap
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 {_x000D_
display: inline-grid;_x000D_
grid-auto-rows: 50px;_x000D_
grid-template-columns: repeat(4, 50px);_x000D_
border: 1px solid black;_x000D_
}_x000D_
_x000D_
.one {_x000D_
grid-column-gap: 5px;_x000D_
}_x000D_
_x000D_
.two {_x000D_
grid-column-gap: 10px;_x000D_
grid-row-gap: 10px;_x000D_
}_x000D_
_x000D_
.three {_x000D_
grid-gap: 10px;_x000D_
padding: 10px;_x000D_
}_x000D_
_x000D_
.item {_x000D_
background: lightgray;_x000D_
}
_x000D_
<div class='box one'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>_x000D_
_x000D_
<hr>_x000D_
_x000D_
<div class='box two'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>_x000D_
_x000D_
<hr>_x000D_
_x000D_
<div class='box three'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
More information:
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;
}
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 {_x000D_
display: flex;_x000D_
flex-flow: row wrap;_x000D_
justify-content: space-around;_x000D_
margin-bottom: 10px;_x000D_
}_x000D_
_x000D_
.item {_x000D_
height: 50px;_x000D_
display: flex;_x000D_
justify-content: center;_x000D_
align-items: center;_x000D_
background-color: #999;_x000D_
}_x000D_
_x000D_
.item-1-4 {_x000D_
flex-basis: calc(25% - 10px);_x000D_
}_x000D_
_x000D_
.item-1-3 {_x000D_
flex-basis: calc(33.33333% - 10px);_x000D_
}_x000D_
_x000D_
.item-1-2 {_x000D_
flex-basis: calc(50% - 10px);_x000D_
}
_x000D_
<div class="container">_x000D_
<div class="item item-1-4">1</div>_x000D_
<div class="item item-1-4">2</div>_x000D_
<div class="item item-1-4">3</div>_x000D_
<div class="item item-1-4">4</div>_x000D_
</div>_x000D_
<div class="container">_x000D_
<div class="item item-1-3">1</div>_x000D_
<div class="item item-1-3">2</div>_x000D_
<div class="item item-1-3">3</div>_x000D_
</div>_x000D_
<div class="container">_x000D_
<div class="item item-1-2">1</div>_x000D_
<div class="item item-1-2">2</div>_x000D_
</div>
_x000D_
Here's a grid of card UI elements with spacing completed using flexible box:
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 {_x000D_
width: 100%;_x000D_
height: 900px;_x000D_
overflow-y: scroll;_x000D_
max-width: inherit;_x000D_
background-color: #ffffff;_x000D_
_x000D_
/*Here's the relevant flexbox stuff*/_x000D_
display: flex;_x000D_
flex-direction: row;_x000D_
justify-content: center;_x000D_
align-items: flex-start;_x000D_
flex-wrap: wrap; _x000D_
}_x000D_
_x000D_
/*Supplementary styles for .card element*/_x000D_
.card {_x000D_
width: 120px;_x000D_
height: 120px;_x000D_
background-color: #ffeb3b;_x000D_
border-radius: 3px;_x000D_
margin: 20px 10px 20px 10px;_x000D_
}
_x000D_
<section class="card-container">_x000D_
<div class="card">_x000D_
_x000D_
</div>_x000D_
<div class="card">_x000D_
_x000D_
</div>_x000D_
<div class="card">_x000D_
_x000D_
</div>_x000D_
<div class="card">_x000D_
_x000D_
</div>_x000D_
</section>
_x000D_
Hope this helps folks, present and future.
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 {_x000D_
display: flex;_x000D_
flex-grow: 1;_x000D_
flex-shrink: 1;_x000D_
}_x000D_
_x000D_
.box.columns {_x000D_
flex-direction: row;_x000D_
}_x000D_
_x000D_
.box.columns>.box~.box {_x000D_
margin-left: 5px;_x000D_
}_x000D_
_x000D_
.box.rows {_x000D_
flex-direction: column;_x000D_
}_x000D_
_x000D_
.box.rows>.box~.box {_x000D_
margin-top: 5px;_x000D_
}
_x000D_
<div class="box columns">_x000D_
<div class="box" style="background-color: red;"></div>_x000D_
<div class="box rows">_x000D_
<div class="box rows">_x000D_
<div class="box" style="background-color: blue;"></div>_x000D_
<div class="box" style="background-color: orange;"></div>_x000D_
<div class="box columns">_x000D_
<div class="box" style="background-color: yellow;"></div>_x000D_
<div class="box" style="background-color: pink;"></div>_x000D_
</div>_x000D_
</div>_x000D_
<div class="box" style="background-color: green;"></div>_x000D_
</div>_x000D_
</div>
_x000D_
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 {_x000D_
stage: 0;_x000D_
browsers: last 2 versions_x000D_
}_x000D_
_x000D_
section {_x000D_
width: 30vw;_x000D_
_x000D_
display: grid;_x000D_
gap: 1rem;_x000D_
grid-template-columns: repeat(auto-fit, minmax(12ch, 1fr));_x000D_
_x000D_
&[flex] {_x000D_
display: flex;_x000D_
flex-wrap: wrap;_x000D_
}_x000D_
_x000D_
margin-bottom: 3rem;_x000D_
}_x000D_
_x000D_
.tag {_x000D_
color: white;_x000D_
background: hsl(265 100% 47%);_x000D_
padding: .5rem 1rem;_x000D_
border-radius: 1rem;_x000D_
}_x000D_
_x000D_
button {_x000D_
display: inline-flex;_x000D_
place-items: center;_x000D_
gap: .5rem;_x000D_
background: hsl(265 100% 47%);_x000D_
border: 1px solid hsl(265 100% 67%);_x000D_
color: white;_x000D_
padding: 1rem 2rem;_x000D_
border-radius: 1rem;_x000D_
font-size: 1.25rem;_x000D_
}_x000D_
_x000D_
body {_x000D_
min-height: 100vh;_x000D_
display: flex;_x000D_
flex-direction: column;_x000D_
justify-content: center;_x000D_
align-items: center;_x000D_
}
_x000D_
<section>_x000D_
<h1>Grid</h1> _x000D_
<div class="tag">Awesome</div>_x000D_
<div class="tag">Coo</div>_x000D_
<div class="tag">Rad</div>_x000D_
<div class="tag">Math</div>_x000D_
</section>_x000D_
<br>_x000D_
<section flex>_x000D_
<h1>Flex</h1>_x000D_
<div class="tag">Awesome</div>_x000D_
<div class="tag">Coo</div>_x000D_
<div class="tag">Rad</div>_x000D_
<div class="tag">Math</div>_x000D_
</section>
_x000D_
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.
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.
section {_x000D_
display: block_x000D_
width: 100vw;_x000D_
}_x000D_
.container {_x000D_
align-content: flex-start;_x000D_
align-items: stretch;_x000D_
background-color: #ccc;_x000D_
display: flex;_x000D_
flex-flow: row wrap;_x000D_
justify-content: flex-start;_x000D_
width: 100%;_x000D_
}_x000D_
_x000D_
.child-item {_x000D_
background-color: #c00;_x000D_
margin-bottom: 2%;_x000D_
min-height: 5em;_x000D_
width: 32%;_x000D_
}_x000D_
_x000D_
.child-item:nth-child(3n-1) {_x000D_
margin-left: 2%;_x000D_
margin-right: 2%;_x000D_
}
_x000D_
<html>_x000D_
<body>_x000D_
<div class="container">_x000D_
<div class="child-item"></div>_x000D_
<div class="child-item"></div>_x000D_
<div class="child-item"></div>_x000D_
<div class="child-item"></div>_x000D_
<div class="child-item"></div>_x000D_
<div class="child-item"></div>_x000D_
<div class="child-item"></div>_x000D_
</div>_x000D_
</body>_x000D_
</html>
_x000D_
According to #ChromeDevSummit there's an implementation of the gap
property for Flexbox in Firefox and Chromium-based browsers.
Here's a Live Demo
Assuming:
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 {_x000D_
display: flex;_x000D_
flex-direction: row;_x000D_
flex-wrap: wrap;_x000D_
margin: 1em 0;_x000D_
background-color: peachpuff;_x000D_
}_x000D_
_x000D_
.item {_x000D_
margin-left: 10px;_x000D_
border: 1px solid;_x000D_
padding: 10px;_x000D_
width: calc(100% / 4 - 2px - 20px - 10px * (4 - 1) / 4);_x000D_
background-color: papayawhip;_x000D_
}_x000D_
_x000D_
.item:nth-child(4n + 1) {_x000D_
margin-left: 0;_x000D_
}_x000D_
_x000D_
.item:nth-child(n + 5) {_x000D_
margin-top: 10px;_x000D_
}
_x000D_
<div class="flex">_x000D_
<div class="item">1</div>_x000D_
<div class="item">2</div>_x000D_
<div class="item">3</div>_x000D_
<div class="item">4</div>_x000D_
</div>_x000D_
<div class="flex">_x000D_
<div class="item">1</div>_x000D_
<div class="item">2</div>_x000D_
<div class="item">3</div>_x000D_
<div class="item">4</div>_x000D_
<div class="item">5</div>_x000D_
<div class="item">6</div>_x000D_
</div>_x000D_
<div class="flex">_x000D_
<div class="item">1</div>_x000D_
<div class="item">2</div>_x000D_
<div class="item">3</div>_x000D_
<div class="item">4</div>_x000D_
<div class="item">5</div>_x000D_
<div class="item">6</div>_x000D_
<div class="item">7</div>_x000D_
<div class="item">8</div>_x000D_
<div class="item">9</div>_x000D_
</div>
_x000D_
gap
property:There is a new gap
CSS property for multi-column, flexbox, and grid layouts that works in some browsers now! (See Can I use link 1; link 2). It is shorthand for row-gap
and column-gap
.
#box {
display: flex;
flex-wrap: wrap;
width: 200px;
background-color: red;
gap: 10px;
}
.item {
background: gray;
width: 50px;
height: 50px;
border: 1px black solid;
}
_x000D_
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
_x000D_
As of writing, this works in Firefox, Chrome, and Edge but not Safari.
row-gap
property:The row-gap
CSS property for both flexbox and grid layouts allows you to create a gap between rows. I think Safari doesn't support it yet.
#box {
display: flex;
row-gap: 10px;
}
column-gap
property:The column-gap
CSS property for multi-column, flexbox and grid layouts works allows you to create a gap between columns. I think Safari doesn't support it yet.
#box {
display: flex;
column-gap: 10px;
}
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.
#box {
display:-ms-flex; /* Older IE Compatibility ;) */
display:flex;
justify-content:space-between;
}
The 'justify-content' property makes even the gaps, no matter what's your containing div width.
So, lets say your gap is 10px, you have 4 elements so you have 3 gaps: 3*10px = 30px.
#box .item {
flex-basis:calc((100% - 30px) /4);
}
This simple calculation just substracts all gaps added up to the container width, the 'justify-content' property above mentioned takes care of the horizontal alignment. Remaining space is divided by 4 (yep that's our number of elements) giving each .item its width. No other property needed, remember they're already aligned!
Hope this helps!
PS: If you need width in your container you set it, same if the gap size or number of elements change, fix the 'flex-basis' calculation in the .item element to address all of them in one line.
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:
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.
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});}
}
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.
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.
Use the css display: inline-flex; value.
<div id='box'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
</div>
.box {
display: inline-flex;
gap: 10px; // gap between items
}
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.
#box {_x000D_
display: flex;_x000D_
width: 100px;_x000D_
}_x000D_
.item {_x000D_
background: gray;_x000D_
width: 50px;_x000D_
height: 50px;_x000D_
}_x000D_
/* u mean utility */_x000D_
.u-gap-10 > *:not(:last-child) {_x000D_
margin-right: 10px;_x000D_
}
_x000D_
<div id='box' class="u-gap-10">_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
We are using display: grid;
and its properties.
#box {_x000D_
display: grid;_x000D_
width: 100px;_x000D_
grid-gap: 5px;_x000D_
/* Space between items */_x000D_
grid-template-columns: 1fr 1fr 1fr 1fr;_x000D_
/* Decide the number of columns and size */_x000D_
}_x000D_
_x000D_
.item {_x000D_
background: gray;_x000D_
width: 100%;_x000D_
/* 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%** */_x000D_
height: 50px;_x000D_
}
_x000D_
<div id='box'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
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
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 {_x000D_
display: flex;_x000D_
width: 100px;_x000D_
}_x000D_
.item {_x000D_
background: gray;_x000D_
width: 22px;_x000D_
height: 50px;_x000D_
}_x000D_
.item+.item{_x000D_
margin-left: 5px;_x000D_
}
_x000D_
<div id='box'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
Hello, below is my working solution for all browsers supporting flexbox. No negative margins.
_x000D_
.flexbox {_x000D_
display: flex;_x000D_
flex-direction: row;_x000D_
flex-wrap: wrap;_x000D_
justify-content: space-between;_x000D_
}_x000D_
_x000D_
.flexbox > div {_x000D_
/*_x000D_
1/3 - 3 columns per row_x000D_
10px - spacing between columns _x000D_
*/_x000D_
box-sizing: border-box;_x000D_
margin: 10px 10px 0 0;_x000D_
outline: 1px dotted red;_x000D_
width: calc(1/3*100% - (1 - 1/3)*10px);_x000D_
}_x000D_
_x000D_
/*_x000D_
align last row columns to the left_x000D_
3n - 3 columns per row_x000D_
*/_x000D_
.flexbox > div:nth-child(3n) {_x000D_
margin-right: 0;_x000D_
}_x000D_
_x000D_
.flexbox::after {_x000D_
content: '';_x000D_
flex: auto;_x000D_
}_x000D_
_x000D_
/*_x000D_
remove top margin from first row_x000D_
-n+3 - 3 columns per row _x000D_
*/_x000D_
.flexbox > div:nth-child(-n+3) {_x000D_
margin-top: 0;_x000D_
}
_x000D_
<div class="flexbox">_x000D_
<div>col</div>_x000D_
<div>col</div>_x000D_
<div>col</div>_x000D_
<div>col</div>_x000D_
<div>col</div>_x000D_
</div>
_x000D_
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
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.
This is not a hack. The same technique is also used by bootstrap and its grid, though, instead of margin, bootstrap uses padding for its cols.
.row {
margin:0 -15px;
}
.col-xx-xx {
padding:0 15px;
}
.columnify {
display: flex;
> * {
flex: 1;
&:not(:first-child) {
margin-left: 2rem;
}
}
}
.columnify {_x000D_
display: flex;_x000D_
}_x000D_
_x000D_
.columnify > * {_x000D_
flex: 1;_x000D_
}_x000D_
_x000D_
.columnify > *:not(:first-child) {_x000D_
margin-left: 2rem;_x000D_
}
_x000D_
<div class="columnify">_x000D_
<div style="display: inline-block; height: 20px; background-color: blue;"></div>_x000D_
<div style="display: inline-block; height: 20px; background-color: blue"></div>_x000D_
<div style="display: inline-block; height: 20px; background-color: blue"></div>_x000D_
</div>
_x000D_
Play with it on JSFiddle.
Just use .item + .item
in selector to match from second .item
#box {_x000D_
display: inline-flex;_x000D_
margin: 0 -5px;_x000D_
}_x000D_
.item {_x000D_
background: gray;_x000D_
width: 10px;_x000D_
height: 50px;_x000D_
}_x000D_
_x000D_
#box .item + .item {_x000D_
margin-left: 10px;_x000D_
}
_x000D_
<div id='box'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
</div>
_x000D_
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.
The negative margin trick on the box container works just great. Here is another example working great with order, wrapping and what not.
.container {_x000D_
border: 1px solid green;_x000D_
width: 200px;_x000D_
display: inline-block;_x000D_
}_x000D_
_x000D_
#box {_x000D_
display: flex;_x000D_
flex-wrap: wrap-reverse;_x000D_
margin: -10px;_x000D_
border: 1px solid red;_x000D_
}_x000D_
.item {_x000D_
flex: 1 1 auto;_x000D_
order: 1;_x000D_
background: gray;_x000D_
width: 50px;_x000D_
height: 50px;_x000D_
margin: 10px;_x000D_
border: 1px solid blue;_x000D_
}_x000D_
.first {_x000D_
order: 0;_x000D_
}
_x000D_
<div class=container>_x000D_
<div id='box'>_x000D_
<div class='item'>1</div>_x000D_
<div class='item'>2</div>_x000D_
<div class='item first'>3*</div>_x000D_
<div class='item'>4</div>_x000D_
<div class='item'>5</div>_x000D_
</div>_x000D_
</div>
_x000D_
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 {_x000D_
display: flex;_x000D_
width: 100px;_x000D_
/* margin: 0 -5px; *remove this*/_x000D_
}_x000D_
.item {_x000D_
background: gray;_x000D_
width: 50px;_x000D_
height: 50px;_x000D_
/* margin: 0 5px; *remove this*/_x000D_
border: 1px solid black; /* add this */_x000D_
}_x000D_
.item.special{ margin: 0 10px; }
_x000D_
<div id='box'>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item'></div>_x000D_
<div class='item special'></div>_x000D_
</div>
_x000D_
I found a hack because i really need this my self.
/* grid */_x000D_
.container {_x000D_
display: flex;_x000D_
flex-flow: row wrap;_x000D_
justify-content: space-between;_x000D_
}_x000D_
_x000D_
.container::after, /* this makes sure odd element goes left and not space between */_x000D_
.item {_x000D_
content:"";_x000D_
width: calc(33.3333% - 20px);_x000D_
margin-bottom: 40px;_x000D_
}_x000D_
_x000D_
/* extra styling - not important */_x000D_
.item {_x000D_
height: 100px;_x000D_
background: #787878;_x000D_
}
_x000D_
<div class="container">_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
<div class="item"></div>_x000D_
</div>
_x000D_
Here's a post grid with nice flex grow categories also. I think you'd like it. See Codepen
Source: Stackoverflow.com