CSS3 Flexible Box Model

by Steven Bradley
on Monday, August 29th, 2011
vanseodesigns ::

CSS offers several tools to help with site layout. Over the years we’ve worked mainly with floats, positioning, and margins, but let’s face it, most of us would like more. Fortunately css3 is giving us more tools for layouts. One of those tools is the flexible box.

A couple of weeks ago .net magazine published an article on The future of css layouts, in which they covered several new css3 layout modules. I’d like to work through some of them starting today with the flexible box layout module.

I’ve created a demo page illustrating some of the properties of the flexbox, though there’s not much to see in the demo that you can’t see from the images throughout this post. It’s there in case you want to play around with the source code.

Browser Support

There’s actually pretty good support for flexible boxes in the latest browsers. Safari, Chrome, Firefox, and IE10PP all support everything discussed below.

On the other hand Opera as well as IE9 and below don’t support it so the flexible box isn’t yet ready for full time use unless you’re ok adding a javascript solution. Flexie is one such solution, though I haven’t had a chance to test it.

You should also know that the spec is changing. The latest W3C working draft and editor’s draft use different terminology than what currently works in practice. I’ll stick with the terminology that currently works and make note of the corresponding terms in the latest specs.

Also note that I’ll stick with the generic terminology in this post, but to make flexible boxes work in practice you’ll need to use vendor prefixes like -webkit and -moz.

flexbox-horizontal

Creating a Flexbox

CSS 2.1 defined 4 layout modes

  • block — for overall layout
  • inline — for text
  • table — for tabular data
  • positioned — for explicit positioning

Flexbox is a new layout mode provided by css3 and it’s similar to block layout on the surface. It lacks some properties of blocks such as floats and columns, but it adds some simple tools for aligning content inside a box.

In a flexbox content can be laid out in any direction, elements can be reordered dynamically, and the size and position of elements can flex in response to the available space.

A flexbox will act like a block when placed it other layout modes by default, but it can be set to act as an inline-box as well. Child elements of a flexbox are referred to as flexbox items.

Here’s a simple example of how it will work.

<div id="flexbox">
  <div id="box1">box 1</div>
  <div id="box2">box 2</div>
</div>

Above we have a parent div with two child divs. The parent div will become the flexbox and the child divs will be the flexbox items inside the flexbox.

#flexbox {display: box; width: 600px}
#box1 {width: 300px}
#box2 {width: 150px}

Pretty simple to set up and again you need to use vendor prefixes at the moment.

  • display: -webkit-box
  • display: -moz-box

You’ll notice that horizontally we have 150px extra of space inside of the flexbox. Properties we later set on the flexbox items will allows us to modify this extra space and alter the behavior of the flexbox.

Note: In the current specs flexbox is being used instead of box so in time we’ll use display: flexbox.

structure flexbox-vertical

box-orient and box-direction

box-orient sets the direction in which flexbox items will be laid out inside the flexbox and has several allowable values

  • horizontal — Lay out children from left to right in a horizontal line
  • vertical — Lay out children from top to bottom vertically
  • inline-axis — Lay out children along the inline axis (map to horizontal)
  • block-axis — Lay out children along the block axis (map to vertical)
  • inherit — The value will be inherited from the parent element

In the image above I set box-orient to vertical, which is probably the value you’ll set most often. Horizontal is the default.

box-direction is a more general way to set the order of the flexbox items. The one value to know about is reverse which displays the flexbox items in reverse order of how they’re listed in the html.

Note: It looks like both box-orient and box-direction are becoming the single flex-direction in the current working drafts.

flex-direction will have the associated values lr, rl, tb, bt, inline, inline-reverse, block, and block-reverse. lr stands for left to right and tb stands for top to bottom.

structure box-pack-align

box-pack and box-align

We won’t always want to fill up all the extra space inside a flexbox. We may instead prefer to have child elements positioned within that space, for example centered vertically or horizontally.

One property we can use is box-pack, which has associated values of start, end, center, and justify.

Start and end can ultimately be any of the 4 box sides depending on whether your flexbox is horizontal or vertical and which direction it’s items are laid out in.

.box {box-pack: center}
.box {box-align: center}

Assuming a horizontal flexbox with no reverse set, start refers to the left edge and end refers to the right edge.

Items would be packed against this edge with the next item packed against the first. Center packs things toward the center and justify packs toward the edges.

Another property for dealing with extra space is the box-align property. It’s values are start, end, center, and stretch, which work similarly to the same values for box-pack.

A new value here is baseline which says to set each flexbox item so their baselines align and then distribute the space above and below. The baseline can be either horizontal or vertical depending on the direction of the flexbox.

Note: The current spec refers to box-pack as flex-pack and box-align and flex-align.

box-lines

The box-lines property sets how the box handles content that overflows it’s size and has the associated values single and multiple.

  • single — All child elements will be placed in a single row or column (elements that do not fit will simply be considered overflow)
  • multiple — The box is allowed to expand to multiple lines, to accommodate all of its children

Note: box-lines aren’t mentioned in the most recent spec, but the editors draft refers to flex-flow, which looks to mimic box-lines. I also haven’t been able to get box-lines working in any browser I’ve tested in.

structure flexible-box

Flexbox Items

The properties above control how the flexbox itself behaves. We also have some properties to control how the flexbox items behave.

Only direct descendants of the flexbox are considered flexbox items. Children of flexbox items (grandchildren of the flexbox) are not also flexbox items of the same flexbox.

A new flexbox would need to be created for them to become new items of a new flexbox.

structure box-ordinal-group

box-ordinal-group

box-ordinal-group controls the order in which the flex-items are displayed within the flexbox. The values of the box-ordinal-group property are integers.

<div>
<span id="span1">span1</span>
<span id="span2">span2</span>
<span id="span3">span3</span>
<span id="span4">span4</span>
</div>

Above we have 4 spans inside a div. Below we’ll set the div to be a flexbox and assign a box-ordinal-group to some of the spans.

div { display: flexbox; }
#span1 { box-ordinal-group: 2; }
#span3 { box-ordinal-group: 2; }
#span4 { box-ordinal-group: 1; }

Because span 4 is given a box-ordinal-group of 1 it will display before both spans 1 and 3, which have a box-ordinal-group of 2.

Span 2 doesn’t have a box-ordinal-group specified and so defaults to a box-ordinal-group of 1. Because span 2 appears in the html before span 4 and because both have the same box-ordinal-group, span 2 will display first.

The order the spans will be displayed is

  • span2
  • span4
  • span1
  • span3

This will solve a lot of the problems I talked about last week in regards to rearranging html boxes as we’ll have more control over the order the boxes are displayed.

Note: In the latest specs box-ordinal-group is being referred to as flex-order, though it will work the same way.

structure box-flex

box-flex

box-flex sets whether or not the child items are inflexible or flexible and in the case of the latter, how. It tells the flexbox and flexbox items what to do with the extra space.

It’s values should be seen as fractions. An element with a box-flex of 2 would get twice the extra space as an element with a box-flex of 1.

<div id="flexbox">
  <div id="box1">box 1</div>
  <div id="box2">box 2</div>
  <div id="box2">box 3</div>
</div>

The above html is the same example used at the start of this post.

#flexbox {display: box; width:600px}
#box1 {width:150px; box-flex: 1}
#box2 {width:150px; box-flex: 13}
#box3 {width:150px; box-flex: 1}

Again we have 150px of extra space inside the box. Here we’ve set box-flex values of 1, 13, and 1 respectively on our flexbox items.

The center flexbox item will receive an additional 130px of the extra space and the other items will each receive 10px of the additional space.

Another property, box-flex-group, is meant to group flexbox items. However at the moment it has no browser support and no mention in the latest spec.

Note: The latest working draft makes no mention of box-flex or box-flex group. Both seem to be absorbed into the flex() function, though the syntax of flex() is still under discussion.

Additional Resources

Below are some other articles that cover the flexible box layout module. They discuss the same properties as I have here and offer their own examples of the code in use.

 

Lynda DamiataCSS3 Flexible Box Model