Flexbox Is As Easy As Pie: Designing CSS Layouts

About The Author

All-rounder with a passion for the Open Web. W3C CSS WG member. Previously at Motorola and Opera. Ex-CERN, ex-Opera, ex-CSS3.info. More about David ↬

Email Newsletter

Weekly tips on front-end & UX.
Trusted by 200,000+ folks.

Flexible box layout is a new box model optimized for UI layout, and it makes a lot of tasks much easier, or even possible at all. Flexbox’s repertoire includes the simple centering of elements, the expansion and contraction of elements to fill available space, and source-code independent layout, among others abilities.

Flexbox (or flexible box layout) is a new box model optimized for UI layout. As one of the first CSS modules designed for actual layout (floats were really meant mostly for things such as wrapping text around images), it makes a lot of tasks much easier, or even possible at all. Flexbox’s repertoire includes the simple centering of elements (both horizontally and vertically), the expansion and contraction of elements to fill available space, and source-code independent layout, among others abilities.

Flexbox Is As Easy As Pie - Designing CSS Layouts

Flexbox has lived a storied existence. It started as a feature of Mozilla’s XUL, where it was used to lay out application UI, such as the toolbars in Firefox, and it has since been rewritten multiple times. The specification has only recently reached stability, and we have fairly complete support across the latest versions of the leading browsers.

There are, however, some caveats. The specification changed between the implementation in Internet Explorer (IE) and the release of IE 10, so you will need to use a slightly different syntax. Chrome currently still requires the -webkit- prefix, and Firefox and Safari are still on the much older syntax. Firefox has updated to the latest specification, but that implementation is currently behind a runtime flag until it is considered stable and bug-free enough to be turned on by default. Until then, Firefox still requires the old syntax.

When you specify that an element will use the flexbox model, its children are laid out along either the horizontal or vertical axis, depending on the direction specified. The widths of these children expand or contract to fill the available space, based on the flexible length they are assigned.

Example: Horizontal And Vertical Centering (Or The Holy Grail Of Web Design)

Being able to center an element on the page is perhaps the number one wish among Web designers — yes, probably even higher than gaining the highly prized parent selector or putting IE 6 out of its misery (OK, maybe a close second then). With flexbox, this is trivially easy. Let’s start with a basic HTML template, with a heading that we want to center.


<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="utf-8"/>
   <title>Centering an Element on the Page</title>
</head>
<body>
   <h1>OMG, I’m centered</h1>
</body>
</html>

Nothing special here, not even a wrapper div. The magic all happens in the CSS:

html {
   height: 100%;
}

body {
   display: -webkit-box;   /* OLD: Safari,  iOS, Android browser, older WebKit browsers.  */
   display: -moz-box;      /* OLD: Firefox (buggy) */
   display: -ms-flexbox;   /* MID: IE 10 */
   display: -webkit-flex;  /* NEW, Chrome 21–28, Safari 6.1+ */
   display: flex;          /* NEW: IE11, Chrome 29+, Opera 12.1+, Firefox 22+ */

   -webkit-box-align: center; -moz-box-align: center; /* OLD… */
   -ms-flex-align: center; /* You know the drill now… */
   -webkit-align-items: center;
   align-items: center;

   -webkit-box-pack: center; -moz-box-pack: center;
   -ms-flex-pack: center;
   -webkit-justify-content: center;
   justify-content: center;

   margin: 0;
   height: 100%;
   width: 100% /* needed for Firefox */
}

h1 {
   display: -webkit-box; display: -moz-box;
   display: -ms-flexbox;
   display: -webkit-flex;
   display: flex;
   -webkit-box-align: center; -moz-box-align: center;
   -ms-flex-align: center;
   -webkit-align-items: center;
   align-items: center;

   height: 10rem;
}

I’ve included all of the different prefixed versions in the CSS above, from the very oldest, which is still needed, to the modern and hopefully final syntax. This might look confusing, but the different syntaxes map fairly well to each other, and I’ve included tables at the end of this article to show the exact mappings.

This is not exactly all of the CSS needed for our example, because I’ve stripped out the extra styling that you probably already know how to use in order to save space.

Let’s look at the CSS that is needed to center the heading on the page. First, we set the html and body elements to have 100% height and remove any margins. This will make the container of our h1 take up the full height of the browser’s window. Firefox also needs a width specified on the body to force it to behave. Now, we just need to center everything.

Enabling Flexbox

Because the body element contains the heading that we want to center, we will set its display value to flex:

body {
   display: flex;
}

This switches the body element to use the flexbox layout, rather than the regular block layout. All of its children in the flow of the document (i.e. not absolutely positioned elements) will now become flex items.

The syntax used by IE 10 is display: -ms-flexbox, while older Firefox and WebKit browsers use display: -prefix-box (where prefix is either moz or webkit). You can see the tables at the end of this article to see the mappings of the various versions.

What do we gain now that our elements have been to yoga class and become all flexible? They gain untold powers: they can flex their size and position relative to the available space; they can be laid out either horizontally or vertically; and they can even achieve source-order independence. (Two holy grails in one specification? We’re doing well.)

Centering Horizontally

Next, we want to horizontally center our h1 element. No big deal, you might say; but it is somewhat easier than playing around with auto margins. We just need to tell the flexbox to center its flex items. By default, flex items are laid out horizontally, so setting the justify-content property will align the items along the main axis:

body {
   display: flex;
   justify-content: center;
}

For IE 10, the property is called flex-pack, while for older browsers it is box-pack (again, with the appropriate prefixes). The other possible values are flex-start, flex-end, space-between and space-around. These are start, end, justify and distribute, respectively, in IE 10 and the old specification (distribute is, however, not supported in the old specification). The flex-start value aligns to the left (or to the right with right-to-left text), flex-end aligns to the right, space-between evenly distributes the elements along the axis, and space-around evenly distributes along the axis, with half-sized spaces at the start and end of the line.

To explicitly set the axis that the element is aligned along, you can do this with the flex-flow property. The default is row, which will give us the same result that we’ve just achieved. To align along the vertical axis, we can use flex-flow: column. If we add this to our example, you will notice that the element is vertically centered but loses the horizontal centering. Reversing the order by appending -reverse to the row or column values is also possible (flex-flow: row-reverse or flex-flow: column-reverse), but that won’t do much in our example because we have only one item.

There are some differences here in the various versions of the specification, which are highlighted at the end of this article. Another caveat to bear in mind is that flex-flow directions are writing-mode sensitive. That is, when using writing-mode: vertical-rl to switch to vertical text layout (as used traditionally in China, Japan and Korea), flex-flow: row will align the items vertically, and column will align them horizontally.

Centering Vertically

Centering vertically is as easy as centering horizontally. We just need to use the appropriate property to align along the “cross-axis.” The what? The cross-axis is basically the axis perpendicular to the main one. So, if flex items are aligned horizontally, then the cross-axis would be vertical, and vice versa. We set this with the align-items property (flex-align in IE 10, and box-align for older browsers):

body {
   /* Remember to use the other versions for IE 10 and older browsers! */
   display: flex;
   justify-content: center;
   align-items: center;
}

This is all there is to centering elements with flexbox! We can also use the flex-start (start) and flex-end (end) values, as well as baseline and stretch. Let’s have another look at the finished example:

You might notice that the text is also center-aligned vertically inside the h1 element. This could have been done with margins or a line height, but we used flexbox again to show that it works with anonymous boxes (in this case, the line of text inside the h1 element). No matter how high the h1 element gets, the text will always be in the center:

h1 { flex;
   align-items: center;
   height: 10rem;
}

Flexible Sizes

If centering elements was all flexbox could do, it’d be pretty darn cool. But there is more. Let’s see how flex items can expand and contract to fit the available space within a flexbox element.

flexbox img 2
An interactive slideshow built using flexbox.

The HTML and CSS for this example are similar to the previous one’s. We’re enabling flexbox and centering the elements on the page in the same way. In addition, we want to make the title (inside the header element) remain consistent in size, while the five boxes (the section elements) adjust in size to fill the width of the window. To do this, we use the new flex property:

section {
   /* removed other styles to save space */
   -prefix-box-flex: 1; /* old spec webkit, moz */
   flex: 1;
   height: 250px;
}

What we’ve just done here is to make each section element take up 1 flex unit. Because we haven’t set any explicit width, each of the five boxes will be the same width. The header element will take up a set width (277 pixels) because it is not flexible. We divide the remaining width inside the body element by 5 to calculate the width of each of the section elements. Now, if we resize the browser window, the section elements will grow or shrink.

In this example, we’ve set a consistent height, but this could be set to be flexible, too, in exactly the same way. We probably wouldn’t always want all elements to be the same size, so let’s make one bigger. On hover, we’ve set the element to take up 2 flex units:

section:hover {
   -prefix-box-flex: 2;
   flex: 2;
   cursor: pointer;
}

Now the available space is divided by 6 rather than 5, and the hovered element gets twice the base amount. Note that an element with 2 flex units does not necessarily become twice as wide as one with 1 unit. It just gets twice the share of the available space added to its “preferred width.” In our examples, the “preferred width” is 0 (the default).

Source-Order Independence

For our last party trick, we’ll study how to achieve source-order independence in our layouts. When clicking on a box, we will tell that element to move to the left of all the other boxes, directly after the title. All we have to do is set the order with the order property. By default, all flex items are in the 0 position. Because they’re in the same position, they follow the source order.

flexbox figure1.3_mini
An interactive slideshow with flex-order.

To make our chosen element move to the first position, we just have to set a lower number. I chose -1. We also need to set the header to -1 so that the selected section element doesn’t get moved before it:

header {
   -prefix-box-ordinal-group: 1; /* old spec; must be positive */
   -ms-flex-order: -1; /* IE 10 syntax */
   order: -1; /* new syntax */
}

section[aria-pressed="true"] {
   /* Set order lower than 0 so it moves before other section elements,
      except old spec, where it must be positive.
 */
   -prefix-box-ordinal-group: 1;
   -ms-flex-order: -1;
   order: -1;

   -prefix-box-flex: 3;
   flex: 3;
   max-width: 370px; /* Stops it from getting too wide. */
}

In the old specification, the property for setting the order (box-ordinal-group) accepts only a positive integer. Therefore, I’ve set the order to 2 for each section element (code not shown) and updated it to 1 for the active element. If you are wondering what aria-pressed=“true” means in the example above, it is a WAI-ARIA attribute/value that I add via JavaScript when the user clicks on one of the sections.

This relays accessibility hints to the underlying system and to assistive technology to tell the user that that element is pressed and, thus, active. If you’d like more information on WAI-ARIA, check out “Introduction to WAI-ARIA” by Gez Lemon. Because I’m adding the attribute after the user clicks, this example requires a simple JavaScript file in order to work, but flexbox itself doesn’t require it; it’s just there to handle the user interaction.

Hopefully, this has given you some inspiration and enough introductory knowledge of flexbox to enable you to experiment with your own designs.

Syntax Changes

As you will have noticed throughout this article, the syntax has changed a number of times since it was first implemented. To aid backward- and forward-porting between the different versions, we’ve included tables below, which map the changes between the specifications.

Speci- ficationIEOperaFirefoxChromeSafari
Standard1112.10+ *2229+, 21–28 (-webkit-)
Mid10 (-ms-)
Old3–21 (-moz-)<21 (-webkit-)3–6 (-webkit-)
Specification versions

When Opera switched to Blink in version 15 it required the -webkit- prefix. The prefix was dropped in Opera 16.

Speci- ficationProperty nameBlock-level flexInline-level flex
Standarddisplayflexinline-flex
Middisplayflexboxinline-flexbox
Olddisplayboxinline-box
Enabling flexbox: setting an element to be a flex container

Speci- ficationProperty namestartcenterendjustifydistribute
Standardjustify-contentflex-startcenterflex-endspace-betweenspace-around
Midflex-packstartcenterendjustifydistribute
Oldbox-packstartcenterendjustifyN/A

Axis alignment: specifying alignment of items along the main flexbox axis

Speci- ficationProperty namestartcenterendbaselinestretch
Standardalign-itemsflex-startcenterflex-endbaselinestretch
Midflex-alignstartcenterendbaselinestretch
Oldbox-alignstartcenterendbaselinestretch
Cross-axis alignment: specifying alignment of items along the cross-axis

Speci- ficationProperty nameautostartcenterendbaselinestretch
Standardalign-selfautoflex-startcenterflex-endbaselinestretch
Midflex-item-alignautostartcenterendbaselinestretch
OldN/A

Individual cross-axis alignment: override to align individual items along the cross-axis

Speci- ficationProperty namestartcenterendjustifydistributestretch
Standardalign-contentflex-startcenterflex-endspace-betweenspace-aroundstretch
Midflex-line-packstartcenterendjustifydistributestretch
OldN/A

Flex line alignment: specifying alignment of flex lines along the cross-axis

This takes effect only when there are multiple flex lines, which is the case when flex items are allowed to wrap using the flex-wrap property and there isn’t enough space for all flex items to display on one line. This will align each line, rather than each item.

Speci- ficationProperty nameValue
Standardorder<number>
Midflex-order`<number>`
Oldbox-ordinal-group`<integer>`

Display order: specifying the order of flex items

Speci- ficationProperty nameValue
Standardflexnone | [ <<var>flex-grow</var>> <<var>flex-shrink<var>></var></var>? || <<var>flex-basis</var>>]
Midflexnone | [ [ <<var>pos-flex</var>> <<var>neg-flex</var>>? ] || <<var>preferred-size</var>> ]
Oldbox-flex<<var>number</var>>
Flexibility: specifying how the size of items flex

The flex property is more or less unchanged between the new standard and the draft supported by Microsoft. The main difference is that it has been converted to a shorthand in the new version, with separate properties: flex-grow, flex-shrink and flex-basis. The values may be used in the same way in the shorthand. However, the default value for flex-shrink (previously called negative flex) is now 1. This means that items do not shrink by default. Previously, negative free space would be distributed using the flex-shrink ratio, but now it is distributed in proportion to flex-basis multiplied by the flex-shrink ratio.

Speci- ficationProperty nameHorizontalReversed horizontalVerticalReversed vertical
Standardflex-directionrowrow-reversecolumncolumn-reverse
Midflex-directionrowrow-reversecolumncolumn-reverse
Oldbox-orient box-directionhorizontal normalhorizontal reversevertical normalvertical reverse
Direction: specifying the direction of the main flexbox axis

In the old version of the specification, the box-direction property needs to be set to reverse to get the same behavior as row-reverse or column-reverse in the later version of the specification. This can be omitted if you want the same behavior as row or column because normal is the initial value.

When setting the direction to reverse, the main flexbox axis is flipped. This means that when using a left-to-right writing system, the items will display from right to left when row-reverse is specified. Similarly, column-reverse will lay out flex items from bottom to top, instead of top to bottom.

The old version of the specification also has writing mode-independent values for box-orient. When using a left-to-write writing system, horizontal may be substituted for inline-axis, and vertical may be substituted for block-axis. If you are using a top-to-bottom writing system, such as those traditional in East Asia, then these values would be flipped.

Speci- ficationProperty nameNo wrappingWrappingReversed wrap
Standardflex-wrapnowrapwrapwrap-reverse
Midflex-wrapnowrapwrapwrap-reverse
Oldbox-linessinglemultipleN/A
Wrapping: specifying whether and how flex items wrap along the cross-axis

The wrap-reverse value flips the start and end of the cross-axis, so that if flex items are laid out horizontally, instead of items wrapping onto a new line below, they will wrap onto a new line above.

At the time of writing, Firefox does not support the flex-wrap or older box-lines property. It also doesn’t support the shorthand.

The current specification has a flex-flow shorthand, which controls both wrapping and direction. The behavior is the same as the one in the version of the specification implemented by IE 10. It is also currently not supported by Firefox, so I would recommend to avoid using it when specifying only the flex-direction value.

Conclusion

Well, that’s a (flex-)wrap. In this article, I’ve introduced some of the myriad of possibilities afforded by flexbox. Be it source-order independence, flexible sizing or just the humble centering of elements, I’m sure you can find ways to employ flexbox in your websites and applications. The syntax has settled down (finally!), and implementations are here. All major browsers now support flexbox in at least their latest versions.

While older versions of browser use different syntaxes, all the latest versions of the major browsers now support Flexbox in its final form. These browsers also no longer require prefixes, except (at the time of writing) Safari 6.1 and above. For the time being, to support all browsers, use the tables above to map the various syntaxes, and get your flex on.

Layout in CSS is only getting more powerful, and flexbox is one of the first steps out of the quagmire we’ve found ourselves in over the years, first with table-based layouts, then float-based layouts. IE 10 already supports an early draft of the Grid layout specification, which is great for page layout, and Regions and Exclusions will revolutionize how we handle content flow and layout.

Flexbox can be used today if you only need to support relatively modern browsers or can provide a fallback, and in the not too distant future, all sorts of options will be available, so that we can use the best tool for the job. Flexbox is shaping up to be a mighty fine tool.

This article is an updated excerpt of the chapter “Restyle, Recode, Reimagine With CSS3” from our Smashing Book #3, written by Lea Verou and David Storey. — Ed.

Further Reading

Smashing Editorial (al, mrn)