Space Elements With Flexbox Instead of Margin

Published Aug 31, 2021

In your HTML markup you often have repeating blocks such as lists, cards, and posts.

example.html
<section>
  <h1>Samurai Movies</h1>
  <ul class="movies">
    <li class="movie">Seven Samurai</li>
    <li class="movie">Hara-Kiri</li>
    <li class="movie">Yojimbo</li>
    <li class="movie">The Sword of Doom</li>
  </ul>
</section>

Using margin can get tedious and repetitive, and you’re probably going to encounter margin collapsing which you won’t even understand is causing the problem if you never heard of it.

That being said we can reduce the amount of markup inside a templating system or framework, so it’s not that big of a deal.

example.js
const movies = ['Seven Samurai', 'Hara-Kiri', 'Yojimbo', 'The Sword of Doom']

const moviesHtml = `
  <section>
    <h1>Samurai Movies</h1>
    <ul class="movies">
      ${movies.map(movie => `<li class="movie">${movie}</li>`).join('')}
    </ul>
  </section>
`

document.body.innerHTML = moviesHtml

We could set the margin for each .movie class but then it would also affect the top element.

example.css
.movie {
  margin-top: 1rem;
}

To refine the previous example we could specify to only target the children after the first child of the .movies class.

example.css
.movies > *:not(:first-child) {
  margin-top: 1rem;
}

We might like to reuse the spacing in our project but it would be tedious and hard to update it’s value if we changed the spacing in the future, so we could create a utiliy class that can be reused across the project.

I find this to be the most reasonable approach for most people who prefer writing regular CSS, but can also take advantage of CSS custom properties and utility classes such as provided by Tailwind CSS.

example.css
:root {
  --space: 1rem;
}

.space > *:not(:first-child) {
  margin-top: var(--space);
}

We can do better. Instead of using margin we can take advantage of flexbox and it’s gap property that’s been previously reserved for CSS Grid Layout.

At the time of writing the gap property is supported across 86% of browsers, so it works for every modern browser.

example.css
.movies {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

It’s easier to create utility classes that we can reuse on every project. You can set different spacing sizes if you want.

example.html
<section>
  <h1>Samurai Movies</h1>
  <ul class="flex flex-col space">
    <li>Seven Samurai</li>
    <li>Hara-Kiri</li>
    <li>Yojimbo</li>
    <li>The Sword of Doom</li>
  </ul>
</section>
example.css
:root {
  --space: 1rem;
}

.flex {
  display: flex;
}

.flex-col {
  flex-direction: column;
}

.space {
  gap: var(--space);
}

Conclusion

Having the ability to write regular CSS but have a set of constraints from utility classes is a great way to achieve a consistent looking design.

By using gap instead of margin we can avoid problems such as margin collapsing, and make our markup less verbose.

Thanks for reading! 🏄‍♀️

Support

If you want to support the content you're reading or watching on YouTube consider becoming a patreon starting low as 1$ per month.

Become a patreon
Subscribe For Updates
Found a mistake?

Every post is a Markdown file so contributing is simple as following the link below and pressing the pencil icon inside GitHub to edit it.

Edit on GitHub