No Time Dad

A blog about web development written by a busy dad

Simple Stat Cards Using CSS Grid

Intro

Cards are a great way to show data to a user in an easy to read format. Most cards you’ll see have a box-shadow applied so they pop out a bit more from the page. I also think that cards can be wildly overdone and confuse users. The key is to find the middle ground where your card looks nice but doesn’t overwhelm the page. That is exactly what I will try to do with the card example here. Simple and to the point while still looking good.

Below is a demonstration of what the stat cards will look like.

Clicks
2,398
Impressions
62,156
CTR
3.9%

Getting started

Our stat cards will contsist of a parent container, a grid container, and the card elements themselves. The parent container is the top level div. In this div we will set the background-color to a light grey, which is a subtle way to make the cards stand out a bit more. We’ll also be adding some padding in the parent container so the spacing is even when the stat cards are next to other elements on a page. The grid container is where we will define our grid. We’ll also define how many columns our grid will have, and the gap around our columns. Lastly, the cards themselves will have a title and a number. We want the number to catch the user’s eye so it will have a large font size.

Taking a mobile first approach, the grid will have a single column on small screens (less than 768px) and three columns on larger screens (at least 768px or larger). You could add a fourth card and go to 2 columns by 2 rows around 460px screen width, but I am not sure how many devices really fall into that screen size range. Plus I think four columns is heading into cluttered screen territory for most dashboards. Especially if your users are on mobile. As the saying goes, sometimes less is more.

Basic structure

Below is the basic structure of the parent container, the grid container, and the cards themselves. As you can see, they aren’t really too complicated. In fact, once you have this basic structure, as shown below, you really just need to add the content. Beneath the code is an example of how the cards look so far. If you were to view this blog post on a small screen you’d see that the cards switch to a single column and back to 3 columns on larger screens.

<div class="Container">
  <div class="Grid__Container">
    <div class="Stat__Card">...</div>
    <div class="Stat__Card">...</div>
    <div class="Stat__Card">...</div>
  </div>
</div>
.Container {
  /* Light grey background to help focus on the cards */
  background-color: rgb(238, 238, 238);
  /* Extra spacing so the grid looks uniform on the page */
  padding: 1rem;
  border-radius: 0.5rem;
}

.Grid__Container {
  /* Initialize the grid */
  display: grid;
  /* Single column on small screens */
  grid-template-columns: repeat(1, 1fr);
  gap: 10px;
}

.Stat__Card {
  padding: 1rem;
  background-color: white;
  /* Subtle box-shadow that defines the shape of the card */
  box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.15);
  border-radius: 0.5rem;
}

@media (min-width: 768px) {
  .Grid__Container {
    /* Switch to 3 columns on larger screens */
    grid-template-columns: repeat(3, 1fr);
  }
}
Card 1
Card 2
Card 3
Adding content

The structure of the card is a container with two child sibling elements. One child element is for the title and the other child element is for the content (or numbers). We want the title to be readable but not as large as the number. Draw the user to the number first. The number is what matters most to them.

The card itself will use flexbox for alignment. Flexbox defaults to flex-direction: row; but in our case we want the content to be under the title so we’ll use flex-direction: column;. Below is the basic structure of the single card element and its corresponding css.

<div class="Stat__Card">
  <div class="Stat__Container">
    <div class="Stat__Title">...</div>
    <div class="Stat__Content">...</div>
  </div>
</div>
.Stat__Container {
  /* Initialize flexbox */
  display: flex;
  /* We want the title to be over the content */
  flex-direction: column;
}

.Stat__Title {
  /* Dark grey color for the title text */
  color: #6c757d;
}

.Stat__Content {
  /* More prominent text for the numbers */
  font-size: 32px;
  font-weight: 700;
}

Thoughts & final code

The cards are indeed pretty simple. Which also makes them a great starting point to build on. You might consider adding arrows to show which direction the data is trending, or svg icons to add more flair to the card. But I really wouldn’t go much further than that. I think it is a bad idea to overwhelm cards with too much stuff. It detracts from the purpose of the card, which is to display the data. Your users might actually thank you for getting to the point and giving them the data they were looking for.

.Container {
  background-color: rgb(238, 238, 238);
  padding: 1rem;
  border-radius: 0.5rem;
}

.Grid__Container {
  display: grid;
  grid-template-columns: repeat(1, 1fr);
  gap: 10px;
}

.Stat__Card {
  padding: 1rem;
  background-color: white;
  border-radius: 0.5rem;
  box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.15);
}

.Stat__Container {
  display: flex;
  flex-direction: column;
}

.Stat__Title {
  color: #6c757d;
}

.Stat__Content {
  font-size: 32px;
  font-weight: 700;
}


@media (min-width: 768px) {
  .Grid__Container {
    grid-template-columns: repeat(3, 1fr);
  }
}
<div class="Grid__Container">
  <div class="Stat__Card">
    <div class="Stat__Container">
      <div class="Stat__Title">Clicks</div>
      <div class="Stat__Content">2,398</div>
    </div>
  </div>
  <div class="Stat__Card">
    <div class="Stat__Container">
      <div class="Stat__Title">Impressions</div>
      <div class="Stat__Content">62,156</div>
    </div>
  </div>
  <div class="Stat__Card">
    <div class="Stat__Container">
      <div class="Stat__Title">CTR</div>
      <div class="Stat__Content">3.9%</div>
    </div>
  </div>
</div>
Clicks
2,398
Impressions
62,156
CTR
3.9%