Solving Problems With CSS Grid and Flexbox: The Card UI

The “card” pattern has seen great success in recent times, but the way we build them is still limited because of the CSS available to us. Until now, that is. By combining CSS Grid and Flexbox, we can make cards which align neatly, behave responsively, and which adapt to the content within them. Let’s see how!

What We’re Going to Build

In this CSS Grid and Flexbox tutorial we’re going to build this card UI (check out the full page version for a clearer idea):

At various breakpoints the card arrangement will change as follows:

CSS Grid vs. Flexbox

When Flexbox hit the CSS scene cries of joy could be heard across the world; finally we had a layout module to solve all our float frustrations. But that wasn’t actually the case. Flexbox works best to distribute elements along a single axis; either horizontally along a row, or vertically as a column. Building a truly fluid grid with Flexbox is difficult.

Grid, however, is intended for laying out elements across two axes (or dimensions); horizontally and vertically. In this tutorial we’re going to use each one for the purpose it was intended, giving us a really solid solution. Let’s begin!

Inspiration for This Tutorial

Recently bbc.co.uk launched (in beta) their latest iteration, going clean and spacious with their card UI. Ignoring the miserable headlines, this looks great.

The top cards are built and aligned across the row with Flexbox, but we’re going to expand on the layout using Grid.

Note: to follow along you’ll need a browser which supports Grid. Here’s some info to get you started.

Our Card Markup

Let’s begin with a wrapper for our grid <div class="band">, some grid items to arrange everything <div class="item">, and some anchors (each anchor will be a card):

Place as many cards as you like; we’re using seven. Each one has a thumbnail <div class="thumb"> which we’ll give a background image later on. Then there’s an <article>, which in turn houses an <h1>, a <span> for the author, and perhaps even a <p> for some more information.

CSS Grid Layout Basics

Now let’s kick off some styles by arranging each of these items in a grid.

Note: if this is your first foray into “Grid” you may want to get up to speed by reading the initial tutorials in Understanding CSS Grid Layout.

We’ll go mobile first here, so the first styles will give our wrapper a width and center it, then set some Grid rules:

Most importantly, here we’re stating that our .band will be display: grid;. We then declare grid-template-columns of 1fr, which says that each column will take up a single fraction of those available. We’ve only declared one for now, so each column will fill the whole width.

Then we state grid-template-rows: auto;. This is actually the default value, so we could have omitted it, and means that the row heights will be determined purely by the content.

Lastly we define a grid-gap of 20px, which gives us our column and row gutters.

Media Query Numero Uno

On wider viewports (500px is completely arbitrary), we’ll change the grid-template-columns to give us a possible two cards per row. Now there are two columns, each being one of the available two fractions.

Media Query Numero Dos

Lastly, for larger screens we’ll go with a four column layout.

Here we could equally have written repeat(4, 1fr) instead of 1fr 1fr 1fr 1fr. For more information on how the fr unit works, check out CSS Grid Layout: Fluid Columns and Better Gutters.

So what has that given us?

Styling the Cards

That’s given us a pretty solid grid layout, and if you’re a fan of brutalism you may want to keep things like this, but for everyone else let’s make our cards look a little more like cards.

This gives us some basic styles: a white background, no underline for the text, a gray color, and a neat box-shadow to give us some depth.

Next we declare the card to be display: flex;. This is important–we’ll be aligning the contents of the card vertically, using Flexbox. Therefore we also state flex-direction: column; to give us our vertical axis. Lastly we declare min-height: 100%; in order that all the cards fill the height of the parent (our grid item). Good work! That gives us this:

Hover State

Let’s make a couple of other improvements before diving further into Flexbox. Add a position: relative; and a transition so that we can move the card on hover:

Then on the hover, lift the card slightly and make the shadow more pronounced:

Typography

Now we’ll add some general styles to the typography to alter the colors and the spacing.

Here’s what you should have:

Thumbnails

Each thumbnail will be applied as a background image, so we’ll add some markup across the board, like this:

Now we’ll make sure the .thumb divs have some dimensions, and that the background images fill them properly:

Good job, that gives us this:

Flexbox Article

Now we want the author name to be aligned at the bottom of the card, irrespective of how much content there is above it. This is where Flexbox again comes in:

We’re using the shorthand flex: 1; to state that this flex item (it’s still a child of the original flex container) should grow to take up all the available space.

Then, we declare that the article is a flex container in its own right, and again we’re declaring flex-direction: column; to give us vertical distribution. Lastly, justify-content: space-between; states that all the flex items within it should be spread evenly along the axis, with equal spacing between.

That’s all great, but it gives us these strange, wandering paragraphs in the middle of our cards.

To align these properly, let’s add flex-grow: 1; (or simply flex: 1;) to them, so they fill all the remaining vertical space, aligning themselves nicely to the top.

Better!

Altering the CSS Grid

At this point we’re pretty much wrapped up, but the one thing Grid allows us to do now is completely change the layout by placing our grid items wherever we like, and at whatever size we like. For this demo, we wanted to make the very first card (let’s call it our “featured card”) two columns wide for anything other than the smallest viewports.

In our first media query, let’s do this:

Harking back to our introductory tutorial on grid areas, here we’re saying that, beyond 500px, the first item should begin on grid line 1 and span across two tracks. The rest of the grid items fall into place automatically.

Within this same media query I’ve also bumped the font-size of the heading in our featured card.

Conclusion

This has been a solid CSS Grid and Flexbox tutorial; Grid handled our main two-dimensional layout, then Flexbox handled the vertical distribution of elements within our cards. Have fun playing around with it!