How to build a Mobile App Layout with CSS Flexbox

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.

Getting started

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.

Style the phone screen

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).

Style the application header

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;
}

Style the main content area

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;
}

Style the library categories

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.

Style the recently played section

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

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.

Wrap up

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!