With a spoonful of flexbox

Flexbox is a smart layout module which offers a more efficient way of laying out items in a given space. One of the key strengths is it's ability to calculate space. The idea is that a container item can change the order, width and height of its' direct children based on the space inside that container. It gives us a whole new level of control over alignment, sizing and ordering.

I've been super excited to see what all the fuss is about, so I have added flexbox to the simple header on this website. This also gave me a nice introduction to how it all works. Here is how I did it.

/*Flexbox layouts on header and nav*/
.header, .nav {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}
@media all and (min-width: 30em) {
   .header, .nav {
       flex-direction: row;
  }
}

First let's look at the display:flex; value as this was my starting point. This needs to be declared on the containing item, which as a result makes it's direct children flex items.

Flexbox axis
A diagram of a flex container and flex items showing some possible sizes and directions. From the W3C specification for flexbox.

The diagram shows a flex container with two flex items inside it. As you can see there are two axes: the main axis and the cross axis. Using the flex-direction property we can specify which axis the flex items will follow. Flex-direction can also influence where the start and end points are.

flex-direction

The flex-direction property establishes the main axis on the flex container, determining which direction flex items are laid out. There are four values for this property:

  • row: left to right (default)
  • row-reverse: right to left (same as row but reverse)
  • column: top to bottom
  • column-reverse: bottom to top (same as column but reverse)

My example uses flex-direction:column; until the screen width is 30em. This means that the flex items follow the cross axis from top to bottom on screen sizes below 30em. Once a screen size goes over 30em the layout changes and it uses the main axis, as specified by the row value.

Justify-content

If there is extra space left in the flex container when either all flex items have reached their maximum size, or they are inflexible, the justify-content property will distribute the space.

I used justify-content: space-between; because this makes the first item (the title) align to the left and the last item (the navigation) align to the right. There are five values that we can use to define the alignment of items on the axis.

Justify-content values
A diagram of the justify-content values. From the W3C specification for flexbox.
  • flex-start: flex items are aligned from the start of the axis (default).
  • flex-end: flex items are aligned from the end of the axis.
  • center: flex items are aligned in the centre of the axis.
  • space-between: the first and last items are pinned to the start and end of the axis (on both edges of the container), then every item in between is given an equal amount of space.
  • space-around: flex items get equal space around them because the container calculates space from the centre working outwards. This means that the items at the start and the end of the axis also get spacing. Visually the container doesn't look equal because the spacing between the first/last items and the container edges are half the size of the space between items. This is because the items against the edges do not have neighbouring items, so they only have one unit of space.

A good use case for the space-around value is a full-width nav bar. In the past I have tried using display: table-cell; which can calculate equal widths of links, but not equal spacing between links. Flexbox's justify-content: space-around; will align the first and last items to each end of the container and then equally space out each link.

While this example is a very simple introduction to flexbox, it quickly became clear how little CSS I actually had to write. Using flex properties feels easier and simpler than using floats, inline-block or table-cell values like I have done so far.

Can we use flexbox?

It has been suggested that we can't use flexbox yet, but actually we can. It is stable and supported enough to use on small page components as progressive enhancements. When we check the browser support on Can I use, we can see that flexbox is supported in IE11 (partial support for IE10) and above, and across all other browsers. Of course for IE9/10 and below the fallback route would need to be taken. It is also worth noting that flexbox has been a candidate recommendation since September 2012, which means that the flexbox syntax we use today should stick around in the future. All of this is great to see and it feels like a good time to be learning this.

I added flexbox as an enhancement to this site's header, so the original (rather basic) code remains as a fallback for unsupported browsers. The layout is very simple and slightly different but it works just fine, allowing me to take advantage of the advanced alignment properties in flexbox. The fallback version looks like this in a browser:


Here is the CSS with the fallback styles. I have also added the vendor prefixes stated on Can I use for browser support.

/*Fallback styles*/
@media all and (min-width: 30em) {
    .nav {
        text-align: center;
    }
    .nav-item {
        display: inline-block;
    }
}
/*Flexbox layouts on header and nav*/
.header, .nav {
    display: flex;
    display: -webkit-flex;
    display: -ms-flexbox; 
    flex-direction: column;
    -webkit-flex-direction: column; 
    -ms-flex-direction: column; 
    justify-content: space-between;
    -webkit-justify-content: space-between;
    -ms-justify-content: space-between;
}
@media all and (min-width: 30em) {
    .header, .nav {
        flex-direction: row;
        -webkit-flex-direction: row; 
        -ms-flex-direction: row;
    }
}

And there's more. Many more powerful and useful properties exist. Examples include flex-grow, flex-shrink and flex-basis which can be used to specify the size and proportion of space taken up by flex items. I will be experimenting with these for my next post on flexbox.

Tags: