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

You can subscribe on YouTube, or consider becoming a patron if you want to support my work.

Patreon
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