Marc Denning

Introduction to Flexbox

This blog post is also published on the Cardinal Solutions Blog.

There are plenty of good resources on flexbox in the community already, but I would like to provide my own take on this newer CSS feature. I will not cover all of the features available in flexbox, but instead walk through some of the basic properties, provide some practical examples that I have come across in my own work, and finally leave you with a few tips, tricks, and links to help make working with flexbox a little bit easier.

Background

CSS layout has been a challenge for a long time. Early on, if you wanted much beyond a vertical column of elements, you had to use tables. When the web standards movement came along, tables were thrown out and several grid systems based on the float or display: inline-block property appeared. Websites have been using some variant of these layout techniques for over a decade, and while they work, they leave much to be desired.

Flexbox emerged a few years ago to provide alternative layout schemes for all sorts of different design patterns. As a layout technology, flexbox is not perfect or a silver bullet for all web design problems, but it provides a significant step forward in what we can build on the web.

The Basics

Flexbox is based around the concept of arranging elements on a main axis and then a cross axis. Secondary to this, the elements arranged on the main axis can have a "flexible" dimension along the axis computed dynamically by the browser. No more JavaScript window resize handlers necessary!

To begin a flexbox layout, we start with a parent element with display: flex:

<div class="flex-container"></div>
.flex-container {
  display: flex;
}

This tells the browser that the immediate children of this element should be laid out using the flexbox rules. Next, we configure the orientation of the main axis with the flex-direction property:

.flex-container {
  display: flex;
  flex-direction: row;
}

The direction of row says that the main axis is horizontal and child elements are laid out from left-to-right (or right-to-left if you specify row-reverse). Using column says that the main axis is vertical and the child elements stack from top-to-bottom (or bottom-to-top if you specify column-reverse).

Main and cross axes diagram for row orientation
Diagram of axes for row orientation
Main and cross axes diagram for column orientation
Diagram of axes for column orientation

The flex-wrap property allows us to configure what happens when child elements fill the parent container. By default, this property is set to nowrap which tells the browser to try to fit all children onto the same line. If the sum of the children's dimensions are too big, they may overflow their parent container.

.flex-container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
}

Other available values for flex-wrap include wrap and wrap-reverse. When the minimum dimensions of the child elements exceed the parent's dimensions, these values allow child elements to flow onto the next line from left-to-right or right-to-left, respectively.

The last property we will go over here is justify-content. This property aligns the child elements along the main axis and distributes leftover space after the children's maximum dimensions have been reached. The default value of flex-start tells the browser to lay out child elements at the start of the main axis and let all extra space fall at the end:

.flex-container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: flex-start;
}

Other options for justify-content include flex-end, center, space-between, and space-around. The value flex-end functions opposite of flex-start by laying out child elements from the end of the main axis and leaving all extra space at the start. We will explore the values center and space-between later on.

Note: The values we used for flex-direction, flex-wrap, and justify-content so far are the browser defaults, but we will keep them as a reminder of what those values are.

Next, we add some children to our .flex-container and define some base padding and a border so we can see the elements' boundaries better:

See the Pen Basics - Part 1 by Marc Denning (@kenobi883) on CodePen.

There are two main properties set on child elements: flex and order. The flex property is a shorthand property for flex-grow, flex-shrink, and flex-basis. While each of those can be set individually, using the shorthand is more common and recommended because it will apply intelligent defaults to the remaining properties. If we look at our output before applying these rules to the child elements, we should see three boxes stuck together, just big enough for their content, aligned to the left.

Notice that we don't use float: left, display: inline-block, or any of the old tricks! By defining a container with display: flex, we have horizontally-aligned children. If we add one rule to our .flex-child definition, we can see even more of flexbox in action:

See the Pen Basics - Part 1 by Marc Denning (@kenobi883) on CodePen.

Now, each child element takes up equal width across the .flex-container. Setting flex: 1 sets the underlying flex-grow property to 1. The flex-grow property is a unitless value (we do not use px or em here). This tells the browser that each element should expand to fill the space available in our .flex-container element proportionately to one another.

Note: Since we only specified one value for the flex shorthand property, the other properties flex-shrink and flex-basis are set to 0 and auto respectively. Like flex-grow, flex-shrink instructs the browser to determine how wide the element should be, but it does so by allowing the element to shrink rather than expand. The flex-basis property provides a default width (or height if using flex-direction: column) from which to shrink or expand. You should only set either flex-grow or flex-shrink to a non-zero value, not both.

If we set the value of flex to 2 for one of our child elements, that element now takes double the amount of space available in the container relative to the remaining elements equally share the leftover space:

See the Pen Basics - Part 2 by Marc Denning (@kenobi883) on CodePen.

The final property to explore is order. The order property allows us to visually re-order child elements. For instance, we could have "Child 3" appear first:

See the Pen Intro to Flexbox by Marc Denning (@kenobi883) on CodePen.

The key here is that the source order of elements in the DOM has not changed. Only what appears visually on the page.

There are other properties and options to cover within the flexbox specification, but this gives us enough to get going. Now, let's look at some practical uses of these properties!

Practical Examples

Application Menu Bar

See the Pen Flexbox Examples - Application Menu Bar by Marc Denning (@kenobi883) on CodePen.

The application menu bar is an example of using the order property. The components displayed are common requirements for a web application: a title, a menu button, and a search bar. Note that in the example, these components are in the DOM in one order, but visually displayed in a different order! For accessibility or SEO reasons, you may want to ensure that while your app's title is in the center of the menu bar, it comes first in the source order of the DOM. Flexbox makes this easy.

See the Pen Flexbox Examples - Sidebar Layout by Marc Denning (@kenobi883) on CodePen.

The side bar layout example once again shows how flex and order properties may be used to provide a content-first, responsive layout. Note that our main content is first in source order and is at the top of the page on smaller screens, but shows up in the middle of the page on wider screens. Change the flex-direction from column on smaller screens to row on wider screens and adjusting the width and order properties, to get a functional layout at both dimensions.

See the Pen Flexbox Examples - Fixed Footer by Marc Denning (@kenobi883) on CodePen.

The fixed footer is one of my current favorites for showing off a neat application of flexbox. You may need to open this example in another window to appreciate the effect. When you adjust the height of the window, notice that when the window is shorter, you can scroll the page as usual and observe the different regions in their static height, but as the window gets taller, the footer stays fixed to the bottom of the window!

There are a few keys to making this work: starting from the body, the container elements should have a height of 100%, flex-direction is set to column and the main content area has flex set to 1 0 auto. This allows the main area to grow in height from its static height but not shrink. This technique is certainly useful for websites where page content may be short on some pages and longer on others, but it is also quite helpful in creating responsive application layouts where some elements have static dimensions, but a primary workspace area should take the rest of the available window space.

Tips & Tricks

Resources