Creating columns

We have four different areas of our layout that require columns.

  • The three cards on the home page
  • Several sections that have an image and text next to each other
  • The grid of mushroom information
  • The bento layout

The grid and bento style layouts are unique when compared to the other two, so we'll come back to those later.

Do we need different classes?

At first glance, the the two column sections and the three column one with the cards are quite different:

  • The content inside them is different
  • One has three columns, the other has two
  • The gap between them is different

Content shouldn't matter

When working on layouts, try not to get stuck on what's inside the layout.

Well put together layouts should be versatile, meaning they are creating a layout that you can plug and play different types of content into.

The number of columns

There are a few ways we could deal with that.

If you use flexbox, by default you'll be getting a column for every direct child:

.columns {
  display: flex;
}

And there are a few different ways you could tackle this with grid:

.columns {
  --column-count: 3;

  display: grid;
  grid-template-columns: repeat(var(--column-count), 1fr);
}

And while that's more of a common approach, this might be simpler:

.columns {
  display: grid;
  grid-auto-flow: column;
}

Flexbox or Grid?

As we can see with those examples, either one could work for these.

There are some advantages to using Grid though:

  • It's easier to create evenly-sized columns
  • Potentially, a little less code

Project and layout dependent

You might need to have something that's 3 columns, but has more than 3 children in it, in which case, grid-template-columns: repeat(var(--column-count), 1fr); is probably the best choice.

Other times, like in this project, it might not be so clear cut which one the best option is, meaning that you could probably justify any of them.

The breakpoint(s)

The examples I shared above all create columns, but these layouts need to be stacked at small screens, and go next to each other at larger screens, which means that we need to decide on a breakpoint to use.

I'm a fan of not overthinking breakpoints, and reducing the number of them used in a layout, so I'll be going with one single breakpoint, which I'll adjust later on once I see how the layout is working.

The gap

For me, this is a great place for a custom property to make that easy to adjust:

@layer layout {
  .equal-columns {
    display: grid;
    gap: var(--equal-columns-gap, 1rem);

    @media (width > 760px) {
      grid-auto-flow: column;
      grid-auto-columns: 1fr;
    }
  }
}

And then this could be modified either with a modifier:

.equal-columns--large-gap {
  --equal-columns-gap: 2rem;
}

.equal-columns--no-gap {
  --equal-columns-gap: 0rem;
}

/* or */
.equal-columns[data-gap="large"] {
  --equal-columns-gap: 2rem;
}

.equal-columns[data-gap="none"] {
  --equal-columns-gap: 0;
}

Or, if you prefer, you could modify it where you need it.

.example {
  --equal-columns-gap: 3rem;

  /* other styles */
}

Modifying their alignment

We need some of our columns to have their content vertically centered.

Once again, a modifier works best here, in my opinion:

.equal-columns {
  /* other styles */

  align-items: var(--column-layout-alignment, start);

  &[data-vertical-alignment="centered"] {
    --column-layout-alignment: center;
  }

  &[data-vertical-alignment="bottom"] {
    --column-layout-alignment: end;
  }
}