Monday, 29 August 2011

CSS3 Flexible Box Model | Van SEO Design

CSS3 Flexible Box Model | Van SEO Design


CSS3 Flexible Box Model

Posted: 29 Aug 2011 05:30 AM PDT

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.

Collage of browser logos

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.

Horizontal flexbox

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.

Flexbox with box-orient set to 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.

Flexbox items centered in flexbox through box-pack and box-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.

Packaging for elastic bands showing front of 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.

Flexbox with box-ordinal-group set on flexbox items

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.

Flexbox with box-flex set on flexbox items

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.

Packaging for elastic bands showing back of flexible box

Summary

The Flexible box layout module adds a lot tools to control the boxes you create in your layouts. Hopefully you can see how much flexibility it truly adds.

There’s more support for flexboxes than you might think as long as you stick with a terminology from the 2009 spec. Do note that the terminology is changing, though it shouldn’t be hard to transition to it.

There’s probably not enough support to use flexboxes in practice, though of course it depends on what browsers you need to support.

The good news is flexbox seems to be coming in the next version of IE. The bad news is we’ll have to wait for enough people to upgrade or use a Javascript workaround. I suspect Opera will get on board soon enough.