CSS Grid - Cards Layout & Aspect Ratio

prvnbist

Praveen Bisht

Posted on December 30, 2019

CSS Grid - Cards Layout & Aspect Ratio

Card-based layouts have been around in web design for longer than you may think and grown in popularity over the years. A lot of platforms have been using card based layouts for years now. Cue meme

Alt Text

There are many ways to implement card based layouts using flexbox, css grid or good ol' float☠. But we'll be using CSS Grid to make your life easy as a front-end developer.

Markup

Let's use un-ordered list for our card based layout but you can also use div as well.

<ul>
   <li></li>
   <li></li>
   <li></li>
   <li></li>
   <li></li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Styles

Our goal is to make a layout that is structured in a grid of cards. Let's introduce CSS Grid to the mix. We'll have to define container ul as grid based container to do that we'll be adding the display property to it and setting it to the value of grid.

ul {
   display: grid;
}
Enter fullscreen mode Exit fullscreen mode

With CSS Grid you can set how many columns you want in the layout using property grid-template-columns.

ul {
  grid-template-columns: 1fr 1fr 1fr;
}
Enter fullscreen mode Exit fullscreen mode

This will create a 3 column layout, here fr represents a fraction of the total width the container spans. We can also use values in px, em, rem and percentages instead of fr. We set each column to 1fr and repeating it 3 times creates 3 columns for us but in case where you want to build equal width column layouts you can use repeat() to avoid repeating yourself😉

ul {
  grid-template-columns: repeat(3, 1fr);
}
Enter fullscreen mode Exit fullscreen mode

Replace the first argument that repeat takes with number of columns you want. Second argument is the width each column will have. Now let's introduce some gutter in case you want some. To do that we can use grid-gap property.

ul {
  grid-gap: 16px;
}
Enter fullscreen mode Exit fullscreen mode

This will add gutters of 16px wide to both columns and rows. To set different gutter to columns and rows you can either use grid-row-gap and grid-column-gap or set grid-gap to <grid-row-gap> <grid-column-gap> to assign different gutter sizes.

ul {
  grid-gap: 16px 12px;
}
Enter fullscreen mode Exit fullscreen mode

or

ul {
  grid-row-gap: 16px;
  grid-column-gap: 12px;
}
Enter fullscreen mode Exit fullscreen mode

But what if you want the layout to have as many number of columns that can fit the window and wrap on browser resize?

Let's welcome auto-fill and auto-fit to the game.

What's auto-fill?

Alt Text

auto-fill will simply fill the row with as many cards it can and will create empty columns if the number of cards are less than the number of columns.

ul {
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr);
}
Enter fullscreen mode Exit fullscreen mode

minmax() takes two arguments -

  1. First - Minimum Width
  2. Second - Maximum Width

The cards will expand as much as maximum width they have in a row until the space for new card becomes available in the row.

What's auto-fit

Alt Text

auto-fit will fill the row with as many cards as it can fit with maximum width. If a row has space to fill 10 cards of maximum width of 100px, it will fit all of them and the cards will wrap to new row if the row doesn't have space to fit a card with it's minimum width.

For more detailed difference between auto-fill and auto-fit refer to this article by @SaraSoueidan

Now for the purpose of this articles we'll be using auto-fill. With this included our css for the container has following properties.

ul {
  display: grid;
  grid-gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr);
}
Enter fullscreen mode Exit fullscreen mode

Now let's style our cards a bit. We'll begin by adding background color to the body tag and some padding too.

body {
  padding: 16px; 
  background: #19191C;
}
Enter fullscreen mode Exit fullscreen mode

For our cards represented by li tags, let's style 'em.

li {
  height: 240px;
  background: #303035;
  border-radius: 8px;
}
Enter fullscreen mode Exit fullscreen mode

Our layout so far look's like this.

Alt Text

Aspect Ratio

On some screens the layout might look good with fixed height but as the screen size increases or for wide devices the cards will stretch horizontally but the height will be not. To avoid this we can setup aspect ratio for our cards that'll keep them in same ratio no matter how wide or how small a screen is. Now to simulate aspect ratio on our cards we can set the height property to auto or simply remove it.

We'll be using padding-top or padding-bottom to simulate a particular aspect ratio. Below are the values that we can use to achieve different aspect ratios.

  1. 1:1 - 100%
  2. 16:9 - 56.25%
  3. 4:3 - 75%
  4. 3:2 - 66.66%
  5. 8:5 - 62.5%

Let's make our cards fit to 16:9 ratio.

li {
  padding-top: 56.25%;
  background: #303035;
  border-radius: 8px;
}
Enter fullscreen mode Exit fullscreen mode

With this added we'll have our cards at 16:9 ratio no matter the size of the screen. But any content within the cards would now have been pushed down by the padding we added. To solve this we can wrap the content of the cards into a container and set it to position: absolute. With this we can position our content at the top of the card.

li {
  padding-top: 56.25%;
  background: #303035;
  border-radius: 8px;
  position: relative;
}

li > img {
  position: absolute;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

All styles together

body {
  padding: 16px; 
  background: #19191C;
}

ul {
  display: grid;
  grid-gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr);
}

li {
  padding-top: 56.25%;
  background: #303035;
  border-radius: 8px;
  position: relative;
}

li > img {
  position: absolute;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

CSS Grid pretty much handles the responsive part for us which I see as absolute win but since we set minimum width for our cards to 320px which means if the window's size is less than that the cards will overflow. So we'll have to use media queries nonetheless🤦🏼‍♂️

@media screen and (max-width: 320px) {
   ul {
      grid-template-columns: repeat(auto-fill, minmax(100%, 1fr));
   }
}
Enter fullscreen mode Exit fullscreen mode

Codepen

💖 💪 🙅 🚩
prvnbist
Praveen Bisht

Posted on December 30, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related