Andrei Pfeiffer logo
Back to Articles

Definition lists with grid layout

CSS
5 min read

In this post, we'll examine various implementations for the layout displayed below, using both flex and grid, debating the robustness of each approach. The layout is a simple horizontal list of 3 key-value pairs, the values being displayed beneath the labels.


Posts123
Followers456
Likes7890
3 key-value pairs implemented with a flex layout

TL;DR: in our final approach, we'll use Definition Lists with grid-auto-flow: column. You can skip to the final implementation if you don't want to follow the step by step guide.

Using a flex layout approach

One approach to this layout is having the 3 key-value groups displayed in a flex container. To make this happen, we'll have to wrap each group in an additional element:



index.htmlHTML
<div class="container">
  <div class="group">
    <span class="label">Posts</span>
    <span class="value">123</span>
  </div>

  <div class="group">
    <span class="label">Followers</span>
    <span class="value">456</span>
  </div>

  <div class="group">
    <span class="label">Likes</span>
    <span class="value">9999</span>
  </div>
</div>
style.cssCSS
.container {
  display: flex;
}

.group {
  flex: 1;
  text-align: center;
}

This approach works, the content is displayed as needed. However, it has an important flaw, because the markup doesn't say anything about the semantics of the content.

Whenever we have span or div elements, we should ask ourselves if we can replace them with other, more semantic elements, that can describe the content better.

Let's look at various ways to improve our content sematics.

Using an Unordered List

One way to improve the semantics, is replacing the non-semantic div elements with an Unordered List. This way, we can think of the content as:

A list of 3 key-value pairs

index.htmlHTML
<ul class="container">
  <li class="group">
    <span class="label">Posts</span>
    <span class="value">123</span>
  </li>

  <li class="group">
    <span class="label">Followers</span>
    <span class="value">456</span>
  </li>

  <li class="group">
    <span class="label">Likes</span>
    <span class="value">9999</span>
  </li>
</ul>
style.cssCSS
.container {
  list-style-type: none;
  margin: 0;
  padding: 0;

  display: flex;
}

.group {
  flex: 1;
  text-align: center;
}

The changes to our code are minor:

  • we've replaced the outer div.container with an ul element;
  • we've replaced the div.group with li elements;
  • we've removed the default ul CSS styling.

However, we still have the span elements wrapping our actual content, which don't offer any semantics. So, let's go a step forward, by switching to a Definition List.

Using a Definition List

Whenever we have to deal with any kind of key-value pairs, we should consider using a Definition List. This way, we can think of our content as:

A definition list of 3 terms

index.htmlHTML
<dl class="container">
  <div class="group">
    <dt class="label">Posts</dt>
    <dd class="value">123</dd>
  </div>

  <div class="group">
    <dt class="label">Followers</dt>
    <dd class="value">456</dd>
  </div>

  <div class="group">
    <dt class="label">Likes</dt>
    <dd class="value">9999</dd>
  </div>
</dl>
style.cssCSS
.container {
  display: flex;
}

.group {
  flex: 1;
  text-align: center;
}

.value {
  margin: 0;
}

Let's go through the code changes:

  • we've replaced the ul.container with an dl element;
  • we've replaced the span.label elements with dt to make them the definition terms;
  • we've replaced the span.value elements with dd to make them the definition descriptions;
  • we've remove the default margin for dd.

This is much better, because our markup describes better the content it provides.

However, we still have some extra div elements, which are annoying, but necessary, considering our flex layout approach. Let's see if we can eliminate those extra div elements with a grid layout.

Using a grid layout approach

Using flex is fine, it gets the job done. But I think we can do better. Instead of thinking of our layout as 3 key-value pairs we can think of it as:

A grid of 2 rows and 3 columns

Using this perspective allows us to get rid of the extra div elements, because CSS Grids can control both the horizontal and the vertical, so we don't need additional wrappers to group our content.



index.htmlHTML
<dl class="container">
  <dt class="label">Posts</dt>
  <dd class="value">123</dd>

  <dt class="label">Followers</dt>
  <dd class="value">456</dd>

  <dt class="label">Likes</dt>
  <dd class="value">9999</dd>
</dl>
style.cssCSS
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  justify-items: center;
}

/*.group {
  flex: 1;
  text-align: center;
}*/

.value {
  margin: 0;
}

The problem is that the grid cells are not displayed as we would expect, because they are distributed by rows, using the order from the markup.

This happens because the grid-auto-flow property is set to row by default.


Posts
123
Followers
456
Likes
7890
Using a grid layout with the default "grid-auto-flow: row" breaks the visual appearance

However, we can control the flow of the cells by settings grid-auto-flow's value' to column:

.container {
  display: grid;
  /* grid-template-columns: 1fr 1fr 1fr; */
  grid-template-rows: auto auto;
  grid-auto-flow: column;
  justify-items: center;
}

This way, the cells will be distributed by columns:

  • they will fill the entire first column;
  • a new column will be added for the 3rd and 5th element, because we've only defined 2 rows with grid-template-rows.
ImportantIt's mandatory to define the grid-template-rows in this case, to tell the grid that "we need to have 2 rows", otherwise it will fit all the cells on 1 row only, by default.

Posts
123
Followers
456
Likes
7890
Using "grid-auto-flow: column" fixes the visual appearance

Final implementation

Below you can see the final implementation:

  • the markup is clean and concise;
  • all HTML elements are semantic and describe the content perfectly;
  • we don't need any extra elements to aid our styling;
  • the labels and values can be aligned independently in case we need to, which gives a higher flexibility compared to a flex layout.


index.htmlHTML
<dl class="container">
  <dt class="label">Posts</dt>
  <dd class="value">123</dd>

  <dt class="label">Followers</dt>
  <dd class="value">456</dd>

  <dt class="label">Likes</dt>
  <dd class="value">9999</dd>
</dl>
style.cssCSS
.container {
  display: grid;
  grid-template-rows: auto auto;
  justify-items: center;
  grid-auto-flow: column;
}

.value {
  margin: 0;
}