The CSS Flexible Box Module Level 1, or Flexbox for short, makes the once difficult task of laying out
many classes of page, widget, application, and gallery almost simple.
With Flexbox, you often don’t need a CSS framework.
In this chapter, you’ll learn how, with a few lines of CSS, you can create almost any feature your site requires.
Flexbox Fundamentals
Flexbox is a simple and powerful way to lay out page components
by dictating how space is distributed, content is
aligned, and elements are visually ordered. Content can easily
be arranged vertically or horizontally, and
can be laid out along a single axis or wrapped across
multiple lines. And much, much more.
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.
Note
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, so the spec may change.
Perhaps most importantly, with flexible box module layouts, elements can be made
to behave predictably for different screen sizes and different display
devices. Flexbox works very well with responsive sites, as content can
increase and decrease in size when the space provided is increased or
decreased.
Flexbox works off of a parent and child relationship. Flexbox layout is activated
by declaring display: flex or display: inline-flex on an element. This element
becomes a flex container, arranging its children within the
space provided and controlling their layout. The children of this flex
container become flex items. Consider the following styles and markup, illustrated in Figure 12-1:
Notice how each child element of the divs became a flex item, and furthermore, how they all laid out in the same way? It didn’t matter that some were paragraphs and others were spans. They all became flex items. (There would likely have been some differences due to the paragraphs’ margins, except those were removed.)
The only real difference between the first and second flex containers is that one was set to display: flex, and the other to display: inline-flex. In the first, the div becomes a block box with flex layout inside it. In the second, the div becomes an inline-block box with flex inside it.
Note
As of this writing, a new pattern emerging in CSS is to separate display values into separate keywords. In this new system, the values used would be display: flex block and display: flex inline. The legacy values flex and inline-flex will continue to work fine, so don’t worry about using them, but if you see values like inline flex or flex inline, that’s why.
The key thing to keep in mind is that once you set an element to be a flex container, like the divs in Figure 12-1, it
will only flex its immediate children, and not further descendants.
However, you can make those descendants flex containers as well, enabling
some really complex layouts.
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”).
As the first div in Figure 12-1 demonstrates,
when the flex items don’t fill up the entire
main axis (in this case, the width) of the container, they will leave extra space.
There are properties dictating how to handle that extra space, which we’ll explore later in the chapter.
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.
Besides distributing space, you can also allow the flex items to grow to take up all the available space by
distributing that extra space among one, some, or all of the flex items.
If there isn’t enough space to contain all the flex items, there are
flexbox properties you can employ to dictate how they should
shrink to fit within their container, or whether they’re allowed to wrap to multiple flex lines.
Furthermore, 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
declaration.
A Simple Example
Let’s say we want to create a navigation bar out of a group of links. This is exactly the sort of thing flexbox was designed to handle. Consider:
In the preceding code, with its display property set to flex, the
nav element is turned into a flex container, and its child links are all
flex items. These links are still hyperlinks,
but they’re also flex items in terms of their presentation.
They are no longer inline-level
boxes: rather, they participate in their container’s flex formatting
context. Therefore, the whitespace between the a elements is completely ignored in layout terms. If you’ve ever used HTML comments to suppress the space between links, list items, or other elements, you know why this is a big deal.
With that CSS, we’ve got ourselves a simple tabbed navigation
bar, as shown in Figure 12-2.
That might not seem like much right now, because there’s nothing here you couldn’t have done with old-school CSS. Just wait: it gets better.
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, and assumed a horizontal constraint
with infinite vertical scroll. This 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.
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, and with the button’s content neatly vertically centered, as shown in Figure 12-3; or, ensuring boxes in a varied content gallery were all the same height, while the top gallery row of boxes was neatly lined up with the boxes in subsequent rows, as shown in Figure 12-4; or, keeping the pieces of a single button all neatly lined up, as shown in Figure 12-5. Flexbox makes all of these challenges fairly simple.
Note
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 classic “Holy Grail” layout, with a header, three equal-height columns of varying flexibility, and a footer, could be solved in many ways—none of them simple—until we had flexbox.
Here’s an example of the HTML that might represent such a layout:
Most designs call for columns of equal heights, but adding backgrounds
to the aside, article, and nav would 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, used massive padding and negative margins, inserted cleared generated content, and other tricks.
With all of these tricks cluttering up our CSS (and somethings our HTML), the old layout methods
could be downright confusing. Many people started using YUI grids,
Bootstrap, Foundation, 960 grid, and other CSS layout libraries just to
bring a little bit of sanity to their development process.
Hopefully, this book will help you realize
you no longer need a CSS framework to keep your layout styles sane.
As this chapter progresses, remember that flexbox was designed for a specific type of layout, that of
single-dimensional content distribution. In other words, it works best at arranging information along a single dimension, or axis.
While you can create grid-like
layouts (two-dimensional alignment) with flexbox, this is not its intended purpose. If you find yourself pining for two-dimensional layout capabilities, see Chapter 13, Grid Layout.
Flex Containers
The first important notion to fully understand is that of flex container,
also known as container box. The element on which
display: flex or display: inline-flex is applied becomes the flex container and generates a flex
formatting context for its child elements.
These children are flex items, whether they are
DOM nodes, text nodes, or generated content. Absolutely positioned
children of flex containers are also flex items, but each is sized and
positioned as though it is the only flex item in the flex container.
We’ll first learn all about the CSS properties that apply to the flex
container, including several properties impacting the layout of flex
items. Flex items themselves are a major concept you need to understand, and
will be covered in full later on, in “Flex Items”.
The display property examples in Figure 12-1 show three flex items
side by side, going from left to right, on one line. With a few
additional property value declarations, we can center the items, align them to the bottom of the container,
rearrange their order of appearance, or lay them out from left to
right or from top to bottom. We can even make them span a few
lines.
Sometimes we’ll have one flex item, sometimes we’ll have dozens.
Sometimes we’ll know how many children a node will have, and sometimes the
number of children will not be under our control.
We might know the number of items, but not know the width of the container.
We should have robust
CSS that can handle our layouts when we don’t know how many flex items
we’ll have or how wide the flex container will be (think responsive).
Fortunately, flexbox makes all of that much easier than it sounds, and it does so with just a handful of new properties.
The flex-direction Property
If you want your layout to go from top to bottom, left to right, right
to left, or even bottom to top, you can use flex-direction to control
the main axis along which the flex items get laid out.
The flex-direction property specifies how flex items are placed in the
flex container. It defines the
main axis of a flex container, which is the primary axis along which flex items are laid out (see “Understanding axes” for more details).
Figure 12-6 shows how that simple list would be arranged by each of the four values of flex-direction applied, assuming a left-to-right language.
The default value, row, doesn’t look all that different than a bunch of inline or floated elements. This is misleading, for reasons we’ll soon see, but notice how the other flex-direction values affect the arrangement of the list items.
For example, you can reverse this layout of the items with flex-direction: row-reverse. The flex items are laid out from top to bottom when
flex-direction: column is set, and from bottom to top if
flex-direction: column-reverse is set, as shown in Figure 12-6.
We specified left-to-right languages, because the direction of the main
axis for row—the direction the flex items are laid out in—is the
direction of the current writing mode. We’ll discuss how writing modes affect flex direction and layout in a bit.
Warning
Do not use flex-direction to change the layout for
right-to-left languages. Rather, use the dir attribute, or the
writing-mode CSS property described in “Setting Writing Modes”, which enables switching between horizontal
and vertical, to indicate the language direction. To learn more about language direction and flex box, see “Other Writing Directions”, later in the chapter, for more details.
In languages like English, the column value sets the flex container’s main axis to be the same
orientation as the block axis of the current writing mode. This is the
vertical axis in horizontal writing modes like English, and the horizontal axis in vertical writing modes like traditional Japanese.
Thus, when declaring a column direction, the flex items are displayed in the same order as
declared in the source document, but from top to bottom instead of left
to right, so the flex items are laid out one on top of the next instead
of side by side. Consider:
Using markup like that, by simply
changing a few CSS properties, we can create a nice sidebar-style
navigation for the list of links we saw earlier as a horizontal row of tabs.
For the new layout, we merely change the flex-direction from
the default value row to column, move the border from the bottom to the
right, and change the colors, border-radius, and margin values, with the result seen in
Figure 12-7.
The column-reverse value is similar to column, except the main axis
is reversed, with main start being at the bottom, and main end being
at the top of the vertical main axis, going upward, as shown in
Figure 12-6. The reverse values only change the appearance. The speech order and tab
order remains the same as the underlying markup.
What we’ve learned so far is super powerful and makes layout a breeze.
If we include the navigation within a full document, we can see how
simple layout can be with just a few flexbox property declarations.
Let’s expand a little on our preceding HTML example, and include the
navigation as a component within a home page:
<body><header><h1>My Page's title!</h1></header><nav><ahref="/">Home</a><ahref="/about">About</a><ahref="/blog">Blog</a><ahref="/jobs">Careers</a><ahref="/contact">Contact Us</a></nav><main><article><imgalt=""src="img1.jpg"><p>This is some awesome content that is on the page.</p><button>Go Somewhere</button></article><article><imgalt=""src="img2.jpg"><p>This is more content than the previous box, but less than
the next.</p><button>Click Me</button></article><article><imgalt=""src="img3.jpg"><p>We have lots of content here to show that content can grow, and
everything can be the same size if you use flexbox.</p><button>Do Something</button></article></main><footer>Copyright © 2018</footer></body>
By simply adding a few lines of CSS, we’ve got a nicely laid out home
page, as shown in Figure 12-8:
Yes, elements can be both flex items while being flex containers, as we
see with the navigation, main, and articles in this case. The body and
articles have column set as their flex directions, and we let nav
and main default to row. Just two lines of CSS!
To be clear, there’s more styling at work in Figure 12-8. Some border, margin, and
padding were applied to all the elements, so you can visually differentiate the flex items for
the sake of learning (I wouldn’t put this less-than-attractive site in
production). Otherwise, all we’ve done is simply declare the body,
navigation, main, and articles as flex containers, making all the navigation,
links, main, article, images, paragraphs, and buttons flex items.
Other Writing Directions
If you’re creating websites in English, or another left-to-right (LTR)
language, you likely want the flex items to be laid out from left to
right, and from top to bottom. Defaulting or setting row will do that.
If you’re writing in Arabic, or another right-to-left language, you likely
want the flex items to be laid out from right to left (RTL), and from top to
bottom. Defaulting or setting row will do that, too.
flex-direction: row arranges the flex items in the same direction as
the text direction, also known as the writing mode, whether it’s the language is RTL
or LTR. While most websites are presented in left-to-right
languages, some sites are in right-to-left languages, and yet others are
top to bottom. With flexbox, you can define single layout. When you
change the writing mode, flexbox takes care of changing the flex
direction for you.
The writing mode is set by the writing-mode, direction, and
text-orientation properties, or by the dir attribute in HTML. (These are covered in Chapter 6.)
When the writing mode is right to left, the
direction of the main axis—and therefore the flex items within the flex
container—will go from right to left when the
flex-direction is row. This is illustrated in Figure 12-9.
Note
If the CSS direction value is different from the dir attribute value
on an element, the CSS property value takes precedence over the HTML
attribute. The specifications strongly recommend using the HTML attribute rather than the CSS property.
There are vertically written languages, including Bopomofo, Egyptian
hieroglyphs, Hiragana, Katakana, Han, Hangul, Meroitic cursive and
hieroglyphs, Mongolian, Ogham, Old Turkic, Phags Pa, Yi, and sometimes
Japanese. These languages are only vertical when a vertical writing mode
is specified. If one isn’t, then all of those languages are horizontal.
If a vertical writing mode is specified, then all of the content is
vertical, whether one of the listed vertically written languages or even
English.
For top-to-bottom languages,
writing-mode: horizontal-tb is in effect, the main axis is
rotated 90 degrees clockwise from the default left to right, so
flex-direction: row goes from top to bottom and
flex-direction: column; proceeds from right to left. The effects the various flex-direction values have on the following markup is shown in
Figure 12-10:
That’s right: the rows are vertical, and columns are horizontal. Not only that, but the basic column direction is right to left, whereas column-reverse runs left to right. That’s what comes of applying these values to a top-to-bottom, right-to-left language like we see here.
All right, we’ve seen various ways flex direction and writing modes interact.
But so far, all the examples have shown a single row or column of flex items. What happens when the flex items’ main dimension (their combined
widths for row or combined heights for column) don’t fit within the
flex container? We can either have them overflow,
or we can allow them to wrap onto additional flex lines. We’ll later learn how to make the flex items shrink to fit too.
Wrapping Flex Lines
If the flex items don’t all fit into the
main axis of the flex container, by default the flex items will not
wrap, nor will they necessarily resize.
Rather, the flex items may shrink if allowed to do so via the flex
item’s flex property (see “Growth Factors and the flex Property”) and/or the flex items may overflow the bounding container box.
You can affect this behavior. The flex-wrap property can be set on
the container to allow the flex items to wrap onto multiple flex lines—rows or columns of flex items—instead of having flex items
overflow the container or shrink as they remain on one line.
The flex-wrap property controls whether the flex container is limited
to being a single-line container or is allowed to become multiline if
needed. When the flex-wrap property is set to allow for multiple flex
lines, whether the value of wrap or wrap-reverse is set determines
whether any additional lines appear either before or after the original line of
flex items.
By default, no matter how many flex items there are, all the flex items
are drawn on a single line. This is often not what we want. That’s where
flex-wrap comes into play. The wrap and wrap-reverse values allow
the flex items to wrap onto additional flex lines when the constraints
of the parent flex container are reached.
Figure 12-11 demonstrates the three values of flex-wrap property when the
flex-direction value is row (and the language is LTR).
Where these examples show two
flex lines, the second line and subsequent flex lines are added in the
direction of the cross axis (in this case, the vertical axis).
Generally for wrap, the cross axis goes from top to bottom for row
and row-reverse and the horizontal direction of the language for
column and column-reverse. The wrap-reverse value is similar to
wrap, except that additional lines are added before the initial line
rather than after it.
When set to wrap-reverse, the cross axis direction is reversed: subsequent lines
are drawn on top in the case of row and
row-reverse and to the left of the previous column in
the case of column and column-reverse.
Similarly, in right-to-left languages,
row wrap-reverse and row-reverse wrap-reverse,
new lines will also be added on top, but for
column wrap-reverse and
column-reverse wrap-reverse newlines will be added to the
right—the opposite of the language direction or writing mode, the
direction of the inverted cross axis.
We’ll talk about axes in just a moment, but first, let’s talk about the shorthand that bring flex direction and wrapping together.
Defining Flexible Flows
The flex-flow property lets you define the directions of the main and
cross axes, and whether the flex items can wrap to more than one line if
needed.
The flex-flow shorthand property sets the flex-direction and
flex-wrap properties to define the flex container’s wrapping and main
and cross axes.
As long as display is set to flex or inline-flex, omitting
flex-flow, flex-direction, and flex-wrap is the same as declaring
any of the following three, all of which have the result shown in Figure 12-12:
In left-to-right writing modes, declaring any of the property values just listed, or omitting
the flex-flow property altogether, will create a flex container with a
horizontal main axis that doesn’t wrap. Figure 12-12 illustrates flex items distributed along the horizontal axis, on one line,
overflowing the container that’s 500 pixels wide.
If instead we wanted a reverse-column-oriented flow with wrapping, either of these would suffice:
In an LTR language, that would cause the flex items to flow from bottom to top, starting at the left side, and wrap to new columns in the rightward direction. In a vertical writing mode like Japanese, the columns would be horizontal, flowing from left to right, and wrap top to bottom.
We’ve kept using terms like “main axis” and “cross axis” without really delving into what they mean. It’s time to clarify all that.
Understanding axes
First: flex items are laid out along the main axis. Flex lines are added in
the direction of the cross axis.
Up until we introduced flex-wrap, all the examples had a single line
of flex items. That single line of flex items involved laying out the
flex items along the main axis, in the main direction, from
main-start to main-end. Depending of the flex-direction property,
those flex items were laid out side by side, top to bottom or bottom to
top, in one row or column along the direction of the main axis. These are illustrated in detail in Figure 12-13.
As you can see, there are a lot of terms used in that figure, many of them new to the discussion. Here are some quick definitions:
main axis
The axis along which content flows. In flexbox, this is the direction in which flex items are flowed.
main size
The total length of the content along the main axis.
main start
The end of the main axis from which content begins to flow.
main end
The end of the main axis toward which content flows, opposite the main start.
cross axis
The axis along which blocks are stacked. In flexbox, this is the direction in which new lines of flex items are placed, if flex wrapping is permitted.
cross size
The total length of the content along the cross axis.
cross start
The edge of the cross axis where blocks begin to be stacked.
cross end
The opposite edge of the cross axis from the cross start.
Where each of these are placed depends on the combination of the flex direction, the flex wrapping, and the writing mode. Charting all the combinations for every writing mode would get difficult, so let’s examine what the mean for left-to-right languages. Table 12-1 breaks it down for us.
Note
It’s important to understand things get reversed when writing direction
is reversed. To make explaining (and
understanding) flex layout much simpler, we’re going to base the rest of
the explanations and examples in this chapter on left-to-right writing
mode, but will include how writing mode impacts the flex properties and
features discussed.
Table 12-1. Dimensions and directions of the main and cross axis, along with their start points, end points, and directions in left-to-right layout
Flex directions in LTR writing modes
row
row-reverse
column
column-reverse
main axis
left to right
right to left
top to bottom
bottom to top
main-start
left
right
top
bottom
main-end
right
left
bottom
top
main size
width
width
height
height
main dimension
horizontal
horizontal
vertical
vertical
cross axis
top to bottom
top to bottom
left to right
left to right
cross-start
top
top
left
left
cross-end
bottom
bottom
right
right
cross size
height
height
width
width
cross dimension
vertical
vertical
horizontal
horizontal
When thinking about flex-direction, we know the flex items are
going to start being laid out along the main axis of the flex
container, starting from the main-start.
When the flex-wrap property is used to allow the
container to wrap if the flex items don’t fit onto one line, the cross
directions determine the direction of additional lines in multiline
flex containers.
As we learned in the flex-flow shorthand
overview in “Wrapping Flex Lines”, flex items can be set to wrap to additional lines if
they would otherwise overflow the main size of the
container. While the laying out of the flex items on each flex line is
done in the main direction, going from main-start to main-end, the
wrapping to additional lines is done along the cross direction, from
cross-start to cross-end.
The cross axis is always perpendicular to the main axis.
As we see in Figure 12-14, when we have horizontal rows of flex items, the
cross axis is vertical. Flex lines are added in the direction of the
cross axis. In these examples, with flex-flow: row wrap and
flex-flow: row-reverse wrap set on horizontal languages, new flex
lines are added below preceding flex lines.
The cross size is the opposite of main size, being height for row
and row-reverse and width for column and column-reverse in both
RTL and LTR languages (though not top-to-bottom languages).
Flex lines are filled with items and placed into
the container, with the first line added at the cross-start side of
the flex container and going toward the cross-end side.
The wrap-reverse value inverts the direction of the cross axis.
Normally for flex-direction of row and row-reverse, the
cross axis goes from top to bottom, with the cross-start on top and
cross-end on the bottom. When flex-wrap is wrap-reverse, the
cross-start and cross-end directions are swapped, with the
cross-start on the bottom, cross-end on top, and the cross axis
going from bottom to top. Additional flex lines get added on top of, or above, the
previous line.
If the flex-direction is set to column or column-reverse, by
default the cross axis goes from left to right in left-to-right
languages, with new flex lines being added to the right of previous
lines. As shown in Figure 12-15, when flex-wrap is set to wrap-reverse,
the cross axis is inverted, with cross-start being on the right,
cross-end being on the left, the cross axis going from right to
left, with additional flex lines being added to the left of the
previously drawn line.
Now that we have a
better understanding of all these terms and dimensions, let’s get back to
the flex-wrap property.
flex-wrap Continued
The default value of nowrap prevents wrapping, so the cross-
directions just discussed aren’t relevant when there is no chance of a
second flex line. When additional lines are possible—when flex-wrap
is set to wrap or wrap-reverse—those lines will be added in the
cross direction. The first
line is placed at the cross-start, with additional lines being added on
the cross-end side.
You can invert the direction of the cross axis, adding new lines on
top or to the left, of previous lines by including
flex-wrap: wrap-reverse. In Figure 12-16, the last example
is wrap-reverse. You’ll notice the new line starts at the
main-start, but is added in the inverse direction of the cross axis
set by the flex-direction property.
In Figure 12-16, the same flex-wrap values are repeated, but with a
flex-direction: column property value instead of row. In this case,
the flex items are laid out along the vertical axis. Just as with the
row-oriented flows, if wrapping is not enabled by the
flex-wrap property—either because flex-wrap: nowrap is explicitly
set on the container, or if the property is omitted and it defaults to
nowrap—no new flex lines will be added even if that means the flex items are drawn beyond the bounding box of the flex container.
With column, just like with row, if the flex items don’t fit into
the flex container and no wrapping is allowed, they’ll overflow the flex container, unless
explicitly changed with min-width: 0 or similar, in which case they
shrink to fit, though flex items will not shrink to smaller than their
border, padding and margins combined.
When flex-flow: column wrap is set on a flex container, if there isn’t
enough room for the flex items to fit into the first column, they’ll wrap onto new lines.
The next flex item will be put on a new line in the cross-axis direction, which in this case is a
vertical line (a column) to the right of the previous line, as can be observed in
the flex-flow: column wrap example in
Figure 12-16. In that particular case, the flex
items have wrapped onto three lines. When we set flex-flow: column wrap-reverse,
the same thing happens, except the cross-start and cross-end placements are swapped, so the initial column goes on the right and subsequent columns (flex lines) are added to the left of that initial column.
As you can see, flex-direction and flex-wrap have great impact on
your layout and on each other. Because it’s generally important to set
both if you’re going to set either, we’re provided with the flex-flow
property, which the specification strongly recommends we use.
Arranging Flex Items
In our examples thus far, we’ve skated past the precise arrangement of flex items within each line, and how that’s determined. It might seem intuitive that a row fills in horizontally, but why should all the items huddle toward the main-start edge? Why not have them grow to fill all available space, or distribute themsleves throughout the line?
For an example of what we’re talking about here, check out Figure 12-17.
Notice the extra space on the top left. In this bottom-to-top,
right-to-left flow, new flex items get placed above of the
previous ones, with new wrap lines being placed to the left of each
previously filled line.
By default, no matter the values of flex-flow,
empty space beyond the flex items in a flex container will be in the direction of main-end
and cross-end…but there are properties that allow us to
alter that.
Flex Container
Thus far in our examples, when the flex items did not fill the flex
container, the flex items were all grouped toward the main-start on
the main axis. Flex items can be flush against
the main-end instead, centered, or even spaced out evenly across the main axis.
The flex layout specification provides us with flex container properties
to control the distribution of space: in addition to display and
flex-flow, the CSS Flexible Box Layout Module Level 1 properties
applied to flex containers include the justify-content,
align-content, and align-items properties.
The justify-content property controls how flex items in a flex line
are distributed along the main axis. The align-content defines how
flex lines are distributed along the cross axis of the flex container.
The align-items property defines how the flex items are distributed
along the cross axis of each of those flex lines. Let’s start by arranging flex items within flex lines.
Justifying Content
The justify-content property enables us to direct how flex items are distributed along the main axis of the flex container within each flex line. It is applied to the flex container, not the individual flex items.
The value of justify-content defines how space is distributed around, or in some cases between, the flex items inside a flex container. The effects of the six possible values are shown in Figure 12-18.
With flex-start, which is the default value, flex
items are placed flush against main-start. With flex-end, flex
items are justified toward main-end. center groups the items flush
against each other, centered in the middle of the main-dimension along
the main axis.
The space-between value puts the first flex item on a
flex line flush with main-start and the last flex item in each flex
line flush with main-end, and then puts an equal amount of space
between every pair of adjacent flex items. space-around splits up the leftover space and then applies half of each portion to each flex item, as if there were non-collapsing margins of
equal size around each item. Note that this means the space between any two flex items is twice that of the space between the first and last flex items and those at the main-start and main-end of the flex line. space-evenly takes the leftover space and splits it so that every gap is the same length. This means the spaces to the start and end edges of the main axis will be the same as the spaces placed between flex items.
justify-content affects more than just the placement within a flex line. If the items are not wrapped and overflow the flex line, then the value of justify-content influences how the flex items will overflow the flex container. This is illustrated in Figure 12-19.
Let’s take a look at the six values in slightly more detail.
Setting justify-content: flex-start explicitly sets the default
behavior of grouping the flex items toward main-start, placing the
first flex item of each flex line flush against the main-start side.
Each subsequent flex item then gets placed flush with the preceding flex
item’s main-end side, until the end of the flex line is reached if
wrapping is set. The location of the main-start side depends on the
flex direction and writing mode, which is explained in “Understanding axes”. If there isn’t
enough room for all the items, and nowrap is the default or expressly
set, the items will overflow on the main-end edge, as shown in Figure 12-20.
Setting justify-content: flex-end puts the last flex on a line flush
against the main-end with each preceding flex item being placed flush
with the subsequent item. In this case, if the items aren’t allowed to
wrap, and if there isn’t enough room for all the items, the items will
overflow on the main-start edge, as shown in
Figure 12-21. Any extra space on a flex line will be on the main-start
side.
Setting justify-content: center will pack all the items together, flush against each other at the center of each flex line instead
of at the main-start or main-end. If there isn’t enough room for all
the items and they aren’t allowed to wrap, the items will overflow
evenly on both the main-start and main-end edges, as shown in the second example in
Figure 12-22. If the flex items
wrap onto multiple lines, each line will have centered flex items, with
extra space being on the main-start and main-end edges.
Setting justify-content: space-between puts the first flex item flush
with main-start and the last flex item on the line flush with
main-end, and then puts an even amount of space around each flex item,
until the flex line is filled. Then it repeats the process with any flex
items that are wrapped onto additional flex lines. If there are three flex
items, there will be the same amount of space between the first and second items as between the second and third, but there will be no extra empty space between the main-start
edge of the container and the first item and the opposite (or main-end) edge of the container and the main-end edge of the last item, as shown in the second example
in Figure 12-23. With space-between, the first item is flush with
main-start, which is important to remember when you only have one flex
item or when your flex items overflow the flex container in a nowrap
scenario. This means, if there is only one flex item, it will be flush
with main-start, not centered, which seems counterintuitive to many
at first.
With justify-content: space-between the space between any two items on
a flex line will be equal but won’t necessarily be the same across
flex lines. When set to allow wrapping, on the last flex line, the
first flex item of that last line is flush against main-start, the
last if there are two or more on that line will be against main-end,
with equal space between adjacent pairs of flex items. As shown in the
last example of Figure 12-23, A and G, the first items on each flex line,
are flush against main-start. F and I, the last items on each line,
are flush against main-end. The flex items are evenly distributed with
the spacing between any two adjacent items being the same on each of the
lines, but the space between flex items on the first line is narrower
than the space between flex items on the second line.
Setting justify-content: space-around evenly distributes the extra
space on the line around each of the flex items, as if there were
non-collapsing margins of equal size around each element on the
main-dimension sides. So there will be twice as much space between the
first and second item as there is between main-start and the first
item, and main-end and the last item, as shown in Figure 12-24.
If the flex items wrap onto multiple lines, the space around each flex
item is based on the available space on each flex line. While the space
around each element on a flex line with be the same, it might differ
between lines, as shown in the last examples in Figure 12-24. The spaces
between A and B and between G and H are twice the width of the spaces
between the main-start edge and A and the edge and G.
If nowrap is set, and there isn’t enough room on the flex container’s
main-direction for all the flex items, the flex items will overflow
equally on both sides, similar to setting center, as shown in the
third example in Figure 12-24.
Setting justify-content: space-evenly means the user agent counts the items, adds one, and then splits any extra
space on the line by that many (i.e., if there are five items, the amount of space is split into six equal-size portions). One portion of the space is placed before each item on the line, as if it were a non-collapsing margin, and the last portion is placed after the last item on the list.
Thus, there will the same amount of space between the
first and second item as there is between main-start and the first
item, and main-end and the last item, as shown in Figure 12-25.
With the margin added to the flex items to make the examples less
hideous, this may be difficult to see. Comparing margin-free examples of
center, space-around, space-between, and space-evenly might be more helpful, so they’re shown in Figure 12-26.
Note
Space-evenly is not currently in the flexbox specification (late 2017),
but it is part of the CSS Box Alignment specification. As the flexbox
specification states it must follow the CSS Box Alignment specification,
it should make its way back into the flexbox spec soon. Plus, most
browsers already support it.
justify-content Examples
We took advantage of the default value of justify-content in
Figure 12-2, creating a left-aligned navigation bar. By changing the default value to
justify-content: flex-end, we can right-align the navigation bar in English:
nav{display:flex;justify-content:flex-start;}
Note that justify-content is applied to the flex container. If we’d applied to the links themselves, using something like nav a {justify-content: flex-start;}, there would have been no alignment effect.
A major advantage of justify-content is that when the writing direction changes, say for right-to-left writing modes, we don’t have to alter the CSS to get the tabs where they need to go. The flex items are always grouped toward main-start when flex-start is applied; in English, main-start is on the left. For Hebrew, main-start is on the right. If flex-end is applied and the flex-direction is row, then the tabs go to the right side in English, and the left side in Hebrew, as shown
in Figure 12-27.
We could have centered that navigation, as shown in Figure 12-28:
nav{display:flex;justify-content:center;}
Aligning Items
Whereas the justify-content defines how flex items are aligned along
the flex container’s main axis, the align-items property defines how
flex items are aligned along its flex line’s cross axis. As with justify-content, align-items is applied to flex containers, not individual flex items.
With the align-items property, you can align all the flex items in a container to the start,
end, or center of the cross axis of their flex lines.
align-items is similar to justify-content but has effects in
the perpendicular direction, setting the cross axis alignment for all
flex items, including anonymous flex items.
With align-items, you can set all the items to be placed
flush against the cross-start or cross-end of their flex line, or
stretched flush to both. Alternatively, you can center all the flex items in the
middle of the flex line. There
are five values, including flex-start, flex-end, center,
baseline, and the default stretch, as shown in Figure 12-29.
Note
While align-items sets the alignment for all the flex items within a
container, the align-self property
enables overriding the alignment for individual flex items, as we’ll see in an upcoming section, “The align-self Property”.
In Figure 12-29, note how the flex items either hug the cross-start
or cross-end side of the flex container, are centered, or stretch to
hug both—except for baseline.
With baseline, the flex items’ baselines are aligned: the flex item
that has the greatest distance between its baseline and its
cross-start side will be flush against the cross-start edge of the
line.
That’s the general idea—and explains non-wrapping flex
containers pretty well—but there’s more to it than that.
In the multiline align-items figures that follow, the following styles have been applied:
For each flex
line, the red line is cross-start and the blue is cross-end. The lines appear purple when a new flex line abuts the previous
flex line. C, H, D, and I have different values for top and bottom
margins. We’ve added a bit of margin to the sides of all the flex items
to make the figures more legible, which doesn’t affect the impact of the
align-items property in this case. J has the font size increased, increasing the
line height. This will come into play when we discuss the baseline
value.
The default is align-items: stretch, as shown in Figure 12-30.
stretch, as its name implies, stretches all stretchable flex items to be as tall or wide as the
tallest or widest flex item on the line. What does “stretchable” mean?
While by default flex items will stretch to take up 100% of the
cross-size, if min-height, min-width, max-height, max-width,
width, or height are set, those properties will take precedence. In other words, if an element has an explicitly set dimension along the cross axis, then it is not stretchable, and stretch will not affect its sizing.
Otherwise, the flex items’ cross-start will be
flush with the flex line’s cross-start, and the flex items’
cross-end will be flush with the flex line’s cross-end. The flex
item with the largest cross-size will remain its default size, and
the other flex items will grow to the size of that largest
flex item.
The size of the stretched flex item includes the margins on the
cross-start and cross-end sides: it is the outer edge of the flex
items’ margin that will be flush with cross-start and cross-end. This is demonstrated by items C, D, H, and I in Figure 12-31.
Their margins are the reason C, D, H, and I appear smaller than the other flex
items on their flex lines. They’re not. The outer edges of the top and
bottom margins are flush with the cross-starts and cross-ends of the
flex lines they occupy. Those flex lines are, in turn, as tall as the
tallest item on the line, or as wide as the widest item when the
cross dimension is horizontal.
Flex lines are only as tall or wide as they need to be to contain their flex
items. In the five align-items figures, the line height of the flex line containing only K is much smaller
than the other two lines.
Start, End, and Center Alignment
The values and effects of start, end, and center alignment are pretty straightforward, so we’ll take them all at once.
The flex-start value lines up each flex items’ cross-start edge
flush against the cross-start edge of their flex line. The flex item’s
cross-start edge is on the outside of the margin: if a flex item has a
margin that is greater than 0, flex item will not appear flush with the
flex line’s cross-start edge, as seen in flex item C, D, H, and I in the first example in
Figure 12-32.
Setting align-items: flex-end will align the cross-end edge of all
the flex items along the cross-end edge of the line they are in as
shown in the second example in Figure 12-32.
None of the flex items has a
bottom margin greater than 0 pixels, so unlike the other examples, this
example does not look jagged—all the flex items’ cross-end edges are visibly flush against the cross-end edge of each flex line.
As shown in the third example in Figure 12-32, setting align-items: center will center the flex items’ cross-size
along the middle point of the cross axis of the line. The center is
the midpoint between the outer edges of a flex item’s margin edges—remember, flex
item margins do not collapse. Because the cross-edge margins for C, D, H,
and I are not symmetrical, the flex items do not appear visibly centered along
the cross axis, even though they are: the halfway points between their top and bottom margin edges are exactly aligned with the midpoints of the flex lines in which they sit.
In LTR and RTL languages, in the
case of flex-direction: row and row-reverse, the aligned midpoint of a flex item is the
point halfway between its top and bottom margin edges. For
flex-direction: column, and column-reverse, the aligned midpoint of a flex item is the
point halfway between its left and right margin edges.
Note
If a flex container’s cross size is constrained, the contents may overflow
the flex container’s cross-start and/or cross-end edge. The
direction of the overflow is not determined by the align-items
property, but rather by the align-content property, discussed in an upcoming section, “Aligning Content”.
align-items aligns the flex items within the flex line and does
not directly impact the overflow direction of the flex items within
the container.
Baseline Alignment
The baseline value is a little more complicated. With baseline,
the flex items in each line are all aligned at their first baselines. The
flex item on each flex line with the biggest distance between its
baseline and its cross-start margin edge has that margin edge placed flush against the
cross-start edge of the line, and all other flex items’ baselines are
lined up with the baseline of that flex item.
Take a look at the second line in Figure 12-33, where J dominates.
The font size for J in this was was increased to 3rem in order to
create a flex item with a taller first line of text than the other flex items. Its top (cross-start) edge is placed against the top (cross-start) edge of the flex line. All the other flex items in the line we moved down until their first text line’s baseline is aligned with the first baseline of J. (The green line indicates the placement of this baseline.)
Now look at the first flex line, the one starting with A.
You’ll notice that A, B, C, D, and E are all top-aligned, but look closer.
The subtlety here is that they are not visibly flush to the top of the flex line.
This happens because D has a top margin of 20 pixels. The outer edge
of D’s top (cross-start) margin is flush against the cross-start of the flex line. As previously noted, the distance between
the cross-start line and baseline is determined by the item on the
line that has the biggest distance between its outer margin on its
cross-start side and its baseline. Therefore, D’s placement (due to its top margin) becomes the baseline against which the other items in the line are aligned.
In many cases, baseline will look like flex-start. For example, had D lacked a top margin, then all the items in that first line would have been visibly flush against the top of the flex line, just as would have happened with flex-start. Whenever the items have different margins, borders, padding, font sizes, or line heights on their cross-start side, there will be a difference between flex-start and baseline.
There is one case in which baseline literally becomes flex-start, and that’s when the baselines of the flex items are parallel to the cross axis. For example, suppose we took the flex container in Figure 12-33 and changed it to flex-direction: column. Now the cross axis, like the baselines of the English text within, is horizontal. Since there’s no way to create an offset from the cross-start edge of the columns (the left side), baseline is treated exactly as if it were flex-start instead.
Additional Notes
If you want to change the
alignment of one or more flex items, but not all, you can include the
align-self property on the flex items you would like to align
differently. The align-self takes the same values as align-items,
and is discussed in “Flex Items”.
You cannot override the alignment for anonymous flex items (non-empty
text node children of flex containers). Their align-self always
matches the value of align-items of their parent flex container.
In the align-items examples, the flex container’s cross-size was as
tall as it needed to be. No height was declared on the container, so
it defaulted to height: auto. Because of this, the flex container grew to
fit the content. You may have noticed the example flex containers were all the same height, and the flex line heights were the same across all examples.
Had the cross-size—in this case the height—been set to a specific size, there may have been extra space at cross-end, or not enough space to fit the content. Flexbox allows us to control the alignment of flex lines with the align-content property. The align-content property is the last property we need to focus on that applies to the flex container (versus the flex items). The align-content property only impacts flex line alignment in multiline flex containers.
The align-self Property
This is jumping ahead a bit, but now is the right time to talk about the align-self property. This is used to override the align-items property
value on a per-flex-item basis.
With the align-items property set on the flex container, you
align all the flex items of that container.
You can override the alignment of any individual flex item with the
align-self property. The default value of align-items is stretch, which is why all the flex items in the five examples in Figure 12-34 are all as tall as the parent, with the exception of the second flex item.
All the flex items have the align-self’s default value of auto set, meaning they inherit the alignment (in this case, stretch) from the container’s align-itemsproperty, except the second flex item in each example. That flex item has been given the align-self value shown underneath the example.
Just as with the values of the align-items property, the flex-start value places the item at the cross-start edge. flex-end places the item at the cross-end edge. center aligns the item in the middle of the cross axis. baseline aligns the baseline of the flex item with the lowst baseline in its flex line. Finally, auto and stretch both stretch the flex items, as the align-items value was allowed to default to stretch. (Similarly, align-self: inherit would cause a stretch alignment in this case.)
To learn more about the flex-start, flex-end,
center, baseline, and stretch values, see
“Aligning Items”.
Aligning Content
The align-content property aligns a flex container’s lines within a
flex container that has extra space in the cross-axis direction, and dictates which direction will have overflow when there is not enough room to fit the flex lines.
The align-content property dictates how any extra
cross-direction space in a flex container is distributed between and
around flex lines. Although the values and concepts are the same, align-content is different from the previously discussed align-items property, which
dictates flex item positioning within each flex line.
Think of align-content as similar to how justify-content aligns
individual items along the main axis of the flex container, but it does it for
flex lines with regard to the cross axis of the container. This property only
applies to multiline flex containers, having no effect on non-wrapping
and otherwise single-line flex containers.
Consider the following CSS as a base, and assume the flex items have no margins:
Figure 12-35 demonstrates the seven possible values of the align-content
property, as used in conjunction with that CSS. In each example, there are three flex lines. Each flex line’s cross-start and cross-end edges are denoted by red and blue lines, respectively. The leftover space in the flex container; that is, the space between or around the flex lines, is represented by the banded regions.
With a height of
480 pixels, the flex container is taller than the default combined heights of
the 3 flex lines. Let’s say the tallest items in each line—E, F, and K—are
150 pixels, 180 pixels, and 30 pixels, respectively, for a combined total of 360 pixels. Each
flex container has an extra 120 pixels of free space in the cross-size
direction.
With five of the align-items values, the free space is
distributed outside of the flex lines, as illustrated in
Figure 12-35. These act in the same ways the same values do for justify-content, only along the cross axis instead of the main axis (as is the case for justify-content). With
the value stretch, the extra space is evenly distributed to all the flex
lines, increasing their cross-size until their edges touch.
In the previous example, with a flex container height of 480 pixels, we have 120 pixels of “leftover” space along the
cross axis, distributed differently depending on the value of the
align-content property.
As shown in the top three examples in Figure 12-35, with
flex-start the 120 pixels is all on the cross-end side of the cross axis. With flex-end, the
extra 120 pixels of available space is all placed at the cross-start side. With
center, the lines are centered, and 60 pixels of extra space (half of 120 pixels) is placed at
cross-start and cross-end sides.
With space-between, there is 60 pixels between adjacent
pairs of flex lines. With
space-around, on the other hand, the space is evenly distributed around each line: the
120 pixels is split into 3, since there are 3 flex lines. This puts 20 pixels of non-collapsed space (half of 40 pixels) on the
cross-start and cross-end sides of each flex line, so there are 20 pixels
of extra space at the cross-start and cross-end sides of the flex
container, and 40 pixels of space between adjacent flex lines.
For space-evenly, there are four spaces to insert: one before each flex line, and an extra space after the last flex line. With three lines, that means four spaces, or 30 pixels for each space. That places 30 pixels of space at the cross-start and cross-end sides, and 30 pixels between adjecent flex lines.
The stretch value is different: with stretch the lines stretch with
the extra space evenly distributed among the flex lines rather than
between them. In this case, 40 pixels was added to each of the flex lines, causing all 3 to grow in height by an equal amount—that is, the exact same amount, not an amount proportional to each.
You’ll note in the sixth example of Figure 12-35, there is
no area within the container that is not occupied by a flex line.
stretch is the default value, as you likely want to fill all the
available space.
If there isn’t enough room for all the lines, they will overflow at
cross-start, cross-end, or both, depending on the value of the
align-content property. This is shown in Figure 12-36, where the dotted box with a light gray background represents a short flex container. (align-items: flex-start was set to make the effect of align-content more obvious.)
The only difference in the CSS
between this and
Figure 12-35 is the height of the flex container. Here, the flex containers have been reduced to a height of 240 pixels, so as to
create flex containers not tall enough to encompass all their flex lines (which, as you may recall, total 360 pixels in height).
When the flex lines overflow the flex container, align-content: flex-start,
space-between, and stretch cause them overflow the cross-end side, whereas align-content: space-around
and center evenly overflow both the cross-end and cross-start
sides. Only align-content: flex-end causes flex lines overflow just the cross-start side.
Keep in mind that these values are not top- or bottom-centric. If the cross axis goes upward, then align-content: flex-start will start aligning flex lines from the bottom and work upward from there, potentially overflowing the top (cross-end) edge. For that matter, when the flow direction is columnar, the cross axis will be horizontal, in which case the cross-start and -end edges will be the right or left edges of the flex container.
Space between, around, and evenly
It’s worth taking a closer look at, and thinking about how, space-between and space-around affect the alignment of flex lines.
When align-content: space-between is set, the flex lines are evenly
distributed in the flex container. This “even distribution” is based on
the available space, not the size of the lines.
If there is more than one flex
line, the first line will be flush against the container’s
cross-start, the last line will be flush against the container’s
cross-end, and any available extra space is distributed evenly between
the additional lines, if there are any. The extra space is distributed
evenly, not proportionally. The space between any two flex lines within
the flex container is equal, even if the cross-sizes of the multiple
flex lines differ.
Furthermore, the middle flex line, if there are an odd number of lines, is not necessarily
centered in the flex container, because the lines don’t necessarily all have the same cross
dimensions.
Note
Only flex containers with multiple lines can have free space in the
cross axis for lines to be aligned in. If there is only one line, the
align-content property will not impact the distribution of the
content. In flex containers with a single line of flex items, the lone
line stretches to fill all of the available space.
Instead, the spacing between any two adjacent lines is the
same. Assume 3 lines with 120 pixels total of free space, as we saw in the previous section. The first flex line goes against the cross-start edge, and the second flex line goes against the cross-end edge. That means there is one line to place between them, and two gaps. The 120 pixels of leftover space gets
divided equally into 2 chunks of 60 pixels each. One 60-pixel chunk is placed between the first and second flex
lines, and the other between the second and third flex lines. This is illustrated in Figure 12-37.
The space-around value distributes the lines within a multiline flex container
evenly, as if all the flex lines had equal, non-collapsing margins on
both the cross-start and cross-end sides. Because there is an equal
distribution of the extra available space around each line, the space
between the edges of the container and the first and last flex lines is
half the size of the distance between any two flex lines. The
distribution of the extra space is shown in Figure 12-37.
Note
As of late 2017, the various alignment values like flex-start, flex-end, and so on are being made more generic: start, end, and so forth. These are part of a wider effort to make CSS more aware of writing and layout directions. An example of this is the addition of properties like margin-start and padding-end. It wasn’t quite advanced enough (or well-supported enough) to merit complete coverage in this edition, but keep an eye on these developments.
We have been, for the most part, taking a look at properties of the flex container (the exception was align-self). It’s
time to take a look at the properties directly applied to flex items.
Flex Items
In the previous sections, we saw how to globally lay out all the flex
items within a flex container by styling that
container. The flexible box layout specification provides several additional
properties applicable directly to flex items. With these flex-item-specific
properties, we can more precisely control the layout of individual flex
containers’ children.
What Are Flex Items?
We create flex containers simply by adding a display: flex or
display: inline-flex to an element that has child nodes. The children
of those flex container are called flex items—whether they’re child elements,
non-empty text nodes between child elements, or generated content. Figure 12-38 shows a situation where each letter is enclosed in its own element, including the space between words, so that each letter and space becomes a flex item.
When it comes to text-node children of flex containers, if the text node
is not empty—containing content other than whitespace—it will be
wrapped in an anonymous flex item, behaving like its flex item siblings.
While these anonymous flex items do inherit all the flex properties set
by the flex container, just like their DOM node siblings, they are not
directly targetable with CSS. Therefore, we can’t directly set any of
the flex item specific properties on them. Thus, in the following markup, the two elements (the <strong> and the <em>) and the text “ they’re what’s for ” each become flex items, for a total of three flex items:
<pstyle="display: flex;"><strong>Flex items:</strong> they’re what’s for <em><br>fast!</em></p>
Generated content (via ::before and ::after) can be styled directly; therefore all the properties
discussed in this chapter apply equally to generated content as they do
to element nodes.
Whitespace-only text nodes within a flex container are ignored, as if
their display property were set to none, as the following code example shows:
In the preceding code, with the display property set to flex, the
unordered list is the flex container, and its child list items are all
flex items. These list items, being flex items, are flex-level boxes,
semantically still list items, but not list items in their presentation.
They are not block-level boxes either. Rather, they participate in their
container’s flex formatting context. The whitespace between and around the li elements—the line feeds and indenting tabs and/or spaces—is completely ignored. The links are not flex items themselves, but are descendants of the flex items the list items have become.
Flex Item Features
The margins of flex items do not collapse. The float and clear
properties don’t have an effect on flex items, and do not take a flex
item out of flow. In effect, float and clear are ignored when applied to flex items. (However, the float property can still affect box
generation by influencing the display property’s computed value.) Consider:
aside{display:flex;}img{float:left;}
<aside><!-- this is a comment --><h1>Header</h1><imgsrc="images/foo.jpg"alt="Foo Master">
Some text
</aside>
In this example, the aside is the flex container. The comment and
whitespace-only text nodes are ignored. The text node containing “some
text” is wrapped in an anonymous flex item. The header, image, and text
node containing “some text” are all flex items. Because the image is a flex
item, the float is ignored.
Even though images and text nodes are
inline-level nodes, being flex items, as long as they are not absolutely
positioned, they are blockified:
aside{display:flex;align-items:center;}
<aside><!-- a comment --><h1>Header</h1><imgsrc="images/foo.jpg"alt="foo master">
Some text <ahref="foo.html">with a link</a> and more text
</aside>
In the last example, the markup is similar to the code in the second example, with the
addition of a link within the non-empty text node. In this case, we are
creating five flex items. The comment and whitespace-only text nodes are
ignored. The header, the image, the text node before the link, the link,
and the text node after the link are all flex items. This is illustrated by Figure 12-39.
The text nodes containing “some text” and “and more text” are wrapped
in anonymous flex items, represented in Figure 12-39 by the dashed boxes (the dashes having been added for illustrative purposes) with no background. The
header, image, and link, being actual DOM nodes, can be styled directly with CSS. The anonymous flex containers are not directly targetable, and so will only have whatever styles they pick up from the flex container.
Additionally, vertical-align has no effect on a flex item, except as it affects the alignment of text within the flex item. In other words, setting vertical-align: bottom on a flex item will make the text inside the flex item all align to the bottoms of their line boxes, not push the flex item to the bottom of its container. (That’s what align-items and align-self are for.)
Absolute positioning
While float will not actually float a flex item,
setting position: absolute is a different story. The
absolutely positioned children of flex containers, just like any other
absolutely positioned element, are taken out of the flow of the
document.
More to the point, they do not participate in flex layout, and are not part of the document flow. However, they can be
impacted by the styles set on the flex container, just as a child
can be impacted by a parent element that isn’t a flex container. In addition to inheriting any inheritable properties, the flex container’s properties can affect the origin of the positioning.
The absolutely positioned child of a flex container is affected by both
the justify-content value of the flex container, and its own
align-self value, if there is one. For example, if you set
align-self: center on the absolutely positioned child, it will start out
centered with respect to the flex container parent’s cross axis. From there, it can moved by properties like top, bottom, margins, and so on.
The order property (explained in a later section, “The order property”) may not impact where the absolutely positioned flex
container child is drawn, but it does impact the order of when it is
drawn in relation to its siblings.
Minimum Widths
In Figure 12-40, you’ll note the line that is set to the nowrap default
overflows the flex container. This is because when it comes to flex
items, the implied value of min-width is auto, rather than 0.
Originally in the specification, if the items didn’t fit onto that
single main axis, they would shrink. However, the specification of
min-width was altered as applied to flex items. (Traditionally,
the default value for min-width is 0.)
If you set the min-width to a width narrower than the computed value
of auto—for example, if you declare min-width: 0—then the flex items
in the nowrap example will shrink to be narrower than their actual content (in some cases). If the items are allowed to wrap, then they will be as narrow as possible to fit their content, but no narrower. Both situations are illustrated in Figure 12-41.
Flex-Item–Specific Properties
While flex items’ alignment, order, and flexibility are to some extent
controllable via properties set on their flex container, there
are several properties that can be applied to individual flex items for
more granular control.
The flex shorthand property, along with its component properties of
flex-grow, flex-shrink, and flex-basis, controls the flexibility of
the flex items. Flexibility is the amount by which a flex item can grow or shrink along the main axis.
The flex Property
The defining aspect of flex layout is the ability to make the flex items
“flex”: altering their width or height to fill the available space in
the main dimension. A flex container distributes free space to its items
proportional to their flex grow factor, or shrinks them to prevent
overflow proportional to their flex shrink factor. (We’ll explore these concepts momentarily.)
Declaring the flex shorthand property on a flex item, or defining the
individual properties that make up the shorthand, enables authors to
define the grow and shrink factors. If there is excess space, you can
tell the flex items to grow to fill that space. Or not. If there isn’t
enough room to fit all the flex items within the flex container at their
defined or default sizes, you can tell the flex items to shrink
proportionally to fit into the space. Or not.
This is all done with the
flex property, which is a shorthand property for flex-grow,
flex-shrink, and flex-basis. While these three sub-properties can be
used separately, it is highly recommended to always use the flex
shorthand, for reasons we’ll soon cover.
The flex property specifies the components of a flexible length: the “length” of the flex item being the length of the flex item along the
main axis (see “Understanding axes”). When a box
is a flex item, flex is consulted to determine the size of the box, instead of the main-axis size dimension property (height or width).
The “components” of the flex property include the flex growth factor,
flex shrink factor, and the flex basis.
The flex basis determines how the flex growth and shrink factors are
implemented. As its name suggests, the flex-basis component of the flex
shorthand is the basis on which the flex item determines how much it can
grow to fill available space or how much it should shrink to fit all the
flex items when there isn’t enough space. It’s the initial size of each
flex item, and can be restricted to that specific size by specifying 0
for both the growth and shrink factors:
.flexItem{width:50%;flex:00200px;}
In the preceding CSS, the flex item will have a main-axis size of
exactly 200 pixels, as the flex basis is 200px, and it is allowed to neither
grow nor shrink. Assuming that the main axis is horizontal, then the value of width (50%) is ignored. Similarly, a value for height would be ignored if the main axis were vertical.
Note
This override of height and width occurs outside the cascade, so you can’t even override the flex basis by adding !important to the height or width value of a flex item.
If the target of a selector is not a flex item, applying the flex property to it will have no effect.
It is important to understand the three components that make up the
flex shorthand property in order to be able to use it effectively.
The flex-grow Property
The flex-grow property defines whether a flex item is allowed to grow
when there is available space, and, if it is allowed to grow and there
is available space, how much will it grow proportionally relative to the
growth of other flex item siblings.
Warning
Declaring the growth factor via the flex-grow property is strongly discouraged by the authors of the specification itself. Instead, declare the
growth factor as part of the flex shorthand. We’re only discussing the property here to explore how growth works.
The value of flex-grow is always a number. Negative numbers are not valid. You can use non-integers if you like, just as long as they’re zero or greater.
The value sets the flex growth factor, which determines how much the
flex item will grow relative to the rest of the flex item siblings as
the flex container’s free space is distributed.
If there is any
available space within the flex container, the space will be distributed
proportionally among the children with a nonzero positive growth factor
based on the various values of those growth factors.
For example, assume a 750px wide horizontal flex container with three
flex items, each set to width: 100px. That means there is a total of 300 pixels of space taken up by the flex items, leaving 450 pixels of “leftover” or available space (since 750 - 300 = 450). This is the first scenario shown in Figure 12-42. In that scenario, none of the flex items are permitted to grow.
In the second scenario in Figure 12-42, only one of the flex items (the third) has been given a growth factor. The declaration we gave it is flex-grow: 1, but it could be literally any positive number the browser can understand. In this case, with two items having no growth factor and the third having a growth factor, all of the available space is given to the flex item with a growth factor. Thus, the third flex item gets all 450 pixels of available space added to it, arriving at a final width of 550 pixels. The width: 100px applied to it elsewhere in the styles is overridden.
In the third and fourth scenarios, the same flex item widths result despite the differing flex growth factors. Let’s consider the third scenario, where the growth factors are 1, 1, and 3. The factors are all added together to get a total of 5. Each factor is then divided by that total to get a proportion. So here, the three values are each divided by five, yielding 0.2, 0.2, and 0.6.
These proportions are each multiplied by the available space to get the amount of growth. Thus:
450 px × 0.2 = 90 px
450 px × 0.2 = 90 px
450 px × 0.6 = 270 px
Those are the growth portions added to each flex item’s starting width of 100 pixels. Thus, the final widths are 190 pixels, 190 pixels, and 370 pixels, respectively.
The fourth scenario has the same result, because the proportions are the same. Imagine for a moment that we altered the growth factors to be 0.5, 1, and 1.5. Now the math works out such that the first flex item gets one-sixth of the available space, the second gets a third, and the third gets half. This results in the flex items’ final widths being 175, 250, and 425 pixels, respectively. Had we declared growth factors of 0.1, 0.1, and 0.3, or 25, 25, and 75, or really any combination of numbers with a 1:1:3 correspondence, the result would have been identical.
As noted in “Minimum Widths”, if no width or flex basis is set, the flex basis defaults to auto,
meaning each flex item basis is the width of its nonwrapped content.
auto is a special value: it defaults to content unless the item has a
width set on it, at which point the flex-basis becomes that width. The
auto value is discussed in “Automatic Flex Basis”. Had we not set
the width, in this example scenario, with our smallish font size, we
would had more than 450 pixels of distributable space along the main axis.
Note
The main-axis size of a flex item is impacted by the available space, the
growth factor of all the flex items, and the flex basis of the
item. We have yet to cover flex basis, but that time is coming soon!
Now let’s consider a case where the flex items have different width values, as well as different growth factors. In Figure 12-43, in the second example, we have flex items that are 100 pixels, 250 pixels, and 100 pixels wide, with growth factors of 1, 1, and 3, respectively, in a container that is 750 pixels wide. This means we have 300 pixels of extra space
to distribute among a total of 5 growth factors (since 750 - 450 = 300).
Each growth factor is therefore 60 pixels (300 ÷ 5).
This means the first and second flex items, with a flex-grow
value of 1, will each grow by 60 pixels. The last flex item will grow by 180 pixels, since its flex-grow value is 3.
To recap, the available space in the flex container, and the growth factors and final width of each flex item, are:
When flexed, the width of the flex items, based on their original width and growth factors, become:
item1 = 100px + (1 × 60px) = 160px
item2 = 250px + (1 × 60px) = 310px
item3 = 100px + (3 × 60px) = 280px
which adds up to 750 pixels.
Growth Factors and the flex Property
The flex property takes up to three values—the growth factor, shrink
factor, and basis. The first positive non-null numeric value, if there is
one, sets the growth factor (i.e., the flex-grow value).
When the growth and shrink factors are omitted in the flex value, the growth factor defaults to 1.
However, if neither flex nor flex-grow are declared, the growth factor defaults to 0. Yes, really.
Recall the second example in Figure 12-42, where the flex growth factors were 0, 0, and 1.
Because we declared a value for flex-grow only, the flex
basis was set to auto, as if we had declared:
So that means the first two flex items had no growth factor, a shrink factor, and a flex basis of auto. Had we used flex in the examples in Figure 12-42 instead of ill-advisedly using flex-grow, the flex basis in each case
would be set to 0%, as if this had been done:
This would have the result shown in Figure 12-44. Compare this to Figure 12-42 to see how things have changed (or not).
You may notice something odd in the first two scenarios: the flex basis been set to zero, and only the last flex item in the second scenario has a positive value for flex grow. Logic would seem that the widths of the 3 flex items should be 0, 0, and 750 pixels, respectively. But logic would also dictate that it makes no sense to have content overflowing its flex item if the flex container has the room for all the content, even if the basis is set to 0.
The specification authors thought of this quandary. When the flex
property declaration explicitly sets or defaults the flex-basis to 0%
and a flex item’s growth factor is 0, the length of the main axis of
the non-growing flex items will shrink to the smallest length the content
allows, or smaller. In Figure 12-44, that minimum length is the width of the widest sequence of letters, “flex:” (including the colon).
As long as a flex item has a visible overflow and no explicitly set value for
min-width (or min-height for vertical main-axes), the minimum width (or
minimum height) will be the smallest width (or height) that the flex item
needs to be to fit the content or the declared width (or height),
whichever is smaller.
If all items are allowed to grow, and the flex basis for each flex item
is 0%, then all of the space, rather than just excess
space, is distributed proportionally based on the growth factors.
In the third example in Figure 12-44,
two flex items have growth factors of one, and one flex item has a growth factor of three. We thus have a total of five growth factors:
(2 × 1) + (1 × 3) = 5
With 5 growth factors, and a total of 750 pixels, each growth factor is worth 150 pixels:
750px ÷ 5 = 150px
While the default flex item size was 100 pixels, the flex basis of 0% overrides that, leaving us with 2 flex items at 150 pixels each and the last flex item with a width of 450 pixels:
1 × 150px = 150px
3 × 150px = 450px
Similarly, in the last example of Figure 12-44, with two flex items having
growth factors of 0.5, and one flex item having a growth factor of 1.5,
we have a total of 2.5 growth factors:
(2 × 0.5) + (1 × 1.5) = 2.5
With 2.5 grows factors, and a total of 750 pixels, each growth factor is
worth 300 pixels:
750px ÷ 2.5 = 300px
While the default flex item size was 100 pixels, the flex basis of 0%
overrides that, leaving us with 2 flex items at 150 pixels each and the
last flex item with a width of 450 pixels:
0.5 × 300px = 150px
1.5 × 300px = 450px
Again, this is different from declaring only flex-grow, because that means the flex basis defaults to auto. In that case, only the extra space, not all the space, is distributed
proportionally. When using flex, on the other hand, the flex basis is set to 0%, so the flex items grow in proportion to the total space, not just the leftover space. The difference is illustrated in Figure 12-45.
Now let’s talk about flex
shrinking factors, which are in some ways the inverse of flex growth factors, but are in other ways different.
The flex-shrink Property
The <flex-shrink> portion of the flex shorthand property specifies the
flex shrink factor. It can also be set via the flex-shrink property.
Warning
Declaring the shrink factor via the flex-shrink property is strongly discouraged by the authors of the specification itself. Instead, declare the
shrink factor as part of the flex shorthand. We’re only discussing the property here in order to explore how shrinking works.
The shrink factor determines how much a flex item
will shrink relative to the rest of its flex-item siblings when there
isn’t enough space for them all to fit, as defined by their content and
other CSS properties. When omitted in the shorthand flex property value or when both flex
and flex-shrink are omitted, the shrink factor defaults to 1. Like the
growth factor, the value of flex-shrink is always a number. Negative numbers are not valid. You can use non-integer values if you like, just as long as they’re greater than zero.
Basically, the shrink factor defines how
“negative available space” is distributed when there isn’t enough room for the flex items and the flex container isn’t allowed to
otherwise grow or wrap. This is illustrated in Figure 12-46.
Figure 12-46 is similar to Figure 12-42, except the
flex items are set to width: 300px instead of 100 pixels. We still have a 750-pixels-wide flex
container. The total width of the 3
items is 900 pixels, meaning the content starts out 150 pixels wider than the parent flex
container. If the items are not allowed to shrink or
wrap (see “Wrapping Flex Lines”), they will burst out from the
fixed-size flex container. This is demonstrated in the first example in
Figure 12-46: those items will not shrink because they have a zero shrink factor.
Instead, they overflow the flex container.
In the second example in Figure 12-46, only the last flex item is set to be
able to shrink.
The last flex item is thus forced to do all the shrinking necessary to enable all the flex items to
fit within the flex container. With 900 pixels worth of content needing to fit
into our 750-pixel container, we have 150 pixels of negative available space. The 2 flex items with no shrink factor stay at 300 pixels wide. The third flex item,
with a positive value for the shrink factor, shrinks 150
pixels, to end up 150 pixels wide. This enables the 3 items to fit within the
container. (In this example the shrink factor was 1, but had it been
0.001 or 100 or 314159.65 or any other positive number the browser could understand, the result would be the same.)
In the third example, we have positive shrink factors for all three
flex items:
As this is the only one of the three flex shorthand properties we declared, this means the flex items will behave as if we had declared the following:
#example3flex-item{flex:01auto;/* growth defaults to 0, basis to auto */}f#example3flex-item:last-child{flex:03auto;}
If all items are allowed to shrink, as is the case here, the shrinking
is distributed proportionally based on the shrink factors.
This means the larger a flex item’s shrink factor, as compared to the shrink factors of its sibling flex items, the more the item will shrink in comparison.
With a parent
750 pixels wide, and 3 flex items with a width of 300 pixels, there are 150
“negative space” pixels that need to be shaved off the flex items that are
allowed to shrink (which is all of them in this example).
With two flex items having a shrink factor of 1, and
one flex item having a shrink factor of 3, we have a total of five
shrink factors:
(2 × 1) + (1 × 3) = 5
With 5 shrink factors, and a total of 150 pixels needing to be shaved off all
the flex items, each shrink factor is worth 30 pixels:
150px ÷ 5 = 30px
The default flex item size was 300 pixels, leading us to have 2 flex items
with a width of 270 pixels each and the last flex item having a width of
210 pixels, which totals 750 pixels:
300px - (1 × 30px) = 270px
300px - (3 × 30px) = 210px
The following CSS produces the same outcome: while the numeric representation of the shrink factors are
different, they are proportionally the same, so the flex item widths will be the same:
Note that the flex items in these examples will shrink to 210, 210, and 270 pixels, respectively, as
long as the content (like media objects or non-wrappable text) within
each flex item is not wider than 210, 210, or 270 pixels, respectively.
If the flex item contains content that cannot
wrap or otherwise shrink in the main-dimension, the flex item will not
shrink any further.
Suppose that the first flex items contain a 300-pixels-wide image.
That first flex item can not shrink, and
other flex items can shrink, therefore it will not shrink, as if it had
a null shrink factor.
In this case, the first item would be 300 pixels, with the 150 pixels of negative
space distributed proportionally based on the shrink factors of the
second and third flex items.
That being the case, we have 4 unimpeded shrink factors (one from the second flex item, and three from the third) for 150 pixels of
negative space, with each shrink factor being worth 37.5 pixels. The flex
items will end up 300, 262.5, and 187.5 pixels respectively, for a total of 750 pixels. The result is illustrated in Figure 12-47:
item1 = 300px - (0 × 37.5px) = 300.0px
item2 = 300px - (1 × 37.5px) = 262.5px
item3 = 300px - (3 × 37.5px) = 187.5px
Had the image been 296 pixels wide, that first
flex item would have been able to shrink by 4 pixels. The remaining 146 pixels of negative space
would then be distributed the among the 4 remaining shrink, yielding 36.5 pixels per factor.
The flex items would then be 296, 263.5, and 190.5 pixels wide, respectively.
If all three flex items contained non-wrappable text or media 300 pixels or
wider, the none of the three flex items would not shrink, appearing similar to the
first example in Figure 12-46.
Proportional Shrinkage Based on Width and Shrink Factor
The preceding code examples were fairly simple because all the flex items started with the same
width. But what if the widths were different? What if the first and last
flex items had a width of 250 pixels and the middle flex item had a width of
500 pixels, as shown in Figure 12-48?
Flex items shrink proportionally relative to both the shrink factor and
the flex item’s width, with the width often being the width of the flex item’s content with no wrapping. In Figure 12-48, we are trying to fit 1,000 pixels into a
750 pixels-width flex container. We have an excess of 250 pixels to be removed from
5 shrink factors.
If this were a flex-grow situation, we would simply
divide 250 pixels by 5, allocating 50 pixels per growth factor.
If we were to shrink that way, we would get flex items 200, 550, and 100 pixels
wide, respectively. But that’s not how shrinking actually works.
Here, we have 250 pixels of negative space to proportionally distribute. To get the
shrink factor proportions, we divide the negative space by the total of the flex items’ widths (more precisely, their lengths along the main axis) times their shrink factors:
Using this equation, we find the shrink percentage:
When we reduce each flex item by 16.67% times the value of flex-shrink, we end up with flex items that are reduced by:
item1 = 250px × (1 × 16.67%) = 41.67px
item2 = 500px × (1 × 16.67%) = 83.33px
item3 = 250px × (3 × 16.67%) = 125px
Each reduction is then subtracted from the starting sizes of 250, 500, and 250 pixels, respectively. We thus end up with flex items that are 208.33, 416.67, and 125 pixels wide.
Differing Bases
With zero shrink factor, if both the width and flex basis of a flex item
at auto, its content will not wrap, even when you think it should.
Conversely, any positive shrink value enables content to wrap.
Because shrinking is proportional based on shrink factor, if all the flex items have similar shrink factors, the content should wrap over a similar number of lines.
In the three examples shown in
Figure 12-49, the flex items do not have a declared width. Therefore, the width
is based on the content, because width defaults to auto. The flex container has been made 520 pixels wide, instead of of our usual 750 pixels.
Note that in the first example, where all the items have the same flex-shrink value, all content wraps over four lines.
In the second example, the first flex item has a shrink factor half of
value of the other flex items, so it wraps the content over (roughly) half the number of lines. This is the power of the shrink factor.
In the third example, with no shrink factor, the text doesn’t wrap at all and the flex items overflow the container by quite a bit.
Warning
As of late 2017, this “line-balancing” and refusal-to-wrap behavior was not consistent across browsers. If you see different results when trying this out for yourself, that may be why.
Because the flex property’s shrink factor reduces the width of flex
items proportionally, the number of lines of text in the flex items will
grow or shrink as the width shrinks or grows, leading to similar height
content within sibling flex items when the shrink factors are similar.
In the examples, take the contents of the flex items to be 280,
995, and 480 pixels, respectively—which is the width of the non-wrapping flex items in the third example (as measured by the developer tools, then rounded
to make this example a little simpler). This means we have to fit
1,755 pixels of content into a 520 pixels-wide flex container by shrinking the
flex items proportionally based on their shrink factor. This means we
have 1,235 pixels of negative available space to proportionally distribute.
Note
Remember that you can’t rely on web inspector tools to figure out shrink
factors for production. We’re going through this exercise to understand how
shrink factors work. If minutia isn’t your thing, feel free to jump to
“The flex-basis Property”.
In our first example, the flex items will end up
with the same, or approximately the same, number of text lines. This is
because flex items shrink proportionally, based on the width of their content.
We didn’t declare any widths, and therefore can’t simply use an explicit element width as the basis for our calculations, as we did in the previous examples. Rather, we distribute the
1,235 pixels of negative space proportionally based on the widths of the
content—280, 995, and 480 pixels, respectively. We determine 520 is
29.63% of 1,755. To determine the width of each flex item with a shrink
factor of 1, we multiply the content width of each flex item by 29.63%:
item1 = 280px × 29.63% = 83px
item2 = 995px × 29.63% = 295px
item3 = 480px × 29.63% = 142px
With the default of align-items: stretch (see “Aligning Items”),
a three-column layout will have three columns of equal height.
By using a consistent shrink factor for all flex items, you can indicate that
the actual content of these three flex items should be of approximately equal height—though,
by doing this, the widths of those columns will not necessarily be uniform.
In the second example in Figure 12-49, the flex items don’t all have the same shrink
factor. The first flex item will, proportionally, shrink half as much as
the others.
We start with the same widths: 280, 995, and 480 pixels,
respectively, but their shrink factors are 0.5, 1.0, and 1.0.
As we know the widths of the content, the shrink factor (X) can be found
mathematically:
We can find the final widths now that we know the shrink factor. If the
shrink factor is 76.47%, it means that item2 and item3 will be shrink by that amount, whereas item1 will shrink by 38.23% (because its flex-shrink value is half the others). The amount of shrinkage in each case is, rounded off to the nearest whole number:
item1 = 280px × 0.3823 = 107px
item2 = 995px × 0.7647 = 761px
item3 = 480px × 0.7647 = 367px
Thus, the final widths of the flex items is:
item1 = 280px - 107px = 173px
item2 = 995px - 761px = 234px
item3 = 480px - 367px = 113px
The total combined widths of these 3 flex items is 520 pixels.
Adding in varying shrink and growth factors makes it all a little less
intuitive. That’s why you likely want to always declare the flex
shorthand, preferably with a width or basis set for each flex item.
If this doesn’t make sense yet, don’t worry; we’ll cover a few more
examples of shrinking as we discuss flex-basis.
Responsive Flexing
Allowing flex items to shrink proportionally like this allows for
responsive objects and layouts that can shrink proportionally without
breaking.
For example, you can create a three-column layout that smartly grows
and shrinks without media queries, as shown on a wide screen in Figure 12-50 and narrow screen in Figure 12-51:
In this example, if the viewport is greater than 1,000 pixels, only the middle
column grows because only the middle column was provided with a positive growth factor. We also dictated that below the 1,000-pixels-wide mark, the columns all shrink.
Let’s take it bit by bit. The nav and aside elements have the following CSS:
flex:01200px;min-width:150px;
This means they don’t grow from their basis, but they can shrink at equal rates. This means they’ll have the width of their flex basis by default. If they do need to shrink, they’ll shrink down to a minimum width of 150px and then stop shrinking. However, if either one has an element that’s more than 150 pixels wide, whether it’s an image or a run of text, it will stop shrinking as soon as it reaches the width of that bit of content. Suppose a 180-pixel image got dropped into the aside element. It would stop shrinking as soon as it reached 180 pixels wide. The nav would keep shrinking down to 150 pixels.
The main element, on the other hand, has these styles:
flex:12600px;
Thus, the main element can grow if there’s space for it to do so. Since it’s the only flex item that can grow, it gets all the growth. That means that, given a browser window 1,300 pixels wide, the two side columns will be 200 pixels wide each, leaving 900 pixels of width for the center column. In shrinking situations, the center column will shrink twice as fast as the other two elements. Thus, if the browser window is 900 pixels wide, the side columns will each be 175 pixels wide, and the center column 550 pixels wide.
Once the windows reaches 800 pixels wide, the side columns will reach their min-width values of 150px. From then on, any narrowing will all be taken up by the center column.
Just to be clear, you are not require to use pixels in these situation. You don’t even have to use the same unit measures for various flex bases. The previous example could be rewritten like this:
We won’t go through all the math here, but the general approach is to set flex bases on character widths for improved readability, with some lower limits based on character widths and others on viewport width.
Note
Flexbox can be useful for one-dimensional page layout like the one shown in this section, where there are only three columns in a line. For anything more complex, or for a more powerful set of options, use Grid layout. (See Chapter 13.)
The flex-basis Property
As we’ve already seen, a flex item’s size is impacted by its content and
box-model properties and can be reset via the three components of the
flex property. The <flex-basis> component of the flex property
defines the initial or default size of flex items, before extra or
negative space is distributed—before the flex items are allowed to
grow or shrink according to the growth and shrink factors. It can also be set via the flex-basis property.
Warning
Declaring the flex basis via the flex-basis property is strongly discouraged by the authors of the specification itself. Instead, declare the
flex basis as part of the flex shorthand. We’re only discussing the property here in order to explore flex basis.
The flex basis determines the size of a flex item’s element box, as set by
box-sizing. By default, when a block-level element is not a flex item,
the size is determined by the size of its parent, content, and box-model
properties. When no size properties are explicitly declared or
inherited, the size defaults to its individual content, border, and
padding, which is 100% of the width of its parent for block-level
elements.
The flex basis can be defined using the same length value types as the
width and height properties; for example, 5vw, 12%, and 300px.
The universal keyword initial resets the flex basis to the initial value of auto, so you might as well declare auto.
In turn, auto evaluates to the width (or height), if declared. If the value of width (or height) is set to auto, then the value of flex-basis is evaluated to content.
The content Keyword
The content keyword is
not supported in most browsers at the time of this writing (late 2017), with the exception of Microsoft Edge 12+, but is equal to the width or height of the content. When content is used and supported, the basis is the size of the flex item’s content; that is, the length of the main-axis size of the longest line of content or widest (or tallest) media object.
Until support is complete, flex-basis: content; can be easily
polyfilled, as it is the equivalent of declaring
flex-basis: auto; width: auto; on that flex item, or
flex-basis: auto; height: auto; if the main-dimension is vertical.
Unfortunately, using content in the flex shorthand in nonsupporting
browsers invalidates the entire declaration (see “Understanding axes”).
The value of content is basically what we saw in the third example in
Figure 12-49, and is shown in Figure 12-52.
In the first and third examples in Figure 12-52, the width of the flex item
is the size of the content; and the flex basis is that same size. In the
first example, the flex items’ width and basis are approximately 132 pixels.
The total width of the 3 flex items side by side is 396 pixels, fitting
easily into the parent container.
In the third example, we have set a null shrink factor (0): this means the
flex items cannot shrink, so they won’t shrink or wrap to fit into the
fixed-width flex container. Rather, they are the width of their
nonwrapped text. That width is also the value of the flex basis. The flex
items’ width and basis are approximately 309, 1,037 pixels, and 523 pixels, respectively. You can’t see the full width of the second flex item or the third flex item at all, but they’re in the chapter files.
The second example contains the same content as the third example, but
the flex items are defaulting to a shrink factor of 1, so the text in this
example wraps because the flex items can shrink. Thus, while the width of
the flex item is not the width of the content, the flex basis—the
basis by which it will proportionally shrink—is the width of the
items’ contents.
Automatic Flex Basis
When set to auto, whether explicitly or by default,
flex-basis is the same as the main-axis size of
the element, had the element not been turned into a flex item. For length
values, flex-basis resolves to the width or height value, with
the exception that when the value of the width or height is auto,
the flex basis value falls back to content.
When the flex basis is auto, and all the flex items can fit within the parent
flex container, the flex items will be their pre-flexed size.
If the flex items don’t fit into their parent flex container, the flex items
within that container will shrink proportionally based on their
non-flexed main-axis sizes (unless the shrink factor is zero).
When there are no other properties setting the main-axis size of the flex items
(that is, there’s no width or even min-width set on these flex items), and
flex-basis: auto or flex: 0 1 auto is set, the flex items will
only be as wide as they need to be for the content to fit, as seen in the
first example in Figure 12-53. In this case, they are the width of the text
“flex-basis: auto;”, which is approximately
110 pixels. The flex items are their pre-flexed size, as if set to
display: inline-block. In this example, they’re grouped at
main-start because
the flex
container’s justify-content defaults to flex-start.
In the second example in Figure 12-53, each of the flex items has flex basis
of auto and an explicitly declared width. The main-axis size of the elements, had they
not been turned into flex items, would be 100, 150, and 200 pixels, respectively. And so they are here, since they fit into the flex container without any overflow along the main axis.
In the third example in Figure 12-53, each of the flex items has flex basis
of auto and a very large explicitly declared width. The main-axis size of the elements, had they
not been turned into flex items, would be 2,000, 3,000, and 4,000 pixels, respectively. Since they could not possibly fit into the flex container without overflowing along the main axis, and their flex shrink factors have all defaulted to 1, they shrink until they fit into the flex container. You can do the math to find out how big they are using the process outlined in a previous section; as a hint, the third flex item should be reduced from four thousand pixels down to a width of 240 pixels.
Default Values
When neither a flex-basis nor a flex is set, the flex item’s main-axis size is
the pre-flex size of the item, as their default value is auto.
In Figure 12-54, two things are happening: the flex bases are defaulting to auto, the growth factor is defaulting to 0, and the shrink factor of each item is defaulting to 1.
For each flex item, the flex basis is their individual width value. That
means the flex bases are being set to the values of the width properties:
100, 200, and 300 pixels in the first example, and 200, 400, and 200 pixels
in the second example.
As the combined widths of the flex items are 600 pixels and 800 pixels, respectively, both of which are both greater than the main-axis size of the 540-pixel-wide containers, they are all shrinking proportionally to fit.
In the first example, we are trying to fit 600 pixels in 540 pixels, so each flex item will shrink by 10% to yield flex items that are 90, 180, and 270 pixels wide. In the second example, we are trying to fit 800 pixels into 540 pixels, so they all shrink 32.5%, making the flex items’ widths 135, 270, and 135 pixels.
Length Units
In the previous examples, the auto flex bases defaulted to the declared widths of
the various flex items. There are other options; for example, we can use the same length units for our
flex-basis value as we do for width and height.
When there are both flex-basis and width (or height, for vertical main axes) values, the basis trumps the
width (or height). Let’s add bases values to the first example from
Figure 12-54. The flex items include the
following CSS:
The widths are overridden by the bases. The flex items shrink down to
270 pixels, 180 pixels, and 90 pixels, respectively. Had the container not had a constrained width, the flex items would have been 300 pixels, 200 pixels, and 100 pixels, respectively.
While the declared flex basis can override the main-axis size of flex items, the
size can be affected by other properties, such as min-width,
min-height, max-width, and max-height. These are not ignored. Thus, for example, an element might have flex-basis: 100px and min-width: 500px. The minimum width of 500px will be respected, even though the flex basis is smaller.
Percentage units
Percentage values for flex-basis are calculated relative to the size of the main
dimension of the flex container.
We’ve already seen the first example in Figure 12-56; it’s included here
to recall that the width of the text “flex-basis: auto” in this case is approximately 110 pixels wide. In
this case only, declaring flex-basis: auto looks the same as writing flex-basis: 110px:
In the second example in Figure 12-56, the first two flex items have a flex basis of
auto with a default width of auto, which is as if their flex basis were set to content. As we’ve noted previously, the flex-basis of the first 2 items ends up being the equivalent of 110 pixels, as the content in this case happens to be 110 pixels wide.
The last item has its flex-basis set to 100%.
The percentage value is relative to the parent, which is 540 pixels.
The third flex item, with a basis of 100%, is not
the only flex item within the non-wrapping flex container. Thus, it will not
grow to be 100% of the width of the parent flex container unless its
shrink factor is set with a null shrink factor, meaning it can’t shrink, or if it contains non-wrappable content that is as wide or wider than the parent
container.
Tip
Remember: when the flex basis is a percent value, the main-axis size is
relative to the parent, which is the flex container.
With our 3 flex bases, if the content is indeed 110 pixels wide, and the container is 540 pixels wide (ignoring other box-model properties for simplicity’s sake), we have a total of 760 pixels to fit in a 540-pixel space. Thus we have 220 pixels of negative space to distribute proportionally. The shrink factor is:
Shrink factor = 220px ÷ 760px = 28.95%
Each flex item will be shrunk by 28.95%, becoming 71.05% of the width
they would have been had they not been allowed to shrink. We can figure
the final widths:
item1 = 110px × 71.05% = 78.16px
item2 = 110px × 71.05% = 78.16px
item3 = 540px × 71.05% = 383.68px
These numbers hold true as long as the flex items can be that small; that is, as long as none of the flex items contain media or nonbreaking text wider than 78.16 pixels or 383.68 pixels. This is the widest these flex items will be as long as the content can wrap to be that width or narrower. We say “widest” because if one of the other two flex items can’t shrink to be as narrow as this value, they’ll have to absorb some of that negative space.
In the third example in Figure 12-56, the flex-basis: auto item wraps over three lines. The CSS for this example is the equivalent of:
We declared the flex-basis of the 3 flex items to be 70%,
auto, and 80%, respectively. Remembering that in our scenario auto is the width of the non-wrapping content, which in this case is approximately 110 pixels, and our flex container is 540 pixels, the bases are
equivalent to:
item1 = 70% × 540px = 378px
item2 = widthOfText(“flex-basis: auto”) = 110px
item3 = 80% × 540px = 432px
When we add the widths of these 3 flex items’ bases, they have total combined width of 920 pixels, which needs to fit into a flex container 540 pixels wide. Thus we have 380 pixels of negative space to remove proportionally among the 3 flex items. To figure out the ratio, we divide the available width of our flex container by the sum of widths of the flex items that they would have if they couldn’t shrink:
Proportional Width = 540px ÷ 920px = 0.587
Because the shrink factors are all the same, this is fairly simple. Each
item will be 58.7% of the width it would be if it had no flex item
siblings:
item1 = 378px × 58.7% = 221.8px
item2 = 110px × 58.7% = 64.6px
item3 = 432px × 58.7% = 253.6px
What happens when the container is a different width? Say, 1,000 pixels? The
flex basis would be 700 pixels (70% × 1,000 pixels), 110 pixels, and 800 pixels (80% × 1,000 pixels),
respectively, for a total of 1,610 pixels:
Proportional Width = 1000px ÷ 1610px = 0.6211
item1 = 700px × 62.11% = 434.8px
item2 = 110px × 62.11% = 68.3px
item3 = 800px × 62.11% = 496.9px
Because with a basis of 70% and 80%, the combined bases of the flex items will always be wider than 100%, no matter how wide we make the parent, all 3 items will always shrink.
If the first flex item can’t shrink for some reason—whether due to unshrinkable content, or another bit of CSS setting its flex-shrink to 0— it will be 70% of the width of the parent—378 pixels in this case.
The other 2 flex items must shrink proportionally to fit into the remaining 30%, or
162 pixels. In this case, we expect widths to be 378 pixels, 32.875 pixels, and
129.125 pixels. As the text “basis:” is wider than that—assume 42 pixels—we get 378 pixels, 42 pixels, and 120 pixels. This result is shown in Figure 12-57.
Testing this out on your device will likely have slightly different
results, as the width of the text “flex-basis: auto” may not be the same
for you, depending on the font that actually gets used to render the text. (We used Myriad Pro, with fallbacks to Helvetica and any generic sans-serif font.)
Zero Basis
If neither the flex-basis property nor the flex shorthand is
included at all, the flex basis defaults to auto. When the flex property is
included, but the flex basis component of the shorthand is omitted from the
shorthand, the basis defaults to 0. While on the surface you
might think the two values of auto and 0 are similar, the 0
value is actually very different, and may not be what you expect.
In the case of flex-basis: auto, the basis is the main size of the flex items’ contents. If the basis of each of the flex items is 0, the “available” space is the main-axis size of the entire flex container. In either case, the “available” space is distributed proportionally, based on the growth factors of each flex item.
In the case of a basis of 0, the size of the flex container is divided up and distributed proportionally to each flex item based on their growth factors—their default original main-axis size as defined by height, width, or content, is not taken into account, though min-width, max-width, min-height, and max-height do impact the flexed size.
As shown in Figure 12-58, when the basis is auto, it is just the extra space that is divided up proportionally and added to each flex item set to grow. Again, assuming the width of the text “flex: X X auto” is 110 pixels, in the first examples we have 210 pixels to distribute among 6 growth factors, or 35 pixels per growth factor. The flex items are 180, 145, and 215 pixels wide, respectively.
In the second example, when the basis is 0, all 540 pixels of the width is distributable space. With 540 pixels of distributable space between 6 growth factors, each growth factor is worth 90 pixels. The flex items are 180, 90, and 270 pixels wide, respectively. While the middle flex item is 90 pixels wide, the content in this example is narrower than 110 pixels, so the flex item didn’t wrap.
The flex Shorthand
Now that we have a fuller understanding of the properties that make up
the flex shorthand, remember: always use the flex shorthand.
It accepts the usual global property values, including initial, auto, none; and the use of an integer, usually 1, meaning the flex item can grow.
Let’s go over all these values.
Common Flex Values
The common flex values are four flex values providing the most
commonly desired effects:
flex: initial
This value sizes flex items based on the width or height property, depending on the main-axis direction, while allowing shrinking.
flex: auto
This flex value also sizes flex items based on the width or height property, but makes them fully flexible, allowing both shrinking and growing.
flex: none
This value again sizes flex items based on the width or height property, but makes them completely inflexible: they can’t shrink or grow.
flex:<number>
This value sets the flex item’s growth factor to the <number> provided. It thus sets the shrink factor to 0, and the basis to 0 as well. This means the width or height value acts as a minimum size, but the flex item will grow if there is room to do so.
Let‘s consider each of these in turn.
Flexing with initial
initial is a global CSS keyword, which means initial can be used on all properties to represent a property’s initial value; that is, its specification default value. Thus, the following lines are equivalent:
flex:initial;flex:01auto;
Declaring flex: initial sets a null growth factor, a shrink factor of
1, and sets the flex bases to auto. In Figure 12-59, we can see the
effect of the auto flex bases. In the first two examples, the basis of each flex item is content—with each flex item having the width of the single line of
letters that make up their content. In the last 2
examples, the flex bases of all the items are equal at 50 pixels, since
width: 50px has been applied to all the flex items. The flex: initial
declaration sets the flex-basis to auto, which we previously saw is the value of the width (or height), if declared, or content if not declared.
In the first and third examples in Figure 12-59, we see that when the flex
container is too small to fit all the flex items at their default
main-axis size, the flex items shrink so that all the flex items fit within the parent flex container. In these examples, the combined flex bases of all the flex items is greater than the main-axis size of the flex container. In the first example, the width of teach flex item varies based on the width of each item’s content and its ability to shrink. They all shrink proportionally based on their shrink factor, but not narrower than their widest content. In the third example, with each flex item’s flex-basis being 50 pixels (due to the value of width), all the items shrink equally.
Flex items, by default, are grouped at main start, as flex-start is
the default value of for the justify-content property. This is only
noticeable when the combined main-axis sizes of the flex items in a flex line are smaller than the main-axis size of the flex container, and none of the flex items are able to grow.
Flexing with auto
flex: auto is similar to flex: initial, but makes the flex items
flexible in both directions: they’ll shrink if there isn’t enough room
to fit all the items within the container, and they’ll grow to take up
all the extra space within the container if there is distributable
space. The flex items absorb any free space along the main axis.
The following two statements are equivalent:
flex:auto;flex:11auto;
A variety of scenarios using auto flexing are shown in Figure 12-60.
The first and third examples of Figure 12-60 are identical to
the examples in Figure 12-59, as the shrinking and bases are the same.
However, the second and fourth examples are different. This is because when
flex: auto is set, the growth factor is 1, and the flex items therefore can grow to incorporate all the extra available space.
Preventing flexing with none
Any flex: none flex items are inflexible: they can neither
shrink nor grow.
The following two lines of CSS are equivalent:
As demonstrated in the first and third examples of Figure 12-61, if there
isn’t enough space, the flex items overflow the flex container. This is
different from flex: initial and flex: auto, which both set a
positive shrink factor.
The basis resolves to auto, meaning each flex item’s main-axis size is determined by the main-axis size of the element had it not been turned into a flex item. The flex-basis resolves to the width or height value of the element. If that value is auto, the basis becomes the main-axis size of the content. In the first two examples, the basis—and the width, since there is no growing or shrinking—is the width of the content. In the third and fourth examples, the width and basis are all 50 pixels, because that’s the value of the width property applied to them.
Numeric flexing
When the value of the flex property is a single, positive numeric value, that value will be used for the growth factor, while the shrink factor will default to 1 and the basis will default to 0.
The following two CSS declarations are equivalent:
flex:3;flex:310;
This makes
the flex item on which it is set flexible: it can grow. The shrink
factor is actually moot: the flex basis is set to 0, so the flex item can only grow from that basis.
In the first two examples in Figure 12-62, all the flex items have a flex growth factor of 3. The flex basis is 0, so they don’t “shrink”; they just grew equally from zero pixels wide until the sum of their main-axis sizes grew to fill the container along the main axis. With all the flex items having a basis of 0, 100% of the main dimension is distributable space. The main-axis size of the flex items are wider in this second example because the wider flex container has more distributable space.
Any numeric value that is greater than 0, even 0.1, means the flex item
can grow. When there is available space to
grow, if only one flex item has a positive growth factor, that item will
take up all the available space. If there are multiple flex items that can grow, the
available extra space will be distributed proportionally to each flex
item based on to their growth factor.
In the last three examples of Figure 12-62, there are six flex items with
flex: 0, flex: 1, flex: 2, flex: 3, flex: 4, and flex: 5
declared, respectively. These are the growth factors for the flex
items, with each having a shrink factor of 1 and a flex basis of 0. The main-axis size of each is proportional to the specified flex growth factor. You might assume that the flex: 0 item with the text “flex: 0” in the third and fourth examples will be zero pixels wide, like in the fourth and fifth examples—but, by default, flex items won’t shrink below the length of the longest word or fixed-size element.
Note
A bit of padding, margins, and borders were added in the figures to make the visuals more pleasing. For this reason, the leftmost flex item, with flex: 0 declared, is visible: it has a one-pixel border making it visible, even though it’s zero pixels wide.
The order property
Flex items are, by default, displayed and laid out in the same order as
they appear in the source code. The order of flex items and flex lines can be reversed with flex-direction, but sometimes you want a little more complicated rearrangment. The order property can be used to
change the ordering of individual flex items.
By default, all flex items are assigned the order of 0, with the flex
items all assigned to the same ordinal group and displayed in the same order as their source order, along the
direction of the main axis. (This has been the case for all the examples seen throughout this chapter.)
To change the visual order of a flex item, set the order property
value to a nonzero integer. Setting the order property on elements
that are not children of a flex container has no effect on such elements.
The value of the order property specifies an ordinal group to which the flex
item belongs. Any flex items with a negative value will appear to
come before those defaulting to 0 when drawn to the page, and all the
flex items with a positive value will appear to come after those
defaulting to 0. While visually altered, the source order remains the
same. Screen readers and tabbing order remains as defined by the source
order of the HTML.
For example, if you have a group of 12 items, and you want the 7th
to come first and the 6th to be last, you would declare:
In this scenario, we are explicitly setting the order for the sixth and
seventh list items, while the other list items are defaulting to order: 0. The result is shown in Figure 12-63.
The seventh flex item is the first to be laid out, due to the
negative value of the order property, which is less
than the default 0, and is also the lowest value of any of its sibling flex
items. The sixth flex item is the only item with a value greater than zero, and
therefore has the highest order value out of all of its siblings. This is why it’s laid out after all the other flex items.
All the other items, all having the default
order of 0, are drawn between those first and last
items, in the same order as their source order, since they are all
members of the same ordinal group (0).
The flex container lays out its content in order-modified document
order, starting from the lowest numbered ordinal group and going up.
When you have multiple flex items having the same value for the order
property, the items share an ordinal group. The items in each ordinal group
will appear in source order, with the group appearing in numeric order, from lowest to highest. Consider the following:
By setting the same order value to more than one flex item, the items
will appear by ordinal group, and by source order within each individual
ordinal group. This has the result shown in Figure 12-64.
Here’s what happened:
Items 2, 5, 8, and 11 were selected to share ordinal group 3, and get a 20% opaque background.
Items 1, 4, 7, and 10 were selected to share ordinal group -1, and get a 40% opaque background.
Items 3, 6, 9, and 12 were not selected at all. They default to the ordinal group 0.
The three ordinal groups, then, are -1, 0, and 3. The groups are arranged in that order. Within each group, the items are arranged by source order.
This reordering is purely visual. Screen readers
should read the document as it appeared in the source code, though they may not. As a visual
change, ordering flex items impacts the painting order of the page: the
painting order of the flex items is the order in which they appear, as
if they were reordered in the source document, even though they aren’t.
Changing the layout with the order property has no effect on the tab
order of the page. If the numbers in Figure 12-64 were links, tabbing through
the links would go through the links in the order of the source code, not
in the order of the layout.
Tabbed Navigation Revisited
Adding to our tabbed navigation bar example in Figure 12-2,
we can make the currently active tab appear first, as Figure 12-65 shows:
The currently active tab has the .active class added, the href
attribute removed, and the order set to -1, which is less than the
default 0 of the other sibling flex items, meaning it appears first.
Why did we remove the href attribute? As the tab is the currently
active document, there is no reason for the document to link to itself.
But, more importantly, if it was an active link instead of a placeholder
link, and the user was using the keyboard to tab through the navigation,
the order of appearance is Blog, Home, About, Careers, and
Contact Us, with the Blog appearing first; but the tab order would
have been Home, About, Blog, Careers, and Contact Us, following
the source order rather than the visual order, which can be confusing.
The order property can be used to enable marking up the main content
area before the side columns for mobile devices and those using screen
readers and other assistive technology, while creating the appearance of
the common three-column layout: a center main content area, with site navigation
on the left and a sidebar on the right, as shown way back in Figure 12-50.
While you can put your footer before your header in your markup, and use
the order property to reorder the page, this is an inappropriate use
of the property. order should only be used for visual reordering
of content. Your underlying markup should always reflect the logical
order of your content:
We’ve been marking up websites in the order we want them to appear, as
shown on the right in the preceding code example, which is the same code as
in our three-column layout example (Figure 12-50). It really would make more sense if we marked up the page as shown
on the left, with the article content, which is the main content,
first in the source order: this puts the article first for screen
readers, search engines, and even mobile device, but in the middle for
our sighted users on larger screens:
main{display:flex;}main>nav{order:-1;}
By using the order: -1 declaration we are able to make the nav
appear first, as it is the lone flex item in the ordinal group of -1.
The article and aside, with no order explicitly declared, default
to order: 0.
Remember, when more than one flex item is in the same ordinal group,
the members of that group are displayed in source order in the direction
of main-start to main-end, so the article is displayed before the
aside.
Some developers, when changing the order of at least one flex item, like
to give all flex items an order value for better markup readability.
We could have also written:
In previous years, before browsers supported flex, all this could have
been done with floats: we would have set float: right on the nav.
While doable, flex layout makes it much simpler, especially if we want
all three columns—the aside, nav, and article—to be of equal
heights.