The CSS Flexible Box Module Level 1, or flexbox for short, makes the once-difficult task of laying out your page, widget, application, or gallery almost simple. With flexbox, layout is so simple you won’t need a CSS framework. Widgets, carousels, responsive features—whatever your designer dreams up—will be a cinch to code. And, while flexbox layout libraries have already popped up, instead of adding bloat to your markup, read this book, and learn how, with a few lines of CSS, you can create almost any responsive feature your site requires.
By design, flexbox is direction-agnostic. This is different from block or inline layouts, which are defined to be vertically and horizontally biased, respectively. The web was originally designed for the creation of pages on monitors. Vertically-biased layout is insufficient for modern applications that change orientation, grow, and shrink depending on the user agent and the direction of the viewport, and change writing modes depending on the language.
Layout on the web has been a challenge for many. For years we joked about the challenges of vertical centering and multiple column layout. Some layouts were no laughing matter, like ensuring equal heights in a grid of multiple side-by-side boxes, with buttons or “more” links fixed to the bottom of each box, with the button’s content neatly vertically centered, as shown in Figure 1-1, or ensuring boxes in a varied content gallery were all the same height, while the top gallery row of boxes were neatly lined up with the boxes in subsequent rows, as shown in Figure 1-2.
Flexbox makes all of these challenges fairly simple.
Other than actually declaring a height, risking lots of whitespace or overflowing content, there was no way to make all the columns equal in height. Multiple column layouts were created by floating every column, with each column being a predetermined width and differing heights dependent on the column’s content. While you can use faux background images with such a multiple column layout solution, or the table
value of the display
property, flexbox is a simple way—and the correct way—to make the columns equal in height.
Before floated layouts, it was common to see tables used for layout. Tables should not be used for layout for many reasons, including the fact that table layout is not semantic, is difficult to update if your layout changes, can be challenging to make accessible, adds to code bloat, and makes it more difficult to copy text. That said, tables are appropriate for tabular data.
The holy-grail layout, with a header, three columns, and a footer, could be solved in many ways, none of them simple, until we had flexbox. Generally, we used floats:
HTML:
<header>
Header</header>
<main>
<nav>
Links</nav>
<aside>
Aside content</aside>
<article>
Document content</article>
</main>
<footer>
Footer</footer>
CSS:
main
{
background-image
:
url(images/fakecolumns.gif)
;
width
:
100%
;
float
:
left
;
}
aside
,
nav
{
float
:
left
;
width
:
25%
;
overflow
:
hidden
;
}
article
{
float
:
left
;
width
:
50%
;
}
This code appears here for historical sake—you don’t need to do this anymore!
The output is shown in Figure 1-5.
Most designs call for columns of equal heights, but adding different background colors or images to aside
, article
, and nav
in Figure 1-5 would actually amplify that they have different heights. To provide for the appearance of equal-height columns, we often added a faux background to the parent based on the column widths declared in our CSS, as shown by the gray-white-gray background image in Figure 1-5.
To ensure the parent was at least as tall as the floated columns, most developers added a clearfix as generated content after the last column, though providing the parent a floated width of 100% was an equally viable solution.
A clearfix
is a class that can be added to your CSS and then to any
element to ensure it fully contains its floated children. It works by adding invisible generated content that is either displayed block
or table
and then cleared, thereby clearing everything above it. Common examples you’ll find in the wild include:
.clearfix
:after
{
content
:
"."
;
display
:
block
;
height
:
0
;
clear
:
both
;
visibility
:
hidden
;
}
and
.clearfix
:after
{
content
:
""
;
display
:
table
;
clear
:
both
;
}
When using this technique, an additional block or anonymous table cell descendant is inserted
into the container as generated content. This descendant is cleared of
any floats in the inline or block direction. This forces the block size
of the container that has the .clearfix
applied to include the
heights of the floats (these dimensions are normally not included since
floats are removed from the flow).
The method I used instead of adding a .clearfix
class and generated content was to take advantage of the fact that, with CSS, all floated elements must be at least as tall as their tallest floated descendant. By making the parent 100% wide and floating it, the parent would be at least as tall as its tallest nested floated descendant while being alone on its own line. This floating method of clearing was supported in browsers before archaic versions of Internet Explorer began supporting generated content:
main
{
width
:
100%
;
float
:
left
;
}
The preceding layout is actually uglier that what is shown in Figure 1-5. I added padding to make it look better. The change to the box model properties caused the total width to be greater than 100%, causing the last column to drop. This is easily resolved with box-sizing: border-box;
. Adding a positive left or right margin would also cause the last column to drop, with no simple quick fix.
Between collapsing margins and dropping floats, the old layout method could be downright confusing. Many people started using YUI grids, Bootstrap, Foundation, 960 grid, and other CSS grid libraries to simplify their development process. Hopefully your takeaway will be that you don’t need a CSS framework crutch.
Note that flexbox was designed for a specific type of layout, that of single-dimensional content distribution. While you can create grid-like layouts (two-dimensional alignment) with flexbox, there is a Grid specification, which with improved support will be the correct way of creating grids. This is discussed further in Grid Layout in CSS by Eric A. Meyer (O’Reilly).
Flexbox is a simple and powerful way to lay out web applications or sections of documents by dictating how space is distributed, content is aligned, and displays are visually ordered, enabling the appearance of stretching, shrinking, reversing, and even rearranging the appearance of content without altering the underlying markup. Content can now easily be laid out vertically or horizontally, can appear to have the order rearranged, can be laid out along a single axis or wrapped across multiple lines, can grow naturally to encompass all the space available, or shrink to fit into the space allotted, and so much more.
Flexbox is a declarative way to calculate and distribute space. Multiple column layouts are a breeze even if you don’t know how many columns your content will have. Flexbox enables you to be confident your layout won’t break when you dynamically generate more content, when content is removed, or when your users stretch or shrink their browser or switch from portrait to landscape mode.
With flexbox, visually rearranging content without impacting the underlying markup is easy. With flexbox, the appearance of content can be independent of source order. Though visually altered, flex properties should not impact the order of how the content is read by screen readers.
Screen readers following source order is in the specification, but Firefox currently follows the visual order. There is discussion in the accessibility community that this Firefox “bug” may be the correct behavior. Therefore, it’s possible the spec may change.
And, importantly, with flexible box module layouts, elements can be made to behave predictably for different screen sizes and different display devices. Flexbox works well for responsive sites, as content can increase and decrease in size when the space provided is increased or decreased.
Flexbox can be used to map out an entire document through block layouts or used inline to better position text.
Flexbox is a parent and child relationship. Flexbox layout is activated
by declaring display: flex;
or display: inline-flex;
on an element
which then becomes a flex container, arranging its children within the
space provided and controlling their layout. The children of this flex
container become flex items.
Flexbox works on an axis grid system. With flexbox you add CSS property values to a flex container element, indicating how the children, the flex items, should be laid out. The children can be laid out from left to right, right to left, top to bottom, or even bottom to top. The flex items can be laid out side by side on a single line, or allowed, or even forced, to be wrapped onto multiple lines based on the flex containers flex property values. These children can be visually displayed as defined by the source order, reversed, or rearranged to any order of your choosing.
Should the children of your flex container not fill up the entire width or height of the container, there are flexbox properties dictating how to handle the extra space, including preserving the space or distributing it between the children. When space is preserved, you can group the children to the left, the right, or centered, or you can spread them out, defining how the space is spread out either between or around the children.
You can grow the children to take up all the available space by distributing that extra space among one, some, or all of the flex items. You get to dictate how the children grow by distributing the extra space evenly, proportionally, or by set amounts. The children can be aligned with respect to their container or to each other, to the bottom, top, or center of the container, or stretched out to fill the container. Regardless of the difference in content length among sibling containers, with flexbox you can make all the siblings the same size with a single CSS declaration.
If there isn’t enough space to contain all the children, there are flexbox properties you can employ to dictate how the children should shrink to fit within their container.
Flexbox defines a formatting context along with properties to control layout. When you set an element to be laid out as a flexible box, it will only flex its immediate children, and not further descendants. However, you can make those descendants flexible boxes as well, enabling some really complex layouts. An element that has both a parent and a child can be both a flex container and a flex item.
Elements that aren’t flexed, and are not absolutely positioned,
have layout calculations biased to block and inline flow directions.
Flex layout, on the other hand, is biased to the flex directions. The
flex-flow
value (see “The flex-flow
Shorthand Property”) determines how content is mapped to the top, right,
bottom, left, along a horizontal or vertical axis, and by width and
height.
Once you set an element to be a flex container, its children follow the flexbox rules for layout instead of the standard block, inline, and inline-block rules. Within a flex container, items line up on the “main axis.” The main axis can either be horizontal or vertical so you can arrange items into columns or rows. The main axis takes on the directionality set via the writing mode: this main axis concept will be discussed in depth later on (see “Understanding axes”).
In the next sections we’ll cover how to make a flex container using the
display
property, then explain the various flex container properties
to distribute and align flex items within the flex container. Once we’ve
covered the properties applied to the flex container, we’ll cover the
properties applied directly to the flex items. We’ll learn how to make
the children of flex containers shrink and grow, and we’ll discuss the
properties applied to the those children that enable them to override
the distribution and alignment globally set on all the flex items by the
parent flex container. We’ve also included several flexbox use cases.
display
PropertyThe first step is to turn an element into a flex container. This is done
with two new values for the well-known display
property.
There are currently 30 values for the display
property descriped in
the various specifications. While not all of the newer display values
are fully supported at the time of this writing, they are expected to be
included in all modern browsers.
The run-in
and compact
values were included in CSS2, but removed in
CSS2.1. run-in
made it back into
CSS Display Module Level
3 along with flow
, flow-root
, and contents
. The inline-list-item
value is included the
CSS
Lists and Counters Module Level 3 specification. All of these
experimental values are still being discussed and are not fully
supported. When the flow-root
value garners support, expect to also get support for space-separated values such as display: flow list-item block;
.
Two of the newer values for the display
property have been added in the
CSS Flexible Box
Layout Module Level 1 specification: flex
and inline-flex
. The value
of flex
turns the element on which it is applied into a block-level
flex container box. Similarly, the inline-flex
value turns the element
on which it is applied into a flex-container block, but the flex
container is an inline-level flex container box.
Simply adding either of these display
property values on an element
turns the element into a flex container and the element’s children into flex items. By default, the children are all the same height, even if
their contents would produce elements of different heights, as shown in
Figure 1-6.
For people familiar with float-based layouts, the default appearance
that is created simply by adding these display
values is similar to
setting a container width to 100% and floating it and all its children
to the left, or using the .clearfix
method, but better. The children
still fit on a single line, even if they may have wrapped if truly
floated. And, just as how floated elements are at least as tall as their
tallest floated children, the container will be tall enough to encompass
its children.
The inline-flex
value makes the flex container behave like an
inline-level element. It will be only as wide as needed, as declared, or as wide as
one column if flex-direction
is set to column
(defined next). Like
other inline-level elements, the inline-flex
container sits together
on a line with other inline-level elements, and is affected by the
line-height and vertical alignment, which creates space for the
descenders underneath the box by default. The flex
value of the
display
property behaves like a block element.
We’ve added padding, margins, and borders to the flex container
and items to improve the appearance of the figures and for better figure legibility. Box-model properties
do impact flex layout. Had we not included these properties, all the
flex items would be bunched up against the flex container and against
each other and would be indistinguishable from one another. The illustration
explanations will not address the effects of the box-model properties
until we start covering some of the effects of box-model layout in
“The align-content
Property”.
If we want to create a navigation bar out of a group of links, it’s very
simple. Simply display: flex;
:
nav
{
display
:
flex
;
}
<
nav
>
<
a
href
=
"/"
>
Home
</
a
>
<
a
href
=
"/about"
>
About
</
a
>
<
a
href
=
"/blog"
>
Blog
</
a
>
<
a
href
=
"/jobs"
>
Careers
</
a
>
<
a
href
=
"/contact"
>
Contact
Us
</
a
>
</
nav
>
In the preceding code, with its display
property set to flex
, the
<nav>
is turned into a flex container, and its child links are all
flex items. These links are flex-level boxes, semantically still links,
but now flex items in their presentation. They are not inline-level
boxes: rather, they participate in their container’s flex formatting
context. Therefore, the whitespace is ignored:
nav
{
display
:
flex
;
border-bottom
:
1px
solid
#ccc
;
}
a
{
margin
:
0
5px
;
padding
:
5px
15px
;
border-radius
:
3px
3px
0
0
;
background-color
:
#ddaa00
;
text-decoration
:
none
;
color
:
#ffffff
;
}
a
:hover
,
a
:focus
,
a
:active
{
background-color
:
#ffcc22
;
color
:
black
;
}
With a little added CSS, we’ve got ourselves a simple tabbed navigation bar, as shown in Figure 1-7.
A flex formatting context is similar to a block formatting context, except flex layout is used instead of block layout: floats do not intrude into the flex container, and the flex container’s margins do not collapse with the margins of its contents.
While there are similarities, flex containers are different from block
containers. Some CSS properties do not apply in the flex context. The
column-*
properties, ::first-line
and ::first-letter
don’t apply
when it comes to the flex container.
The ::first-line
and ::first-letter
pseudo-elements
select the first line and first letter of block-level elements respectively.