How to build a responsive feature list with CSS Flexbox

In this tutorial, you will learn how to build a common component on product landing pages. Have you seen marketing pages that display feature images and their descriptions in alternating order? Flexbox makes this pattern really easy to build out, and no, you don’t have to change the HTML in order to achieve this.

The feature list on alfredapp.com
camera The feature list on alfredapp.com (Large preview)

The particular feature list we’ll be building is the one found on alfredapp.com. If you inspect the elements on that site via your browser’s DevTools, you will see that the layout was achieved using floats. I’ll show you how to achieve the exact same layout with Flexbox and how to make it responsive too!

Getting started

You can grab the starter code from Jsfiddle and copy it to your local text editor, or click the Fork button to fork it into a new fiddle.

If you look at the HTML pane, you will see that each feature is enclosed in a div element with a class of feature, and within it is contained the image and its description.

In the CSS pane, we have all the styles we need minus the Flexbox bits. That’s what we’re going to cover in the sections below.

Make each feature a flex container

The first thing we need to do is make each feature a flex container. We can do this by setting display: flex on the .feature selector.

.feature {
  padding-top: 30px;
  padding-bottom: 30px;
  display: flex;
}
Image and text are place flush against each other across the main axis on setting display: flex on each feature
camera (Large preview)

This causes the image and text to be placed flush against each other along the main axis. There is no space to distribute along the main axis since the images fill up all the available space, and the text is squished together in an unsightly manner.

We can give the images and text a consistent width using the width property as shown below:

.feature-image {
  width: 55%;
}

.feature-description {
  width: 40%;
}
Image now takes 55% of the space while text takes 40% of the space
camera (Large preview)

Now, the text takes up 40% of the space along the main-axis while the image takes 55% of space. This leaves 5% space which is placed at the end since the default value of justify-content on a flex container is flex-start. We can put this space between the flex items with justify-content: space-between;

.feature {
  padding-top: 30px;
  padding-bottom: 30px;
  display: flex;
  justify-content: space-between;
}

The remaining 5% space is now between the flex items. Notice that the images are really stretched out at this point. Normally, when you give an image a width or a height in CSS, the browser resizes the image so that it maintains its aspect ratio.

In this case though, the aspect ratio is ignored and the image is stretched to its full height despite the fact that we set a width of 55% on it in the CSS. The property controlling this behaviour is align-items whose default value is stretch.

We can make the browser respect the aspect ratio of the image once again by setting align-items to flex-start. Instead of stretching the flex items, they will be flushed against the start edge of the cross axis.

.feature {
  padding-top: 30px;
  padding-bottom: 30px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}
Images are no longer stretched to their full height but resized to maintain the aspect ratio
camera (Large preview)

The next thing to do is to reverse the order of the flex items in the second and fouth feature list items so that the images come before the text. We can achieve that without changing our markup in any way. Notice that the second and fourth features have a class of reverse applied to them, so we can affect each one using the .reverse selector.

To reverse the arrangement of the flex items, we need to use the flex-direction property on the flex container. Its default value is row which makes the main axis go in the direction of the text (left to right in English language).

Other valid values for the flex-direction property are:

  • row-reverse: main axis goes from right to left.
  • column: main axis goes in the block direction, from top to bottom.
  • column-reverse: main axis goes from bottom to top.

If we set the value of flex-direction to row-reverse, the direction of the main axis is reversed. This gives the effect of changing the order of the flex items, but really, it’s only the direction of the main axis that changed.

.reverse {
  flex-direction: row-reverse;
}
The direction of the main axis is reversed when flex-direction is set to row-reverse
camera (Large preview)

Now the feature list looks identical to what we set out to achieve, at least on the desktop view. On mobile, it doesn’t look too good yet.

Fix mobile responsiveness

You can use the Ctrl+Shift+M shortcut in Firefox or Ctrl+Shift+I followed by Ctrl+Shift+M in Chrome to see how it currently looks on a mobile screen.

We need to make sure the image and text take the full width of the viewport and that the image sits above the text.

Let’s make the image sit on top of the text first. We can do this by changing the value of flex-direction to column-reverse. This makes the main axis go from bottom to top instead of left to right.

@media screen and (max-width: 750px) {
  .feature {
    flex-direction: column-reverse;
  }
}

The images now sit atop the text, but they do not take the full width of the container. This is due to the width which we set on each flex item earlier. We can easily change the width property of both the image and text to 100% so that they take the full width of the viewport.

@media screen and (max-width: 750px) {
  .feature {
    flex-direction: column-reverse;
  }

  .feature-image {
    width: 100%;
  }

  .feature-description {
    width: 100%;
  }
}

Everything looks great! We’ve been able to achieve a responsive feature list using only a handful of Flexbox properties.

Wrap up

In this article, we’ve looked at how to use Flexbox to make a responsive feature list. If you want to practice on your own, find other websites that implement a feature list in the manner of the one we just built and try to recreate it.

In the next tutorial, I’ll cover some of the lesser understood Flexbox properties including flex-grow, flex-shrink and flex-basis, and I’ll show you how to use them to build another real world component. Till next time!