Space between items with and without Flexbox gap

Adding gaps between items became really easy with the introduction of the gap attribute for Grid layouts around 2018. And at the time of writing, gap is also supported for Flexbox layouts by most major browsers, with the notable exception of Safari.

As a quick reminder, this is how gap works with Grid layouts:

.boxes {
  display: grid;
  gap: 12px;
}

And you’ll get the exact same experience with Flexbox layout:

.boxes {
  display: flex;
  gap: 12px;
}

The main difference is that you can now combine it with flex-wrap: wrap.

If you need support for Safari (and it’s early 2021) or older versions of Chrome and Firefox, you’ll have to resort to one of the many workarounds.

Margins on everything but the last thing #

This is easy to get right: every item gets a margin on the right except for the very last one.

.boxes > :not(:last-child) {
  margin-right: 12px;
}

A drawback is that we can’t support potential wrapping items, since we would need a conditional bottom margin, and even then, the horizontal margins stop making sense:

The lobotomized owl #

I’ve used this one the most. If I’m being honest, probably because of the memorable name. There are some advantages, though, but those are best explained by A List Apart.

.boxes > * + * {
  margin-left: 12px;
}

Sadly, the lobotomized owl doesn’t handle wrapping either:

Hidden negative margins #

This one works by wrapping the layout with overflow: hidden.

.wrapper {
  overflow: hidden;
}

.boxes > * {
  margin: 12px 0 0 12px;
}

.boxes {
  display: flex;
  flex-wrap: wrap;
  margin: -12px 0 0 -12px;
  width: calc(100% + 12px);
}

To illustrate why the wrapper is necessary, here it is without it:

Flexible grid #

We can achieve a very similar result using a Grid layout:

.boxes {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(20%, 1fr));
}

Why only “very similar”? What can Flexbox do that Grid can’t? Flexbox is content-driven and Grid is layout-driven. A wrapping layout with items of different computed sizes isn’t possible with Grid. Here’s the example from above repurposed to attempt an auto-sized, auto-wrapping layout. The items all end up with the same width:

Raindrops on roses
Whiskers on kittens
Bright copper kettles
Warm woolen mittens
Brown paper packages tied up with strings
These are a few of my favorite things

Here’s another attempt with grid-auto-flow: column and white-space: nowrap which unfortunately no longer features auto-wrapping columns:

Raindrops on roses
Whiskers on kittens
Bright copper kettles
Warm woolen mittens
Brown paper packages tied up with strings
These are a few of my favorite things

As mentioned in the beginning, this is trivial with flex-wrap: wrap.

.boxes {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.box {
  flex: 0 0 auto;
}
Raindrops on roses
Whiskers on kittens
Bright copper kettles
Warm woolen mittens
Brown paper packages tied up with strings
These are a few of my favorite things

If you manage to do this with Grid, please submit a pull-request to edit this post! I’ll be happy to merge it and learn something new along the way.

I’m looking forward to using gap with Flexbox. Especially once the next major version of Safari is released, which should include the Webkit changeset that added support for it.

Thanks to sirlantis for a careful review of this post.