DLG Software


Application development

  with JavaScript, Flex, and AIR

This is an intro to the CSS Flexible Box specification, or flexbox, used to lay out web pages. Content includes links to numerous in-depth flexbox resources and several demos.

Simplifying UI layout

flexbox

CSS is brilliant for separating a web page's visual characteristics from its content (the HTML) and its behavior (the JavaScript). Many aspects of CSS are themselves brilliant — its effects and animations, selectors and pseudo-classes, adaptation to screen size through media queries, there's lots of good stuff here. But the page layout features of CSS? Not so brilliant.

Truth be told, doing layout with CSS frequently sucks, and it sucks most frequently when you're developing SPAs where the layout is often both complex and constantly changing as your application state changes. It sucks because it's harder than it should be. Floats and clearfixes, inline-block and table-cell, games with margins and positioning, of course all of this has its place and is often straightforward, but it's also true that creating layouts that are both complex and flexible can sometimes leave you feeling as if you're running a 10k while carrying a 50 pound weight — sure, you can still make it to the finish line, but getting there takes longer and is way more effort than necessary. Finally, though, there's good news on this front. Things are beginning to suck less. Because a layout standard called flexbox is finally being implemented consistently across modern browsers and flexbox is a relatively sane way to do layout.

What is Flexbox?

Flexbox (a.k.a. flexible box layout and flex layout) is a W3C standard that simplifies making layouts that are responsive and, well, flexible. Flexbox gives you control over how a container's direct descendents are sized and layed out. Through CSS properties you can apportion available space among children, modify order of children, set their alignment and spacing, and much more.

Here are some of the benefits of flexbox:

  • can lay out its children vertically or horizontally (flex-direction property)
  • children can grow to fill all available space of their parent (flex-grow or flex properties)
  • children can shrink to fit parent's available space if their normal sizing/layout would cause overflow (flex-shrink or flex properties)
  • children can be assigned growth/shrink factors that define the relative sizing of siblings. For example, you can have 1 child always twice as large as its siblings (flex-grow, flex-shrink, or flex properties)
  • children can easily be spaced and aligned, including dead simple vertical centering (justify-content, align-items, and align-self properties)
  • flexbox can use "overflow" line wrapping when children won't fit on a single row or column (flex-flow and flex-wrap properties)
  • you can display children in an order different from source order and dynamically reorder them (order property)
  • you can nest flexboxes, allowing for complex yet still flexible layouts

Keep in mind that this is all being done through CSS, no JavaScript required. And of course since this is CSS the layout is dynamic — if the user resizes the browser or rotates the mobile device or if you the developer do use JavaScript to change a flexbox-related CSS property then the layout will adjust based on current flexbox-related CSS values and current height and width. And since this is CSS you can also use media queries to assign different property values for different screens (though with flexbox you may find you have less need for media queries).

If you're itching to see some of this in action here are a couple of intro flexbox resources (there are many more resources and live demos later in this primer).

  • Chris Coyier of CSS-Tricks.com has a nice video overview of flexbox
  • Flexy boxes lets you explore flexbox capabilities (tip: start by changing the flex property's first parameter to set relative sizes of the children and to have them fill available space)

The Complications: Flexbox support and changing standards

So, the layout capabilities of flexbox should sound good, and they are — when you can use them. We're doing web development here, so as you'd expect there are inconsistent implementations across browsers and some older browsers don't support flexbox at all (including IE9 and lower). Modernizr's HTML5 Cross Browser Polyfills page recommends the Flexie polyfill which I haven't tried, but in any case it replicates only the old 2009 syntax. Which brings us to another problem: the multiple incarnations of flexbox you'll encounter.

Since 2009 browsers have implemented 3 different flexbox specifications with 3 different syntaxes. There's the initial 2009 spec, an early 2012 working draft spec used by IE10, and the final 2012 spec you'll find implemented in current releases of nearly all browsers. Below is a summary of support from CSS-Tricks' excellent "Guide to Flexbox" (for support info also check caniuse and HTML5please).

Chrome Safari Firefox Opera IE Android iOS
21+ (new)
20- (old)
3.1+ (old)
6.1+ (new)
2-21 (old)
22+ (new)
12.1+ (new) 10 (tweener)
11+ (new)
2.1+ (old)
4.4+ (new)
3.2+ (old)
7.1+ (new)
  • (new) means the recent syntax from the specification (e.g. display: flex;)
  • (tweener) means an odd unofficial syntax from 2011 (e.g. display: flexbox;)
  • (old) means the old syntax from 2009 (e.g. display: box;)

from Guide to Flexbox  

When your application needs to work in a wide variety of browsers or browser versions dealing with the multiple flexbox versions can make flexbox feel like normal CSS layout (i.e., kinda sucks) since you need a slew of browser prefixes and fallbacks (luckily tools like SASS and Autoprefixer can help with this). Here's an example:

#mainFlexboxWrapper {
  height: 100%;           /* make the flexbox itself fill available space  */
  
  /*** Make the container a Flexbox ***/
  display: -webkit-box;  /* 2009 specification. Need for some still common */
  display: -moz-box;     /* browsers like pre-4.4 Android stock, older iOS */
  display: -ms-flexbox;  /* 2012 March working draft spec used by IE10     */
  display: -webkit-flex; /* 2012 spec prefixed for iOS7/8                  */
  display: flex;         /* 2012 spec - the real deal, unprefixed          */
 
  /*** Change layout from default horizontal/row ***/
  -webkit-box-orient: vertical;  
  -moz-box-orient: vertical;
  -ms-flex-direction: column;                   
  -webkit-flex-direction: column; 
  flex-direction: column;   
}

It's important to note that there are features in the 2012 specs that don't have a simple fallback in one of the older flexbox specs. For example in the 2009 spec shrinking of items is enabled whenever growing is enabled, you can't independantly control a flex item's ability to shrink like you can in the later spec. Below are a few posts that cover mixing and matching your CSS to address the different flexbox standards:

So, does lack of flexbox support in older browsers and multiple standards mean flexbox comes with too much baggage to make it useful? Not by a long shot. Because while you can't use flexbox everywhere, when you can use it flexbox sucks a whole lot less than other CSS layout options. Let's take a brief look at why…

Flexbox Basics

To use flexbox you set CSS properties on both a parent (theflex container) and its children (theflex items). Properties that you set on a flex container affect how it lays out and sizes its direct children only — grandchildren and later children are not affected.


 
Code and description of features below are for 2012 flexbox specification. In the demos you can use your browser's developer tools to view the full CSS which includes fallbacks for earlier flexbox specs

Flex container

To make an element a flex container you set its CSS display property to flex (or inline-flex if you want a non-block element). That's all you need to create a flexbox; its direct children are now flex items. This means they can use the flexible box model instead of the standard box model — i.e., they can now be made flexible. One advantage is flexible sizing — flex items can grow to fill their parent's unused space and they can shrink to fit their parent when normal sizing would overflow it.

Several flexbox-related CSS properties control how your flex container lays out its children. For example, if you don't want the default horizontal row layout you can set the layout direction using theflex-direction property (values are column, column-reverse, row, row-reverse) as shown below.

  .flexContainer {
     display: flex ;        
     flex-direction: column ;   
  }

Still other flexbox-related properties control child alignment, spacing, justification, etc. I won't give details on all of these properties here, but the resource links below cover everything and I especially recommend the W3C flexbox spec itself, it's a very readable spec with useful diagrams.

There is a bit of terminology you'll need for flexbox: main axis and cross axis.  The main axis corresponds to the direction your items are layed out (i.e., the flex-direction) while the cross axis is perpendicular to the main axis. For example, if flex-direction is set to row then your main axis is horizontal and the cross axis is vertical. This is important to note because some options work only on the main axis (e.g., justify-content) while others work only on the cross axis (e.g., align-items). See the spec for a more detailed definition and diagram.

One last thing to note about flex containers: while a flexbox controls only its direct descendants you can nest flexboxes (i.e., an element can be both a flex child and a flex container). By nesting flexboxes you can create complex yet still flexible layouts. A couple of the demos below use nested flexboxes.

Flex items

The direct descendents of the flex container are its flex items. Once again you use CSS properties to control layout and sizing. Properties you set on a flex item affects how it relates to its siblings, including relative size, display order, alignment override, etc.

One of the biggest benefits of flexbox is the sizing of flex items. First, be aware that flex items can be made flexible or inflexible. Flexible flex items are sized based on the flexbox-related CSS properties you assign and the flex container's available space. Inflexible flex items don't participate in resizing, they "opt out", following normal box-sizing rules (however, they do indirectly affect the flexible items simply by taking up space within their common parent's bounds).

For flexible sizing the most important property is probablyflex. The value of this property is often a single numeric value that is used as a weight when growing items to fill their flex container. For example, if you have 2 flex items, one with flex:1 and the other with flex:2 then the second will generally grow twice as much as the first. I say generally because the actual sizing depends on the values of 3 flexbox-related properties flex-grow, flex-shrink, and flex-basis. These 3 properties are key to the resizing of flex items. Here's a summary of their function:

  1. flex-grow: controls whether a flex item can grow and how much it will grow when the parent has unused space after laying out its children
  2. flex-shrink: controls whether a flex item can shrink and how much it will shrink when the parent does not have enough space to fit its children
  3. flex-basis: sets flex item "base size", overriding other sizing specifications you might have given the item such as height:60px or width:40%. This base size is used in the parent-unused-space calculation. Items grow/shrink from this base size. The special value of auto tells flexbox to use the item's normal sizing (which can itself be the CSS special size value of  auto, which sizes the element based on its contents)

The flex property is actually a shorthand method for setting these 3 properties. You can set all 3 through the flex property by assigning 3 space-delimited values. For example, setting flex:1 .5 200px is the same as setting flex-grow:1, flex-shrink:.5, and flex-basis:200px. As we've seen in the examples above, you can also assign flex a single value (including keywords like none, more on that in a moment).

  flex: flex-grow [ flex-shrink ] [ flex-basis ] || flex-keyword

Note the syntax above — you can assign 1, 2, or 3 values to the flex property. When you assign the flex property a single numeric value such as flex:10 you're explicitly setting just flex-grow but it's important to note that this implicitly sets values for flex-shrink and flex-basis. When you assign flex a single number value then flex-shrink is set to 1 and flex-basis is set to 0. So, flex:10 is the same as setting flex-grow:10, flex-shrink:1, and flex-basis:0

You can also assign flex the keywords none, auto, and initial. These are basically presets for all 3 values of flex-grow, flex-shrink, and flex-basis. For example, the keyword none (i.e. flex:none) translates to flex:0 0 auto. In other words, setting flex:none is like setting flex-grow:0, flex-shrink:0 and flex-basis:auto (this setting makes a flex item inflexible at its normal box-sizing size but its height/width do affect the parent-unused-space calculation).

Here's a summary of the domain of values for the flex property:

  • none: same as flex:0 0 auto. Makes the item fully inflexible (neither shrinks nor grows). Because of the auto Its height/width are counted in the parent-unused-space calculation. It will display at its "normal" box-sizing size
  • initial: same as flex:0 1 auto. This is the default. Item will shrink if necessary to fit parent space but will not grow; height/width affect parent-unused-space calculation
  • auto: same as flex:1 1 auto. Item can both shrink and grow. Because flex-basis is auto the item is given its normal size. This size is used in the parent-unused-space calculation and any "grow space" allocated to the item is "tacked on" to the normally sized item.
  • number>0: same as flex:<number-you-assign> 1 0px. Makes the item flexible, able to grow or shrink to parent space. Numeric value you assign is used to weight the allocation of parent's unused space — i.e., an item with flex:2 (or flex-grow:2) will be allocated twice as much of that unused space as an item with flex:1 (or flex-grow:1). If all flex items have a number>0 as their flex value then they're sized proportionally based on these flex values (that's because of the flex-basis:0px — more on this special case in Example 2 below).
  • 0 (zero): same as flex:0 1 0px. You really won't use this one, since the flex-basis of 0px will simply cause the item to disappear (because it's sized to 0px and won't grow). In general if you want to hide something better to use display:none. And if what you really want is an item to be inflexible and to get its normal size — i.e,. you want the item to "opt out" of flexbox sizing — then you need flex: 0 0 auto or flex:none. Note: in browsers supporting the 2009 flexbox spec setting box-flex:0 makes it inflexible at its current size.
  • as described above, you can also assign the flex property multiple values which will set flex-grow, flex-shrink, and flex-basis (example: flex:1 0 200px).

Permissible flex values and the different defaults are detailed in the W3C flexbox spec's section on the flex property. Also useful is this CSS-Tricks flex property reference.

Ok, it's easier to grok this stuff with some diagrams and demos, so both are below. Note that the focus here is mostly on how flex items are grown rather than shrunk.


 
Examples and demos have an  i  button in the upper right corner. Use this to display flexbox-related CSS values. This is quick and dirty, useful for mobile, but for full CSS use your browser's devtools.

Simple example: Growing flex items

When a flexbox container has unused space — i.e., height or width left over after it lays out its children — you can have its flex items grow to fill that space. How much an item grows depends on several factors: its flex-grow value, its flex-basis value, and sometimes its "normal size" (e.g., explicit height such as height:60px). Parent unused space is determined by adding up space needed by all children and seeing what's left over. Left over space is divided up based on flex-grow values — an item with flex:2 will be allocated a portion of unused space twice as large as an item with flex:1. Space allocated to an item is added to its flex-basis size. If flex-basis is auto then the allocated space is "tacked on" to the item's normal size (e.g., if it has height:60px then it's tacked on to 60px). Here's an example:

child1 specified height:40px, flex:none, inflexible, height stays @ 40px
child2 specified height:60px, flex:1 0 auto, grows to 85px (60+25px)
25px growth "tacked on"
child3 specified height:50px, flex:3 0 auto, grows to 125px (50+75px)
75px growth "tacked on"
#flexboxParent {  
   display: flex;
   flex-direction: column;
   height: 250px;
}
#child1 {height:40px; flex: none;}
#child2 {height:60px; flex:1 0 auto;}
#child3 {height:50px; flex:3 0 auto;}

Parent height:250px, so has 100px "leftover" space. Total "flex units" is 4 (1+3) so leftover space Is allocated 25px to child2 (1/4 of 100) and 75px to child3 (3/4 of 100). BUT sizing would change if you changed flex-basis value

Example 1: Normal growth sizing — Run demo

When items are grown there's a special case where all items grow to fill all parent space and sizing is effectively based only on each item's flex-grow value. This occurs when all items have flex-grow enabled and flex-basis:0px. In this case an item's "normal" size is unimportant because all items are treated as having a size of 0. Result: when parent unused space is calculated it's all unused. And since allocated unused space is "tacked on" to each item's flex-basis (which is now 0px) the result is proportional sizing based on flex value:

item's height or width in %  =  item's flex value / sum of all items' assigned flex values

To illustrate this let's modify the previous example, giving all flex items a single positive number as their flex value (which implicitly gives them all a flex-basis:0px). Note that the end result is considerably different from the earlier example, with sizing effectively based on flex value only.

child1 specified height:40px,
flex:1, flex'd ht:50px (1/5 of parent)
child2 specified height:60px,
flex:1, flex'd ht:50px (1/5 of parent)
child3 specified height:50px,
flex:3, flex'd ht:150px (3/5 of parent)
#flexboxParent {  
   display: flex;
   flex-direction: column;
   height: 250px; 
}
#child1 { height:40px; flex:1; }
#child2 { height:60px; flex:1; }
#child3 { height:50px; flex:3; }

Parent height:250px is allocated based on flex values: total of flex values=5 so child1 and child2 get 1/5 while child3 gets 3/5. Key here is that all items have flex-basis:0px

Example 2: Proportional growth sizing — Run demo

One thing should be obvious by now: flex-basis is very important when it comes to sizing items. Here are some things to note about flex-basis:

  • the flex-basis value is what's used in the parent-unused-space calculation, so if an item's flex-basis is anything other than 0px that item will impact this calculation. When an item has a flex-basis of 0px it's still used in the parent-unused-space calculation but of course at 0px it has no impact.
  • If flex-basis:auto then the item's normal size (e.g., explicit height such as height:60px) will be used in the parent-unused-space calculation and allocation
  • any "grow space" allocated to the item is added onto its flex-basis size

One thing worth highlighting is that the spec recommends that you use the flex property rather than directly assigning values to its constituent flex-grow, flex-shrink, and flex-basis properties. I'm not sure I agree with this, but here's what they say:

"Authors are encouraged to control flexibility using the 'flex' shorthand rather than with component properties, as the shorthand correctly resets any unspecified components to accommodate common uses."   from W3C flexbox spec

Finally, it's worth pointing out that mixing flexible and inflexible items is often useful — for an example of this see the "sticky footer" demo below.

Ok, time to let you play with some of this. The four demos below cover properties described above and more. However, keep in mind that this post is intended to give only a taste of flexbox capabilities. For in-depth flexbox info see the Resources section below; to interactively explore flexbox you can also use Flexy boxes.

Flexbox Demos

Demos below cover some flexbox basics. Be sure to resize your browser (or rotate your mobile device) to see how flexbox handles layout changes. Also note the following:

  • these demos should work in browsers that use the final 2012 flexbox spec. For browsers that use an earlier spec I try to include fallbacks, but some things like line wrap/flow just aren't implemented in browsers using the 2009 spec and have no simple fallback
  • in browsers that don't support flexbox these demos just won't work — I'm not using polyfills
  • demos have a yellow  i  button in the upper right corner that gives a quick dump of selected flexbox-related CSS values (for full CSS and source use your browser's devtools).
  • if you're using a browser that doesn't support scrollable divs (e.g., Android 2.x stock) you won't be able to read all of the text, it will be clipped which cripples some of the demos (I am so looking forward to the demise of Android 2.x stock browser)
  • these demos let you explore flexbox capabilities but not all layouts here are useful. If you want practical layouts then check out Solved by Flexbox
It looks like your browser supports the 2012 flexbox specification so these demos should work fine for you.

Demo 1: Filling available space and relative sizing

This first demo simply lets you set the flex property on individual flex items. It has 3 flex items all of which start out with flex:1 (so initially they're sized proportionally, each getting 1/3 of parent). This demo has fallbacks for the earlier flexbox specs so it should work in browsers that support the older flexbox specs, but for those browsers enter only single numeric values and use 0 to make an item inflexible.

Demo1 sample screen
 #flexContainer {
   height: 100%; 
   display: flex ;        
   flex-direction: column ;
 } 
 .flexItem {
   flex: 1 ;  
   overflow:auto ;
 }

No height is specified for flex items. Initially all have flex-basis:0 so you start out with proportional sizing based on flex values. See below for some exploratory values to try...

Demo 1: Exploring the flex property — Run demo

Playing with different flex values can help you understand the effect of its 3 constituent properties, particularly flex-basis. Below are some things you might want to try.


 
Reminder: code and description here are for the final 2012 flexbox spec. 2009 spec doesn't have the same features and properties. For example, there's no analog for flex-basis and flex-shrink properties
  • To see the proportional sizing that I described above just change the value of the first child to 2. The flex:2 box will become twice as large as both of its siblings (because ratio to the others is 2:1) and take up half of their parent's total space (because it's been assigned 2 of the total 4 (2+1+1) assigned "flex units"). Remember, this isn't "normal" flexbox sizing, just a special case when all items have flex-basis:0
  • now make all items inflexible by assigning them all the special value  none. All 3 size to their content (because they've been assigned no explicit height). Because none grow now you can see the parent's unused space.
  • now in any item enter a non-zero numeric value. That item grows to fill that unused parent space. As long as at least one flex item has a number>0 for its flex-grow the parent's space will always be filled
  • now in any item enter a 0 value. That item will disappear. That's because you gave it a single numeric value, which means it's implicitly assigned flex-basis:0px. And of course it won't grow larger than that 0px because you disabled growth by setting flex to 0. That isn't too useful, if you just want to hide the item better to use display:none. More useful is this: reload the page so you can see all 3 children again and then on any item set flex to either 0 auto or initial. Now the item is sized normally (in this case sized to content), won't grow, will shrink. Note: if your browser is using the 2009 flexbox spec then entering a 0 makes the item inflexible at its current size.
  • reload page to reset to defaults, then set Child2 to 1 0 auto. First thing to note is that you aren't using simple proportional sizing now. That's because the height of Child2 now is counted in the parent-unused-space calculation and any space allocated to Child2 is now added onto its normal height. This will make it a bigger than it's siblings which still have flex:1 (and an implicit flex-basis of 0px).
  • set all items to 1 0 100px - you've got proportional sizing again (as long as your viewport is at least 300px tall). Why? Because they're all treated as being 100px tall regardless of content or any height spec you assigned. All that matters is that flex-basis value. And since flex-basis and flex-grow are the same for all they end up sized equally, each getting 1/3 of total space
  • reload the page to reset to defaults, then in Child1 expand and collapse the white-background informational text (use the more/less button). Note that as the text slides up and down Child1's height doesn't change; it maintains its proportional relationship with the other flex items. That's because it's flex-basis is currently 0px, so any change in the height its content needs doesn't matter. Now change Child1 to 1 0 auto and again hide/show that text. Now Child1 changes height as the text hides/shows, and this makes its siblings also change height. That's because auto tells flexbox to always count the size of Child1 when measuring and allocating unused parent space, and that space is "tacked on" to Child1 as its height changes to accommodate the changing height of the text as it slides up/down

Notes on this demo:

  • This MDN post has a summary of flex property values, as does this CSS-Tricks post
  • allocation of space is different between final 2012 spec and older flexbox 2009 spec. For example, 2009 doesn't have flex-basis property or simple proportional sizing
  • in IE10 you can enter multiple values as you would with flex in the final 2012 spec. This demo does support entering multiple values for IE10. It also accepts the none keyword (but not the other keywords)
  • for 2009 spec browsers only the first value you enter is used and is assumed to be numeric
  • for 2009 spec browsers enter the value 0 to make an item inflexible (item will lock at current size)

Demo 2: Sticky footer

You can use flexbox's grow-to-fill-space capability to easily create a sticky footer. Demo 2 shows a dead simple layout for this — inflexible <header> and <footer> containers separated by a <div> that grows to fill available space. When that middle container grows it "pushes down" the footer, locking it at the bottom of their parent. Although the header and footer are inflexible they do size to content, so if their height changes (e.g., the browser is made narrower, causing the text to wrap which in turn increases the container's height) flexbox responds by adjusting the height of that middle flex item to fill available space even as that space changes (which of course keeps the footer in position).

Demo1 sample screen

This just shows how having a flexible item above an inflexible item can give you a sticky footer -- when the flexible item grows to fill available space it "pushes down" the 3rd child, keeping it always at the bottom of the parent container, making it a sticky footer

This demo includes a media query that drops font-size for smaller screens

As with all of these demos, to see the full CSS including fallbacks use your browser's devtools

Demo 2: Sticky footer — Run demo

Notes on this demo:

  • to see what would happen without flexbox growing that middle container use the "set flex-grow:0" checkbox. This disables the container's growth and it collapses down to its normal size, which in this case is its min-height:value of 100px. And of course this makes your footer no longer locked to the bottom of the parent container (for browsers supporting the 2009 flexbox spec the item will become inflexible at its current height, resize the browser and you'll see it...)
  • when the screen gets small you'll start to see text clipping in the header and footer (it will no longer size to content because of lack of space). To handle this the demo has a media query that drops font-size when width is LT 400px or height LT 300px or is iPhone LT 6.
  • for another way to create a sticky footer with flexbox see this video of Zoe Mickley Gillenwater's presentation on flexbox at a 2014 Smashing conference, is packed with useful info...

Demo 3: Centering, wrapping, reordering

Vertical centering is one layout task that often took more effort than it should have, particularly when your container height was dynamic such as when the browser was being resized. There were ways to do it including using JavaScript but a simple, sensible CSS solution just wasn't there. Well, flexbox makes centering vertically and horizontally a piece of cake. Demo 3 shows centering on both axes (though you can have different alignments on the different axes, and individual flex items can override alignment with align-self). For a bit more info on this topic Smashing has a useful post that covers centering through flexbox.

This demo also has an option to show flexbox wrapping (disabled if browser doesn't support the final 2012 spec, though note that IE10 does actually support wrapping, and it's even included in the 2009 spec but not implemented in any browsers). When you activate the "more kids, with wrap on" checkbox 4 more children are added and you're presented with options that help you explore this flexbox feature. Wrapping lets your flexbox span multiple lines when the main axis doesn't have enough space to fit all children. Note that when wrap is enabled flex-shrink isn't so important because items will wrap to a new line if they don't fit. With wrapping your key value is flex-basis — it is the measure that controls how much you can fit on a line.

Finally, in this demo child6 has a checkbox to change its order value. All of the boxes have been assigned an order value that matches their source order (i.e., the second box has order:2). The checkbox changes the child6's order value from 6 to -1, which is a lower order value than the other flex items, so child6 moves to first position in the flexbox. Very simple, and combined with media queries can be very useful in optimizing layouts for smaller mobile screens.

Demo1 sample screen

Properties set on flex container

.flexContainer {  
  height:100%;
  width:100%;
  /* center on main axis */
  justify-content: center; 
  /* center on cross axis */
  align-items: center;
  /* enable wrap to new row/col*/
  flex-wrap:wrap
       etc....

Initially flex items aren't assigned a flex value so they get the default: 0 1 auto — don't grow, do shrink, use normal sizing (initial sizes: height:195px, width:220px)

Demo 3: Centering, alignment, wrap, reorder — Run demo

Notes on this demo:

  • numbers in the upper right corner reflect HTML source order
  • items start out with height:195px and width:220px
  • the checkbox in child2 activates wrapping and adds 4 more children, but it's disabled if your browser doesn't support the final 2012 flexbox spec (note that IE10 does support wrapping, I just haven't bothered to enable it for IE10 in this demo)
  • while child4 lets you enter numeric px values for height and width, keep in mind that these are ignored on the main axis whenever flex-basis isn't set to auto
  • some of the options in Child5 will reset both height/width to auto, and some force the layout direction to horizontal
  • some of the wrap/flow layouts in child5 are just explorations, they're not always useful (for practical layouts see Solved by Flexbox). In some cases layout won't visibly change when you change the layout option, especially on small screens. That's because your container size is a factor in layout, so resize your browser (or rotate your tablet) and you might then see layout/sizing differences. Here's a summary of the exploratory flex value assignments of this demo:
    1. 0 1 auto: this is the default value for all flex items. With flex-grow:0 and flex-basis:auto the items have their "normal" height of 195px. An exception is small screens — on a phone you might see flex-shrink kick in, sizing items down to fit the viewport, though they'll shrink no further than their min-height:50px. Note that you'll only see shrinking when wrapping is off — once wrap is enabled you don't get shrinking, you get line-wrapping. This is easy to see in a desktop browser. Try this: with wrap off (so, only child1 and child2 visible) start sizing down your browser. At some point those 2 children should start shrinking on the main axis. Ok, now try this: in child2 click that checkbox to activate wrapping. Now the items wrap before shrinking. The flexbox determines how many items it can fit on a line (row or column, depends on flex-direction) and when it can't fit any more on a line it just starts on a new line. In this demo because of that flex-basis:auto the wrapping algorithm uses the item's specified height and width (which is used again depends on flex-direction).
    2. 1 0 auto: inverse of option #1 above, items can now grow but won't shrink. They still wrap based on their size (because of the flex-basis:auto) but once the wrapping is done the parent-unused-space calculation is performed and items grow to fill unused space in their row/column. Note that this growth is only on the main axis (the next options shows growth on both axes)
    3. 1 1 50px + cross axis stretch: this attempts to fit all items to parent space, growing them them on the main axis and stretching them on the cross axis. To reduce wrapping flex-basis is set to 50px, which means flexbox treats each item as having a height/width of only 50px, so you only need 300px to fit all 6 items on a single line. The flex-grow:1 then expands each item to fill space on the main axis, equally distributing the leftover space. The result: on the main axis the six children fill space and are equally sized. To have the items fill the cross axis align-items:stretch is applied to the flex container. Very importantly the items' height/width are set to auto here (this is for the cross-axis sizing, since other specified height/widths would interfere with cross axis stretch — enter a height/width via the input fields and you'll see that the value you enter "wins", overriding the align-items:stretch).
    4. 1 1 100% + size to content: here the flex-basis:100% results in wrapping for every item, with each item appearing on a separate line (because at 100% each item fills its line, causing the next item to wrap onto a new line). Since flex-grow:1 each item will then grow to fill its main axis line. To size items to their content on the cross-axis the items' height/width are set to auto. Also, to make the layout a bit more useful two flex container properties are forced: align-items:stretch (to have items also grow in the cross axis space) and flex-direction:row (set it to vertical and you'll see why). TIP: this demo works with flex-basis set to 100% because it uses box-sizing:border-box. Without that the margins/borders will cause scrollbars to appear (of course you could cheat-fix that by setting width to something slightly smaller like 96%, but why bother, border-box is better)
    5. "pack em in" — this option attempts to maximize children's use of parent space and minimize scrolling for content. If your browser is sized fairly large you'll see an irregular tile layout (once there's enough space for content-based sizing to allow multiple items on a line). For smaller screens you just see the boxes stacked vertically (because orientation is row and items are wrapping to new lines). This option makes quite a few changes, best to see the CSS for this, but among the changes it makes is forcing the flex container's flex-direction:row (NOTE: this also deselects the "use a vertical layout" checkbox) and on flex items it sets flex:1 1 auto.  This means items will grow on the main axis. For cross-axis sizing the items' height/width are set to auto (which sizes items to their content).
  • the order option in child6 shows how easy it is to display flex items in an order different from source order. In this demo all children are given source order to match their position (i.e., child2 has order=2). The "set child6 order=-1" checkbox simply gives child6 the lowest order value of all flex items so it's moved to first position (before child1 which has order=1)
  • on small screens you may see flex-shrink kick in on load
  • this uses box-sizing:border-box to simplify layout
  • this helephant.com post has some good info on flow/wrap
  • wrapping (multi-line flexboxes) are not available in Firefox until version 28

Demo 4: Nesting flexboxes

You can also nest flexboxes to create more complex layouts. This is demonstrated by demo 4, which has 3 levels of flexboxes, as follows:

  1. an outermost flexbox is used to fill the browser's space with its two children. These two containers, the yellow <header> and the red-bordered main body <div>, are layed out vertically, with the latter always growing to fill the vertical space below the header (which sizes to content)
  2. the red-bordered container isn't just a flexbox child, it's also a flexbox. Like its parent it has two children, the leftPane and rightPane containers. However, this flexbox uses row layout for side-by-side positioning of its children — the green-bordered leftPane <div> has a width of 40% and its blue-bordered sibling fills the remaining horizontal space
  3. Like their parent, the green-bordered leftPane and blue-bordered rightPane are flexboxes as well as flexbox children. These innermost nested flexboxes both use column layout. In the left pane the pink-background child has a value of flex:1 to fill available space. This "pushes down" the purple footer container to keep it at the bottom of leftPane. The flexbox in the right pane is simply used to size its white-background div, growing it so that it always fills the space below the rightPane heading text
Demo1 sample screen

This brings together many of the features covered above, using nested flexboxes to make a slightly more complex (yet still flexible) layout. Summary of nesting:

  1. outermost flexbox is used to make red-bordered div fill space below header
  2. red-border flexbox horizontally lays out its 2 children (leftPane and rightPane)
  3. innermost flexboxes in right and left panes vertically layout/size children (e.g. create sticky footer in left pane)

Demo 4: Flexbox nesting — Run demo

Notes on this demo:

  • to see how flexbox children can dynamically resize to fill available space use the Hide/Show button to toggle display of the orange-background header child or use the orange child's "hide leftPane" checkbox to hide/show the leftPane div
  • each nested flexbox in this demo displays a bit more info via tooltips (though of course if you're on mobile you're out of luck...)
  • js/jquery isn't used for layout here, used only for applying effects. The gradual height/width
    change of the effects shows how flexbox resizes flex items in response to sibling size change
  • this should work on most phones but it's not a great layout for small screens. I haven't bothered, but a media query would be in order here that modified things a bit, maybe laying out the pink and cyan containers vertically instead of horizontally (i.e., change the flex-direction property)
  • as noted previously, in Android 2.x stock browser which doesn't support scrolling divs (i.e., overflow:auto or scroll) then this demo will appear broken, you can't scroll to see all of the text, but of course this has nothing to do with flexbox

Gotchas

Since flexbox lives and plays within web browsers there are, of course, pain points to mention — differences between browsers, things that just don't work in some browsers. Luckily the pain isn't too extreme among the browsers that do support the final 2012 spec. Below are posts that include lists of known flexbox issues:

Conclusion

Hopefully the content above has given you an idea of what's possible with flexbox.  However, keep in mind that this post gives only a taste of what's possible with flexbox. For the full course of flexbox features and for more complex examples see the Resources list below.

Obviously flexbox is no panacea.  For one thing, there are support issues — older browsers (e.g., IE9 and earlier) don't support flexbox and there are no good polyfills for the 2012 spec's features.  And the multiple Flexbox standards mean that browsers that support only the early Flexbox specs won't be capable of some of the newer flexbox features.

Bottom line with flexbox: using flexbox isn't always an option, but when it is an option it's usually a better option than doing CSS layout the old-fashioned way. 

Resources


Copyright © Dan Gronell 2014. Licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 unported license. Creative Commons License

You can contact me at dan@dlgsoftware.com.


Here is the mailto link
if you'd like to use it...