Chapter 12. Flexible Box Layout

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:

div#one {display: flex;}
div#two {display: inline-flex;}
div {border: 1px dashed; background: silver;}
div > * {border: 1px solid; background: #AAA;}
div p {margin: 0;}
<div id="one">
    <p>flex item with<br>two longer lines</p>
    <span>flex item</span>
    <p>flex item</p>
</div>
<div id="two">
    <span>flex item with<br>two longer lines</span>
    <span>flex item</span>
    <p>flex item</p>
</div>
Adding display: flex; or display: inline-flex creates a flex container
Figure 12-1. The two kinds of flex containers
Tip

Look for the Play symbol to know when an online example is available. All of the examples in this chapter can be found at https://meyerweb.github.io/csstdg4figs/12-flexbox/.

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:

nav {
  display: flex;
}
<nav>
  <a href="/">Home</a>
  <a href="/about">About</a>
  <a href="/blog">Blog</a>
  <a href="/jobs">Careers</a>
  <a href="/contact">Contact Us</a>
</nav>

In the preceding code, with its display property set to flex, the nav 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.

So let’s add some more CSS to the links:

nav {
  display: flex;
  border-bottom: 1px solid #ccc;
}
a {
  margin: 0 5px;
  padding: 5px 15px;
  border-radius: 3px 3px 0 0;
  background-color: #ddaa00;
  text-decoration: none;
  color: #ffffff;
}
a:hover, a:focus, a:active {
  background-color: #ffcc22;
  color: black;
}

With that CSS, we’ve got ourselves a simple tabbed navigation bar, as shown in Figure 12-2.

A simple tabbed navigation (files/nav_displayflex.html)
Figure 12-2. A simple tabbed navigation

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.

Power grid layout with flexbox, with buttons aligned on the bottom
Figure 12-3. Power grid layout with flexbox, with buttons aligned on the bottom
Button with many components neatly vertically centered
Figure 12-5. Widget with several components, all vertically centered
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:

<header>Header</header>
<main>
  <nav>Links</nav>
  <aside>Aside content</aside>
  <article>Document content</article>
</main>
<footer>Footer</footer>

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).

Assume the following basic markup structure:

<ol>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ol>

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 four values of the flex-direction property
Figure 12-6. The four values of the flex-direction property

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:

nav {
  display: flex;
  flex-direction: column;
  border-right: 1px solid #ccc;
}
a {
  margin: 5px;
  padding: 5px 15px;
  border-radius: 3px;
  background-color: #ccc;
  text-decoration: none;
  color: black;
}
a:hover, a:focus, a:active {
  background-color: #aaa;
  text-decoration: underline;
}

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.

Changing flex-direction can completely change the layout of your content
Figure 12-7. Changing the flex direction can completely change the layout

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>
      <a href="/">Home</a>
      <a href="/about">About</a>
      <a href="/blog">Blog</a>
      <a href="/jobs">Careers</a>
      <a href="/contact">Contact Us</a>
  </nav>
  <main>
      <article>
        <img alt="" src="img1.jpg">
        <p>This is some awesome content that is on the page.</p>
        <button>Go Somewhere</button>
      </article>
      <article>
        <img alt="" src="img2.jpg">
        <p>This is more content than the previous box, but less than
        the next.</p>
        <button>Click Me</button>
      </article>
      <article>
        <img alt="" 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 &#169; 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:

* {
  outline: 1px #ccc solid;
  margin: 10px;
  padding: 10px;
}
body, nav, main, article {
  display: flex;
}
body, article {
  flex-direction: column;
}
Home page layout using flex-direction: row and column
Figure 12-8. Home page layout using flex-direction: row and column

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.

The four values of the flex-direction property when direction is right to left, demonstrated here with display: inline-flex;
Figure 12-9. The four values of the flex-direction property when writing direction is right to left
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:

<ol lang="jp">
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ol>
The four values of the flex-direction property when writing mode is horizontal-tb
Figure 12-10. The four values of flex-direction property when writing mode is horizontal-tb

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.

The three values of flex-wrap property
Figure 12-11. The three values of the flex-wrap property in a row-oriented flow

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:

flex-flow: row;
flex-flow: nowrap;
flex-flow: row nowrap;
flex-flow: row;
Figure 12-12. A row-oriented unwrapped flex flow

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:

flex-flow: column-reverse wrap;
flex-flow: wrap column-reverse;

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.

Axes for row, row-reverse, column, and column-reverse in left-to-right languages
Figure 12-13. Main- and cross-axis term placements in left-to-right writing modes
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.

Flex lines on row and row-reverse when flex-wrap: wrap is set
Figure 12-14. Stacking of row-oriented flex lines

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.

Note

align-items: flex-start and align-content: flex-start were added to the flex container in Figure 12-14 and Figure 12-15 to enunciate the height and directions of the flex lines. These properties are covered in the following sections.

Now that we have a better understanding of all these terms and dimensions, let’s get back to the flex-wrap property.

Flex lines on columns and column-reverse when flex-wrap: wrap-reverse is set
Figure 12-15. Stacking of column-oriented flex lines

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.

The three values of flex-wrap property with a column flex-direction
Figure 12-16. The three values of flex-wrap property in a column-oriented flow

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.

No matter the value of flex flow, the empty space will be in the direction of main-end and cross-end
Figure 12-17. Empty space will be in the direction of main-end and cross-end

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.

The six values of the justify-content property
Figure 12-18. The six values of the justify-content property

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.

The overflow direction in a single-line flex container depends on the value of the justify-content property
Figure 12-19. Overflow of a single-line flex container is affected by justify-content

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.

Impact of setting justify-content: flex-start;
Figure 12-20. Flex-start alignment

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.

Impact of setting justify-content: flex-end;
Figure 12-21. Flex-end alignment

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.

Impact of setting justify-content: center;
Figure 12-22. Center alignment

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.

Impact of setting justify-content: space-between;
Figure 12-23. Space-between alignment

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.

Impact of setting justify-content: space-around;
Figure 12-24. Space-around alignment

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.

Impact of setting justify-content: space-evenly;
Figure 12-25. Space-evenly alignment

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.

css4 1226
Figure 12-26. Comparing center, space-between, space-around, and space-evenly

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.

Right- and left-aligned navigation in LTR and RTL languages using justify-content
Figure 12-27. Internationally robust navigation alignment

We could have centered that navigation, as shown in Figure 12-28:

nav {
  display: flex;
  justify-content: center;
}
Changing the layout with one property value pair
Figure 12-28. Changing the layout with one property value pair

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.

The five values of the align-items property when you have a single row of flex items and single column of flex items
Figure 12-29. The five values of the align-items property for both rows and columns 

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:

flex-container {
  display: inline-flex;
  flex-flow: row wrap;
  border: 1px dashed;
}
flex-item {
  border: 1px solid;
  margin: 0 10px;
}
.C, .H {
  margin-top: 10px;
}
.D, .I {
  margin-top: 20px;
}
.J {
  font-size: 3rem;
}

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.

css4 1230
Figure 12-30. Stretch alignment

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.

Effect of cross-axis margins on align-items property
Figure 12-31. Effect of cross-axis margins on item alignment

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.

Flex-start, flex-end, and center alignment
Figure 12-32. Flex-start, flex-end, and center alignment

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.)

css4 1233
Figure 12-33. Baseline alignment

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.

css4 1234
Figure 12-34. Changing flex item alignments

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-items property, 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:

.flex-container {
  display: flex;
  flex-flow: row wrap;
  align-items: flex-start;
  border: 1px dashed;
  height: 480px;
  background-image: url(banded.svg);
}
.flex-items {
    margin: 0;
    flow: 1;
}

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.

css4 1235
Figure 12-35. Distribution of extra space for each value of align-content

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.)

Appearance of align-content property when lines are overflowing the container
Figure 12-36. Flex-line overflow directions for each value of align-content

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.

css4 1237
Figure 12-37. Distribution of free space for space-between, space-around, and space-evenly

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.

Items with display: flex; become flex containers, and their non-absolutely positioned children become flex items
Figure 12-38. The child nodes are flex items, the parent node is a flex container

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:

<p style="display: flex;">
    <strong>Flex items:</strong> they’re what’s for <em>&lt;br&gt;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:

nav ul {
  display: flex;
}
<nav>
  <ul>
    <li><a href="#1">Link 1</a></li>
    <li><a href="#2">Link 2</a></li>
    <li><a href="#3">Link 3</a></li>
    <li><a href="#4">Link 4</a></li>
    <li><a href="#5">Link 5</a></li>
  </ul>
</nav>

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>

    <img src="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>

    <img src="images/foo.jpg" alt="foo master">
    Some text <a href="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.

Figure 12-39. Five flex items in an aside

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.)

Flex items overflowing their container when min-width defaults to auto, unless wrapping is allowed
Figure 12-40. Flex container overflow with minimum-width flex items

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 items in non-wrapping containers will shrink if the min-width is explicitly set to 0, which is the default in Safari 9
Figure 12-41. Zero-minimum-width flex items in non-wrapped and wrapped flex containers

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: 0 0 200px;
}

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.

With a growth factor of 0, the flex item will not grow; any positive value will allow the item to grow proportionally to the value
Figure 12-42. A variety of flex-growth scenarios

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:

  1. 450 px × 0.2 = 90 px

  2. 450 px × 0.2 = 90 px

  3. 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.

The available space is evenly distributed to each growth factor; any positive value will allow the item to grow proportionally to the value.
Figure 12-43. Mixed widths and growth factors

To recap, the available space in the flex container, and the growth factors and final width of each flex item, are:

  • Available space: 750px - (100px + 250px + 100px) = 300px
  • Growth factors: 1 + 1 + 3 = 5
  • Width of each growth factor: 300px ÷ 5 = 60px

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:

#example2 flex-item {
  flex: 0 1 auto;
}
#example2 flex-item:last-child {
  flex: 1 1 auto;
}

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:

#example2 flex-item {
  flex: 0 1 0%;
}
#example2 flex-item:last-child {
  flex: 1 1 0%;
}

As the shrink factor defaults to 1 and the basis defaults to 0%, the following CSS is identical to the preceding snippet:

#example2 flex-item {
  flex: 0;
}
#example2 flex-item:last-child {
  flex: 1;
}

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).

Flex grow looks different when the flex basis is 0, and some items are not allowed to grow
Figure 12-44. Flex sizing when using the flex shorthand

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.

Flex grow looks different when the flex basis is 0, and sometimes are not allowed to grow
Figure 12-45. Flex sizing differences between using flex and flex-grow

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.

A flex shrink factor of 0 will not allow flex items to shrink; any positive value will enable the item to shrink proportionally relative to sibling flex items that are allowed to shrink on the same flex line
Figure 12-46. A variety of flex shrinking scenarios

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:

#example3 flex-item {
  flex-shrink: 1;
}
#example3 flex-item:last-child {
  flex-shrink: 3;
}

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:

#example3 flex-item {
  flex: 0 1 auto; /* growth defaults to 0, basis to auto */
}
f#example3 flex-item:last-child {
  flex: 0 3 auto;
}

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:

flex-item {
  flex: 1 0.25 auto;
}
flex-item:last-child {
  flex: 1 0.75 auto;
}

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
Figure 12-47. Shrinking being impeded by flex item content

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 their shrink factor
Figure 12-48. Flex items shrink proportionally relative to their shrink factor

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:

upper S h r i n k upper P e r c e n t equals StartFraction upper N e g a t i v e upper S p a c e Over left-parenthesis left-parenthesis upper W i d t h Baseline 1 times upper S h r upper F Baseline 1 right-parenthesis plus period period period plus left-parenthesis upper W i d t h upper N times upper S h r upper F upper N right-parenthesis right-parenthesis EndFraction

Using this equation, we find the shrink percentage:

  • = 250px ÷ ((250px × 1) + (500px × 1) + (250px × 3))
  • = 250px ÷ 1500px
  • = 0.166666667 (16.67%)

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.

css4 1249
Figure 12-49. Flex items shrink proportionally relative to their shrink factor and content 

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:

  • 280px + 995px + 480px = 1615px
  • (0.5 × 280px) + (1 × 995px) + (1 × 480px) = 1235px
  • X = 1235px ÷ 1615px = 0.7647

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:

nav {
  flex: 0 1 200px;
  min-width: 150px;
}
article {
  flex: 1 2 600px;
}
aside {
  flex: 0 1 200px;
  min-width: 150px;
}
By setting different values for growth, shrink, basis, and min-width, you can create responsive layouts, with or without media queries
Figure 12-50. A wide flexbox layout
css4 1251
Figure 12-51. A narrow flexbox layout

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: 0 1 200px;
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: 1 2 600px;

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:

nav {
  flex: 0 1 20ch;
  min-width: 15vw;
}
article {
  flex: 1 2 45ch;
}
aside {
  flex: 0 1 20ch;
  min-width: 10ch;
}

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.

css4 1252
Figure 12-52. Sizing flex items on a content basis

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.

css4 1253
Figure 12-53. Auto flex basis and flex item widths

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.

When no flex properties are set, the flex item's main-axis size will be the pre-flex size of the item
Figure 12-54. Default sizing of flex items

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.

css4 1255
Figure 12-55. Sizing flex items with length-unit flex bases

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:

flex-container {
  width: 540px;
}
item1 {
  width: 100px;
  flex-basis: 300px;  /* flex: 0 1 300px; */
}
item2 {
  width: 200px;
  flex-basis: 200px;  /* flex: 0 1 200px; */
}
item3 {
  width: 300px;
  flex-basis: 100px;  /* flex: 0 1 100px; */
}

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:

flex-container {
  width: 540px;
}
flex-item {
  flex: 0 1 100%;
}

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 for flex-basis is relative to the width of the flex container
Figure 12-56. Sizing flex items with percentage flex bases

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:

flex-container {
  width: 540px;
}
item1 {
  flex: 0 1 70%;
}
item2 {
  flex: 0 1 auto;
}
item3 {
  flex: 0 1 80%;
}

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.

css4 1257
Figure 12-57. While the percentage value for flex-basis is relative to the width of the flex container, the main-axis size is impacted by its siblings

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.

flex-basis auto versus 0
Figure 12-58. Flex growth in auto and zero flex bases

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: 0 1 auto;

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.

With containers of different main sizes, the flex items shrink but won't grow when flex: initial is set on the flex items
Figure 12-59. Flex items shrink but won’t grow when flex: initial is set

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: 1 1 auto;

A variety of scenarios using auto flexing are shown in Figure 12-60.

With flex: auto set on the flex items, the flex items can grow and shrink
Figure 12-60. Flex items can grow and shrink when flex: auto is set

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:

flex: none;
flex: 0 0 auto;

The effects of none are shown in Figure 12-61.

With flex: none, flex items will neither grow nor shrink
Figure 12-61. With flex: none, flex items will neither grow nor shrink

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: 3 1 0;

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.

With flex: n, you're declaring the flex items growth factor while setting the flex basis to zero
Figure 12-62. Flexing using a single numeric value

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:

ul {
  display: inline-flex;
}
li:nth-of-type(6) {
  order: 1;
}
li:nth-of-type(7) {
  order: -1;
}

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.

Setting order to any value other than 0 will reorder that flex item
Figure 12-63. Reordering flex items with the order property

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:

ul {
  display: inline-flex;
  background-color: rgba(0,0,0,0.1);
}
li:nth-of-type(3n-1) {
  order: 3;
  background-color: rgba(0,0,0,0.2);
}
li:nth-of-type(3n+1) {
  order: -1;
  background-color: rgba(0,0,0,0.4);
}

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.

Flex items appear in order of ordinal groups, by source order within their group
Figure 12-64. Flex items appear in order of ordinal groups, by source order within their group

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:

nav {
  display: flex;
  justify-content: flex-end;
  border-bottom: 1px solid #ddd;
}
a {
  margin: 0 5px;
  padding: 5px 15px;
  border-radius: 3px 3px 0 0;
  background-color: #ddd;
  text-decoration: none;
  color: black;
}
a:hover {
  background-color: #bbb;
  text-decoration: underline;
}
a.active {
  order: -1;
  background-color: #999;
}

<nav>
  <a href="/">Home</a>
  <a href="/about">About</a>
  <a class="active">Blog</a>
  <a href="/jobs">Careers</a>
  <a href="/contact">Contact Us</a>
</nav>
Changing the order will change the visual order, but not the tab order
Figure 12-65. Changing the order will change the visual order, but not the tab order

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:

<header></header>                         <header></header>
<main>                                    <main>
   <article></article>                      <nav></nav>
   <aside></aside>                          <article></article>
   <nav></nav>                              <aside></aside>
</main>                                   </main>
<footer></footer>                         <footer></footer>

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:

main {
  display: flex;
}
main > nav {
  order: 1;
}
main > article {
  order: 2;
}
main > aside {
  order: 3;
}

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset