How to build a responsive feature list with CSS Flexbox
Learn how to use the Flexbox layout model to recreate a real-world product feature list
I’ve described how to build a few web components with Flexbox here, here and here. Let’s kick things up a notch by building a full mobile app layout with Flexbox.
I’ll show you some some really neat ways you can leverage the power of Flexbox in your websites and applications by recreating a layout from Spotify’s mobile app.
Here’s a live demo of what we’ll be building.
Open up this fiddle and click the Fork button to create your own instance of the fiddle.
The HTML pane contains the all the markup we need. Mostly just a bunch of divs and SVG icons. In the CSS pane, I’ve included a basic CSS reset as well some a few general styles.
The SVG icons present aren’t very visible at the moment. This is because I set the fill
property to a light color which blends in almost completely with the white background colour of the page.
Let’s move along now to writing the styles that will build up our app layout, taking advantage of the Flexbox layout model where necessary.
Add the following code below all the other rules in the CSS pane:
.phone-screen {
width: 100%;
max-width: 450px;
height: 90vh;
border: 10px solid blue;
margin: 5vh auto;
border-radius: 5px;
display: flex;
flex-direction: column;
color: #f6f6f6;
background-color: #121212;
}
.header, .content, .footer {
padding: 15px;
}
In order to emulate a phone screen, I’ve restricted the width of the layout to 450px while giving it a bright blue border to make the edges distinct. I’ve also made .phone-screen
a flex container (with display: flex
), and changed the direction of the main-axis
so that it runs in the block direction (from top to bottom).
We can achieve the header layout pretty easily with Flexbox. All we need to do is make .header
a flex container, and distribute the available space along the main axis between the flex items.
.header {
background-color: #222327;
display: flex;
justify-content: space-between;
align-items: center;
min-height: 60px;
}
.header h1 {
font-size: 24px;
}
The first thing we’ll do here is prevent the content from overflowing the phone screen. We can do this by adding the following code to the CSS pane:
.content {
overflow-y: auto;
}
Next, we can style the categories at the top like this:
.categories {
padding-left: 20px;
list-style-type: none;
font-size: 20px;
margin-bottom: 40px;
}
.categories li {
display: flex;
align-items: center;
margin-bottom: 25px;
}
.categories svg {
margin-right: 20px;
fill: #7c7d81;
}
Here, I’ve aligned each icon and text with the align-items
property so that they are centered vertically.
We can center the Recently Played heading and give it a bottom margin like this:
.recent h2 {
text-align: center;
margin-bottom: 20px;
}
Now, onto the playlists. Let’s apply a generic cover art styling, and make each playlist a flex container while distributing the available space between the flex items.
.cover {
width: 60px;
height: 60px;
background-color: peachpuff;
margin-right: 20px;
}
.playlist {
padding-left: 10px;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.playlist svg {
fill: #7c7d81;
}
.info h1 {
font-size: 20px;
}
.info p {
color: #7c7d81;
font-size: 16px;
}
Hmmm that doesn’t look quite right. The problem stems from the names of each recently played playlist. Since they vary in length, the space that is available to distribute between the flex items isn’t the same across all the playlists.
We can fix this using a Flex property that I have not mentioned before: flex-grow
. It is applied on flex items, not the flex container.
.info {
flex-grow: 1;
}
The flex-grow
property determines how much of the available space in a flex container should be assigned to a flex item relative to the growth factor of the other flex items in the container. Its default value is 0
which means flex items do not grow beyond their intrinsinc or explicit width, if any.
However, if flex-grow
is set to a numerical value greater than 0
, that flex item will grow in size if there is available space in the flex container after all the flex items have been laid out.
Let’s consider a few examples to really understand how flex-grow
works.
Consider the two boxes below. They are both flex items and have a width of 100px
each. As you can see, there is plenty of space in the flex container that can be used somehow.
We could, for example, place that space between the flex items using justify-content: space-between
. Or we could make one of the flex items grow to fill up the remaining space with flex-grow
. Let’s do just that for .item2
:
Applying flex-grow: 1
to .item2
causes it to swallow up all the available space and grow in size. Remember that flex-grow
for .item1
is still set to 0
(by default). So it remains 100px
in width.
What happens if we give .item1
a flex-grow
value of 1
as well? Let’s see:
Now, both flex items grow at the same rate. The available space is divided equally amongst them and, since they were the same width to begin with (100px
), the result is they are the same size after growing.
Let’s consider what happens if flex-grow
is set to 2
on one of the items:
Here, .item1
grows at twice the rate as .item2
. Basically, the available space is divided in the ratio 2:1 and shared amongst the flex items as appropriate. The same thing happens if you set the value of flex-grow
to some other value. The available space will be distributed according to the ratio defined by the different flex grow factors.
Let’s head back to our app layout. Since the flex-grow
property of the other flex items in .playlist
is set to 0
, this causes the whole space left in each container to be appended to .info
causing it to be the same size across all the playlists.
The styling of the Recently Played section is now complete and we can move on to the footer.
Let’s add some general styles for the footer elements:
.footer {
background-color: #222327;
}
.footer-nav {
padding-top: 10px;
padding-bottom: 10px;
}
.song {
font-weight: 700;
}
.artist {
color: #7c7d81;
}
.nav-items svg {
width: 28px;
margin-bottom: 5px;
fill: #7c7d81;
}
.library {
color: #f7f7f7;
}
.library svg {
fill: #f7f7f7;
}
Next up, we’ll align the elements in .now-playing
properly using Flexbox.
.now-playing {
display: flex;
justify-content: space-between;
}
Looking good! Let’s wrap up by styling the navigation elements at the bottom:
.nav-items {
display: flex;
list-style-type: none;
padding-left: 50px;
padding-right: 50px;
justify-content: space-between;
color: #7c7d81;
}
.nav-items li {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
Everything looks great now. What we did in that last bit was to space the nav items evenly, and align the icon and text in each nav item. We used flex-direction: column
to ensure that the icon is on top of the text, otherwise they would have been placed flushed against each other in the inline direction.
I hope this tutorial has showed you just how useful Flexbox is to layout elements in a user interface. I expect to have more tutorials on this subject, so stay tuned. Till next time!
Comments
Ground rules
Please keep your comments relevant to the topic, and respectful. I reserve the right to delete any comments that violate this rule. Feel free to request clarification, ask questions or submit feedback.