CSS Flexbox Layout Module

Last updated:

(Note: This is a draft proposal to replace the current Flexbox module located at http://dev.w3.org/csswg/css3-flexbox. It has not been endorsed or officially reviewed by the CSSWG yet, and should not be taken as anything more than my own personal proposal.)

Introduction

CSS 2.1 defined three layout modes, algorithms which determine the size and position of boxes based on their relationships with their sibling and ancestor boxes: table layout, designed for laying out information in a tabular format, static layout, designed for laying out documents and simple applications, and positioned layout, designed for very explicit positioning without much regard for other elements in the document. This module introduces a new layout mode, flexbox layout, which is designed for laying out more complex applications and webpages.

Flexbox layout is superfically similar to static layout. It lacks many of the more complex text or document-formatting properties that can be used in static layout, such as float or columns, but in return it gains several additional properties for determining the size and placement of boxes that address common needs in complex applications and web pages. The children of a flexbox can be laid out in any direction and have their order swapped around, as well as "flexing" their sizes and positions to respond to the available space in the flexbox.

In this specification, an element with display:flex is called a "flexbox". Children of the flexbox are called "flexbox children". No other elements are referred to specially, as Flexbox Layout only affects the layout of the flexbox itself and its direct children (or anonymous boxes wrapping its direct children, in some cases).

Creating A Flexbox

property : display

new value : flex

You can declare that an element is a flexbox, and thus should use flexbox layout, by setting the display property on the element to the value flex.

All children of a flexbox must be block-level or atomic inline-level elements. Contiguous runs of non-replaced inline elements are wrapped in an anonymous block-level box. Out-of-flow elements (such as floats and absolutely positioned elements) leave behind a "placeholder" in their original source location which is treated like a non-replaced inline element for the purpose of this wrapping. (This can, for example, create an empty flexbox child, if all the children are block-level elements and one is absolutely positioned.) It is recommended that authors avoid putting in elements which are auto-wrapped with anonymous boxes, as the anonymous boxes cannot be targetted and controlled with the various flexbox properties defined later in this draft.

[[Ping fantasai on the correct terms to use here.]]

Setting display:flex on an element forces it to use a new layout algorithm, and so some properties that were designed with the assumption of "normal" flow don't make sense in a flexbox context. In particular:

  • all of the properties in the Multicol module compute to their initial values on a flexbox
  • [Others?]

A flexbox child creates a new BFC. As well, the margins of a flexbox child do not collapse with any other margin.

Flexbox Direction

property : flexbox-direction

values : ltr | rtl | ttb | btt | inline | inline-reverse | block | block-reverse

default value : inline

applies to : flexboxes

The flexbox-direction property specifies how flexbox children are placed on each line of the flexbox. A value of ltr means that the first flexbox child is placed against the left edge of the flexbox, with later children placed immediately to the right of the preceding flexbox child. A value of rtl is the same, but with the initial flexbox child placed against the right edge of the flexbox and later children placed to the left. Both of these values mean that the flexbox is a horizontal flexbox. A value of ttb means that the first flexbox child is placed against the top edge of the flexbox, with later children placed immediately below it, while btt means the first child is placed against the bottom edge of the flexbox, with later children placed immediately above it. Both of these values mean that the flexbox is a vertical flexbox.

A value of inline computes to one of ltr, rtl, ttb, or btt, depending on the direction and block-flow of the flexbox: if the start side of the flexbox is the left side, inline must compute to ltr; if the start side of the flexbox is the right side, inline must compute to rtl; if the start side of the flexbox is the top side, inline must compute to ttb; if the start side of the flexbox is the bottom side, inline must compute to btt. inline-reverse, block, and block-reverse are identical to inline, but base their computed value off of the end side, before side, or after side of the flexbox, respectively.

For example, a very basic flexbox can be marked up as:

<div style="display: flex; width: 400px; height:100px;">
  <div style="flex-grow: 1;"></div>
  <div style="flex-grow: 2;"></div>
  <div style="flex-grow: 1;></div>
</div>

[[TODO: Fix diagram to not use the flex unit.]]

A vertical flexbox can be used to emulate the functionality of HTML's <center> element:

<div>
  <span>foo foo foo foo</span>
  <span>bar bar<br>bar bar</span>
  <span>foo foo foo foo foo foo foo foo foo foo foo foo</span>
</div>
<style>
  div { display: flex; flex-direction: ttb; width: 200px; }
  span { margin: 0 auto; }
</style>

Flexibility

The defining aspect of Flexbox Layout is flexibility - flexbox children can be made flexible, which means they'll work together to distribute available space, stretching or shrinking their widths and heights as necessary to fill the flexbox completely. The space around and between the children can flex as well, pushing the children around inside the flexbox.

This is controlled through several new properties, and some existing properties: the width/height properties, flex-stretch controls the size of the flexbox children in the direction of the flexbox (width for horizontal flexboxes, height for vertical flexboxes), margin and flex-pack control the space between flexbox children in the direction of the flexbox, and margin, the width/height properties, and flex-align control the size, spacing, and alignment of boxes in the perpendicular direction.

Note: The flexbox properties in this section are symmetrical for horizontal and vertical flexboxes, except where noted. To simplify the language, this section will assume a horizontal flexbox. In a vertical flexbox all properties apply in the same way, with all references to physical directions or dimensions swapped to the relevant direction or dimension in the opposite direction.

This chapter is almost entirely informative. The only normative content in this chapter, and the contained subchapters, are the syntax definitions of the properties introduced herein. In particular, the descriptions of how these properties work are entirely informative. A later section of the spec gives the normative meaning of each property, in terms of the sizing algorithm.

Horizontal Sizing

new property : flex-grow

values : <number>

default value : 0.0

allowed on : flexbox children

new property : flex-shrink

values : <number>

default value : 0.0

allowed on : flexbox children

new property : flex-stretch

values : <flex-grow> <flex-shrink>

default value : 0.0 0.0

allowed on : flexbox children

The flex-grow and flex-shrink properties control whether or not a flexbox child's width is flexible, and how flexible it is. The value of these properties must be non-negative numbers; a negative number for either value renders the property invalid. The flex-stretch property is a shorthand property which sets both flex-grow and flex-shrink together.

Free space is determined by subtracting the sum of the preferred widths of the flexbox children from the width of the flexbox. The free space may be positive, in which case any flexible children may grow to fill the space, or negative, in which case any flexible children may shrink to avoid overflowing the space, in either case respecting min and max widths on the flexbox children as well. The preferred width of a flexbox child with a specified width is that width; otherwise, it's the max-content width of the flexbox child.

If there is positive free space in the flexbox, then any flexbox child with a non-0 value for flex-grow is considered flexible. Flexible children will divide up the free space proportionally according to their flex-grow values. For example, if the flexbox has three children, two with flex-grow:1 and one with flex-grow:2, and there is 100px of free space in the flexbox, the first two children will increase their width by 25px, while the latter child will increase its width by 50px.

Similarly, if there is negative free space in the flexbox, then any flexbox child with a non-0 value for flex-shrink is considered flexible. Flexible children will divide up the (negative) free space proportionally according to their flex-shrink values. For example, if the flexbox has three children, two with flex-shrink:1 and one with flex-shrink:2, and there is -100px of free space in the flexbox, the first two children will decrease their width by 25px, while the latter child will decrease its width by 50px.

Auto left and right margins also participate in free space distribution, similar to if they were blocks with width:0; flex-grow:1;.

Horizontal Spacing

new property : flex-pack

values : start | end | center | justify

default value : start

applies to : flexboxes

The flex-pack property specifies what to do with leftover free space if there are no flexible widths or margins, or if all flexible widths have grown to their maximum size and there is still space left over.

The start value specifies that flexbox children will be packed toward the start of the flexbox (this is not necessarily the 'start' logical edge - it's the edge of the flexbox that flexbox children are first placed against). That is, any leftover free space must be placed at the end of the flexbox.

Similarly, the end value specifies that flexbox children will be packed toward the end of the flexbox (same caveat as above applies). That is, leftover free space is placed at the start of the flexbox.

The center value specifies that flexbox children will be placed in the center of the flexbox; leftover free space is split equally between being placed at the start and end of the flexbox.

The justify value specifies that flexbox children will be spaced evenly in the flexbox; if there are N flexbox children, leftover free space is split into N-1 equal parts and inserted between each flexbox child. There is no free space placed at the start or the end of the flexbox; the first and last flexbox child will be flush with the edges of the flexbox.

Vertical Spacing, Sizing, and Positioning

Vertically sizing and positioning flexbox children is much simpler than doing so horizontally, as you only have to worry about one box and its margins. Free space is just the height of the flexbox minus the preferred height of the flexbox child and its top and bottom margins. Ordinarily, an auto height will attempt to fill all the available space (flex-align can change this behavior, see below). If there is space left over after computing the height, remaining space is split evenly between the auto margins. If there is free space left over and neither margin is auto, then the free space is placed after the flexbox (the 'end' or 'after' logical side of the flexbox, whichever maps to a vertical direction).

new property : flex-align

values : shrink | before | after | middle | baseline

default value : before

applies to : flexbox children

The flex-align property aligns the contents of a flexbox child with the contents of other flexbox children in the same flexbox. It has slightly different effects depending on the writing-mode of the flexbox child.

If the flexbox child has a vertical writing-mode (in a horizontal flexbox, remember - the same applies to a horizontal writing-mode in a vertical flexbox), then flex-align has only a minor effect. A value of before, after, middle, or baseline will make the flexbox child's height flex if it is auto; a value of shrink makes an auto height shrink-wrap.

If the flexbox child has a horizontal writing-mode, flex-align has its full effect. Similar to the previous paragraph, a value of before, after, middle, or baseline will make an auto height flex to the full height of the flexbox, while a value of shrink will make an auto height shrink-wrap. As well, flex-align will align the contents of the flexbox children with each other. All the flexbox children with the same value for flex-align will be aligned together, independent of the alignment of any flexbox children with a different flex-align values:

  • before and shrink: All flexbox children with a value of before or shrink for flex-align will have the before-side of their contents aligned together. In English text, for example, this is the top of the content.
  • after: All flexbox children with a value of after for flex-align will have the after-side of their contents aligned together.
  • middle: All flexbox children with a value of middle for flex-align will have the middle of their contents (halfway between the before-edge and the after-edge of their content).
  • baseline: All flexbox children with a value of baseline for flex-align will have the baselines of their contents aligned.

Flex Assignment Algorithm

[[to be completed - much work was already done in the v2 draft, it just needs to be rewritten]]

(a limited set of Markdown is supported)

Here is a full detailed explanation for compatibility including IE10+ http://www.wpmemorize.com/2013/css-flexbox-to-design-flexible-layouts/

Reply?

(a limited set of Markdown is supported)