gap is a very useful CSS property that allows to set separation or glutter between children elements in a layout.
.container {
gap: 1rem;
display: flex;
flex-wrap: wrap;
max-width: 22rem;
}
Produces:
gap
is a shorthand to set row-gap
(vertical gap) and column-gap
(horizontal gap) in one declaration.
.container {
/* Separate declaration for row and column gap */
row-gap: 1rem;
column-gap: 2rem;
/* Shorthand */
gap: 1rem 2rem;
}
Unfortunately, gap
global support is not very complete, specially in Safari. At the time of this writing, it has 71.56% support due primarily to lack of support in Safari (it started supporting gap for flex containers since iOS 14.5 launched on April 26, 2021).
Important: gap
support for flexbox containers is lower than on grid containers, which has a global support of 92.9%
Gap for flexbox containers
Depending on our target users, they may use old browsers. If you check your website usage and notice that an important part of your users use browsers that don't play well with the gap
property on flexbox, you may need to use a polyfill instead.
Let's start with the following markup:
<div class='flex-gap-4'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
We build a container with 8 children. I've ommited styling classes to keep it simple.
Here's the class of the container:
.flex-gap-4 {
display: flex;
flex-wrap: wrap;
}
We defined a flex container that allows elements to wrap.
This produces a grid-like view of four elements per row as shown below:
Now, let's try to add a separation between each item within the container. Let's try to add margin between elements by using the Adjacent Sibling Combinator (* + *):
.flex-gap-4 > * + * {
margin-left: 1rem;
margin-bottom: 1rem;
}
Here's how it looks:
It doesn't work because when items span more than one column, from the second item on, there's extra margin to the left. This is because we're applying margin to every children that follows another children. You can read more about the Adjacent Sibling Combinator here.
To fix the issue with the extra margin at the left and top, we can add negative margins to the parent like this:
.flex-gap-4 {
margin-left: -1rem;
margin-top: -1rem;
}
Now our layout looks as expected:
Now that we have a working layout with gaps, here's how our code looks like:
.flex-gap-4 {
display: flex;
flex-wrap: wrap;
margin-left: -1rem;
margin-top: -1rem;
}
.flex-gap-4 > * {
margin-left: 1rem;
margin-top: 1rem;
}
You can customize the margins whenever you want to simulate row-gap
and column-gap
using CSS properties:
.flex-gap {
display: flex;
flex-wrap: wrap;
margin-left: calc(-1 * var(--column-gap, 0));
margin-top: calc(-1 * var(--row-gap, 0));
}
.flex-gap-4 > * {
margin-left: var(--column-gap, 1rem);
margin-top: var(--row-gap, 1rem);
}
You can't add border that surrounds the content because inner elements have a margin applied to the left.
Since we use margins on both the parent and children elements, if we try to have multiple levels of nesting involving our solution, it won't work because we're trying to modify the margin between elements. Below is an example on this that shows how a little margin is added to the elements.
If you can use gap
, go ahead and do it. Your code will be easier to manage and
less error-prone. If you can't, make sure that you apply a polyfill that is easy
to change in the future so you can evaluate it again in, let's say 1 year or
whatever makes sense to you!