Chapter 2. Flex Container

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 a flex formatting context for the containing box’s children, known as the flex container. Once we have created a flex container (by adding a display: flex or display: inline-flex), we need to learn how to manipulate the layout of the container’s children.

The children of this container box are flex items, whether they are DOM nodes, text nodes, or generated content. Absolutely positioned children of flex containers are also flex items, but they are sized and positioned as though they are the only flex item in the flex container.

We will 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 grok and will be covered in full in Chapter 3.

Flex Container Properties

The display property examples in Figure 1-6 show three flex items side by side, going from left to right, on one line. With a few additional property value declarations, we could have centered the items, aligned them to the bottom of the container, rearranged their order of appearance, and laid them out from left to right or from top to bottom. We could even have made 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. Sometimes the number of children will not be under our control. We might have a varied number of items in a set-width container. 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). There are several properties outside of the new display values we can add to the flex container to provide control over layout that enable us to build responsive layouts and responsive widgets.

The display, flex-direction, flex-wrap, and flex-flow properties impact the ordering and orientation of the flex container. The justify-content, align-items, and align-content properties can be applied to the flex container to impact the alignment of the container’s children.

The flex-flow Shorthand Property

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.

The default value of flex-direction is row. The default value of flex-wrap is nowrap. 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, which all mean the same thing:

flex-flow: row;
flex-flow: nowrap;
flex-flow: row nowrap;

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, as shown in Figure 2-1. That’s not the look you’re going for. flex-flow can help. But you might be wondering why we’re introducing a shorthand property before you understand the component properties.

flex-flow: row
Figure 2-1. flex-flow: row;

While the specification’s authors encourage the use of the flex-flow shorthand, understanding flex-wrap and flex-direction, the two properties that make up this shorthand, is necessary. And, by learning about the values that make up the flex-flow shorthand, we’ll learn how to fix the unsightly layout shown in Figure 2-1.

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 (see “Understanding axes”), which is the primary axis along which flex items are laid out.

Figure 2-2 shows the four values of flex-direction, including row, row-reverse, column, and column-reverse in left-to-right languages. Note that all flex properties discussed here, like all CSS properties, accept the global values of inherit, initial, and unset.

The four values of the flex-direction property
Figure 2-2. The four values of the flex-direction property when the language is left-to-right

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.

Preferably, we should have used the flex-flow shorthand property. The two right columns in Table 2-1 are equivalent, with the nowrap value being explained in the next section.

Table 2-1. The values for flex-direction and flex-flow equivalents
flex-direction single-value flex-flow flex-flow

row

row

row nowrap

row-reverse

row-reverse

row-reverse nowrap

column

column

column nowrap

column-reverse

column-reverse

column-reverse nowrap

You can reverse this default direction with flex-direction: row-reverse.

The flex items will be 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 2-2. 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.

Note

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, which enables switching between horizontal and vertical, to indicate the language direction.

In horizontal writing modes, which includes left-to-right and right-to-left languages, setting flex-direction: row, flex-flow: row, flex-flow: row nowrap, or omitting both the longhand and shorthand properties so it defaults to row will set all the flex items horizontally, side to side. By default, they will all be aligned horizontally, along the main-axis line, in source order. In left-to-right languages, they will be aligned from left to right: the left side is referred to main-start and the right is main-end, for the start and end points of the main-axis. In right-to-left languages, the main direction is reversed: the flex items are side by side from right to left, with the main-axis going from left to right, the right side being main-start and left being main-end.

The row-reverse value is the same as row, except the flex items are laid out in the opposite direction of the text direction: the start and end points are reversed. The direction of the main-axis of the flex container is reversed by the row-reverse value. For left-to-right languages, like English, row-reverse will lay out all the flex items side to side from right to left, horizontally, with main-start being on the right and main-end now on the left. These are shown in the top two image examples in Figure 2-2.

Had the direction of the page or flex container been reversed, such as for Hebrew or Arabic, with the attribute dir="rtl" on the flex container or an ancestor in the HTML, or with direction: rtl on the flex container or container’s ancestor in the CSS, the direction of the row-reverse main axis, and therefore the flex items, would be inverted from the default, going left to right, as shown in Figure 2-3. Similarly, the writing-mode property impacts the direction in which the flex items are drawn to the page.

The four values of the flex-direction property when direction is right to left, demonstrated here with display: inline-flex
Figure 2-3. The four values of the flex-direction property when direction is right to left, demonstrated here with display: inline-flex

The column value will lay out the flex items from top to bottom. 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 and the horizontal axis in vertical writing modes. Basically, it sets the flex-container’s main-axis to vertical in most cases.

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.

Note

The writing-mode controls the block flow direction: the direction in which lines and blocks are stacked. The default value, horizontal-tb, stacks them top to bottom. The other values stack them right to left or left to right.

The direction controls the inline “base direction,” the direction in which content within a line is ordered. LTR, short for “left to right,” goes from nominal “left” to nominal “right”. RTL, short for “right to left”, is the opposite. Which side is nominally “left” for the purpose of direction is affected by the writing mode: if the writing mode is vertical, the “left” side might be the top!

The inline base direction is and should always be a property of the content. Use the dir attribute in HTML. Do not use the CSS direction property. The writing-mode is a layout preference.1 Chinese, Japanese, and Korean can be written in either orientation. While English is a top-to-bottom, left-to-right language, you will sometimes see and may even use vertical writing for stylistic effect.

With column, 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:

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 similar markup to our preceding navigation example, by simply changing a few CSS properties, we can create a nice sidebar-style navigation.

For the navigation’s new layout, we changed the flex-direction from the default row to column, moved the border from the bottom to the right, and changed the colors, border-radius, and margin values, as seen in Figure 2-4.

Changing flex-direction can completely change the layout of your content
Figure 2-4. Changing flex-direction can completely change the layout of your content
The four values of flex-direction property when writing mode is horizontal-tb
Figure 2-5. The four values of flex-direction property when writing mode is horizontal-tb

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 laid out in the bottom-right example in Figure 2-3.

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

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; 2017</footer>
</body>

By simply adding a few lines of CSS, we’ve got a nicely laid out home page, as shown in Figure 2-6:

* {
  outline: 1px #ccc solid;
  margin: 10px;
  padding: 10px;
}
body, nav, main, article {
  display: flex;
}
body, article {
  flex-direction: column;
}

It took only two CSS property/value declarations to create the basic layout for a site home page.

Obviously there was some additional CSS. We added border, margin, and padding to all the elements so you can 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. 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!

Home page layout using flex-direction: row and column
Figure 2-6. Home page layout using flex-direction: row and column

But 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, as shown in Figure 2-1, or we can allow them to wrap onto additional flex lines.

The flex-wrap Property

Thus far, the examples have shown a single row or column of flex items. If the flex items’ main-dimensions don’t all fit across the main-axis of the flex container, by default the flex items will not wrap. Rather, the flex items may shrink if allowed to do so via the flex item’s flex property (see “The flex Property”) and/or the flex items may overflow the bounding container box.

You can control this behavior. flex-wrap 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 2-7 demonstrates the three values of the flex-wrap property when the flex-direction value is defaulting to row. When there are two or more flex lines, the second line and subsequent flex lines are added in the direction of the cross-axis.

Whether the additional flex lines are added above or below, as in the case of Figure 2-7, or to the left or to the right of the previous line is determined by whether wrap or wrap-reverse is set, by the flex-direction value, and by the writing mode.

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 current 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 flex-direction: row and flex-direction: row-reverse and to the left of the previous column in the case of flex-direction: column and flex-direction: column-reverse. Similarly, in right-to-left languages, flex-flow: row wrap-reverse and flex-flow: row-reverse wrap-reverse, new lines will also be added on top, but for flex-flow: column wrap-reverse and flex-flow: column-reverse wrap-reverse new lines will be added to the right—the opposite of the language direction or writing mode, the direction of the inverted cross-axis.

The three values of flex-wrap property
Figure 2-7. The three values of the flex-wrap property

You may notice that in Figure 2-7, the new lines created in the wrap and wrap-reverse examples are not the same height as the first line. Flex lines are as tall or wide as their tallest or widest flex item within that line. The flex line’s main dimension is the main dimension of the flex container, while the flex line’s cross dimension grows to fit the cross-size of the flex item with the largest cross-size.

While the examples thus far are fairly simple, as you may have noticed from the two previous paragraphs, fully understanding all the complexities of flexbox is not. The preceding explanation introduced possibly confusing terms like main-axis, main-start, and main-end and cross-axis, cross-start, and cross-end. To fully grasp flexbox and all the flexbox properties, it is important to understand.

To understand flex layout you need to understand the physical directions, axes, and sizes affecting the flex container and its flex items. Fully understanding what the specification means when it uses these terms will make fully understanding flexbox much easier.

Understanding axes

Flex items are laid out along the main-axis. Flex lines are added in the direction of the cross-axis. The “main-” terms have to do with flex items. The “cross-” terms come into play on multiline flex containers: when wrap or wrap-reverse is set and the flex items actually wrap onto more than one line.

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.

Table 2-2 summarizes the “main-” and “cross-” terms. It lists the dimensions and directions of the main-axis and cross-axis, along with their start point, end points, and directions for left-to-right writing mode layouts. In addition to describing the dimensions and direction of the flex container, these terms can be used to describe the direction and dimension of individual flex items.

Table 2-2. Dimensions and directions of the main- and cross-axis, along with their start point, end points, and directions in left-to-right layout
  Flex directions in left-to-right (LTR) writing modes
row row-reverse column column-reverse
main-axis left to right right to left top to bottom bottom to top
main dimension horizontal horizontal vertical vertical
main-start left right top bottom
main-end right left bottom top
main-size width width height height
cross dimension vertical vertical horizontal horizontal
cross-start top top left left
cross-end bottom bottom right right
cross-size height height width width

In the case of flex-flow: row (Figure 2-1), the sum of the main-sizes of the nonwrappable line of flex items was greater than the main-size of the flex container parent. In plainer English, the combined widths (and noncollapsed horizontal margins) of the flex items was wider than the width of the flex container.

In horizontal writing modes, for row and row-reverse, the main size refers to the widths of the flex items and flex container. In the case of column and column-reverse, the main size is height.

Figure 2-8 shows the axes and the direction of each axis for flex containers with a flex-direction of row, row-reverse, column, and column-reverse for LTR writing modes.

Axes for row, row-reverse, column, and column-reverse in left-to-right languages
Figure 2-8. Axes for row, row-reverse, column, and column-reverse in LTR languages

The main-axis is the primary axis along which flex items are laid out, with flex items being drawn along the main-axis in the direction of main-start to main-end.

If all writing modes were from left to right and top to bottom, like in English, flex-direction would be less complex. For both RTL and LTR languages, flex-direction: row and flex-direction: row-reverse the main-axis is horizontal. For LTR languages, in the case of row, the main-start is on the left, and main-end is on the right. They’re inverted for row-reverse, with the main-start switching to the right and main-end now on the left. For column, the main axis is vertical, with main-start on top and main-end on the bottom. For column-reverse, the main-axis is also vertical, but with main-start on bottom and main-end is on the top.

As shown in Table 2-3, when the writing mode is right to left, like in Arabic and Hebrew, if you have dir="rtl" set in your HTML, or direction: rtl set in your CSS, the direction of the text will go from right to left. In these cases, the direction of row is reversed to be from right to left with main-start on the right and main-end on the left. Similarly, the main-axis for row-reverse will go from left to right, with main-start being on the right. For column, the main-start is still on the top and main-end is on the bottom, just like for left-to-right languages, as both are top-to-bottom languages.

Table 2-3. Dimensions and directions of the main- and cross-axis, along with their start points, end points, and directions when writing mode is right to left
  Flex directions in RTL writing modes
row row-reverse column column-reverse
main-axis right to left left to right top to bottom bottom to top
main dimension horizontal horizontal vertical vertical
main-start right left top bottom
main-end left right bottom top
main-size width width height height
cross dimension vertical vertical horizontal horizontal
cross-start top top right right
cross-end bottom bottom left left
cross-size height height width width

If your site has writing-mode: horizontal-tb set, as in Figure 2-5, the main-axis of the content for row and row-reverse will be vertical, while column and column-reverse are horizontal. The writing-mode property is starting to get support in browsers, with support in Edge and Firefox, prefixed support in Chrome, Safari, Android, and Opera, and support for an older syntax in Internet Explorer.

Note

While the CSS direction property along with unicode-bidi can be used to control the direction of text, don’t do it. It is recommended to use the dir attribute and CSS writing-mode property because HTML’s dir attribute concerns HTML content, and the writing-mode property concerns layout.

It’s important to understand things get reversed when writing direction is reversed. Now that you understand that, to make explaining (and understanding) flex layout much simpler, we’re going to make the rest of the explanations and examples all be based on left-to-right writing mode, but will include how writing mode impacts the flex properties and features discussed.

How your flex layout appears on the screen is determined in part by interactions between flex-flow—which includes flex-direction and flex-wrap—and the writing mode. We’ve covered the direction in which flex items are added to a line of flex items, but when the end of the flex line is reached, how are new flex lines added?

When thinking about flex-direction, we now know the flex items are going to start being laid out across the main axis of the flex container, starting from the main-start. The “cross-” directions come into play when it comes to adding additional lines of flex items, known as flex lines. 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.

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 perpendicular to the main-axis. As we see in Figure 2-9, 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. Flex lines are filled with items and placed into the container, with lines added starting on 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 2-9. Flex lines on row and row-reverse when flex-wrap: wrap is set

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, as shown in Figure 2-9. When flex-wrap is set to 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, as shown in Figure 2-7. 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 2-10, 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.

Flex lines on columns and column-reverse when flex-wrap: wrap-reverse is set
Figure 2-10. Flex lines on column and column-reverse when flex-wrap: wrap-reverse is set
Note

We added align-items: flex-start (see “The align-items Property”) and align-content: flex-start (see “The align-content Property”) to the flex container in Figures 2-9 and 2-10 to enunciate the height and directions of the flex lines. These properties are covered in the following sections.

The flex-wrap property seemed fairly intuitive when it was first described. It turned out to be a bit more complex than it might have originally seemed. You may never implement reversed wrapping in a right-to-left language, but this is a “Definitive Guide.” Now that we have a better understanding of the “cross-” dimensions, let’s dig deeper into the flex-wrap property.

flex-wrap continued

The default value of nowrap prevents wrapping, so the cross- directions just discussed aren’t relevant when there is no chance of a second flex line. When additional lines are possible—when flex-wrap is set to wrap or wrap-reverse—those lines will be added in the cross direction, which is perpendicular to the main-axis. The first line starts at the cross-start with additional lines being added on the cross-end side.

The wrap-reverse value inverts the direction of the cross-axis. Normally for flex-direction of row and row-reverse, the cross-axis goes from top to bottom, with the cross-start on top and cross-end on the bottom. When flex-wrap is wrap-reverse, the cross-start and cross-end directions are swapped, with the cross-start on the bottom, cross-end on top, and the cross-axis going from bottom to top. Additional flex lines get added on top of the previous line.

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 Figures 2-9, 2-10, and 2-11, the last example in each is wrap-reverse. You’ll notice the new line starts at the main-start, but is added in the inverse direction of the cross-axis set by the flex-direction property.

In Figure 2-11, 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 first example in Figure 2-7, 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 within the flex container’s main dimension, they’ll overflow the flex container, unless explicitly forced 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-direction: column; flex-wrap: wrap;" or "flex-flow: column wrap;" is set on a flex container, the flex item children are aligned along the main-axis. In LTR modes, the first flex item is placed in the top left, which is the main-start and cross-start respectively. If there is room, the next item will be placed below it, along the main-axis. If there isn’t enough room, the flex container will wrap the flex items onto new lines. The next flex item will be put on a new line, which in this case is a vertical line to the right of the previous line, as can be observed in the flex-flow: column wrap example, the top-right example in Figure 2-11.

The three values of flex-wrap property with a column flex-direction
Figure 2-11. The three values of flex-wrap property with a column flex-direction

Here, the flex items have wrapped onto 3 lines. The flex items are wrapping onto new lines as the height: 440px was set on the parent. Including a height forces the creation of new flex lines when the next flex item will not fit onto the current flex line.

As shown in the bottom-right example in Figure 2-11, when we include "flex-direction: column; flex-wrap: wrap-reverse;" or "flex-flow: column wrap-reverse;" and the main-axis is the vertical axis, flex items are added below the previous flex item, if they can fit within the parent container. Because of the wrap-reverse, the cross-axis is reversed meaning new lines are added in the opposite direction of the writing mode. As shown in this example and in Figure 2-10, with wrap-reverse, columns are laid out right to left, instead of left to right. The first column of flex items is on the leftmost side of the parent flex container. Any additional required columns will be added to the left of the previous column. Again, we’re assuming a left-to-right default writing mode for all the examples.

In this example, the flex items are different heights based on their content. When divided across three lines, the last line is not filled. Since subsequent lines are being added to the left of previous lines, the empty space, if there is any, will be on the bottom left (assuming justify-content, described next, is set or defaults to flex-start).

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 are provided with the flex-flow property, which is simply shorthand for flex-direction and flex-wrap.

Flex Line Cross Dimension

Similar to the display examples in Figure 1-6, in the flex-flow example in Figure 2-1, the flex items grew to fill the cross dimension of the flex line they were on. Because they default to nowrap, all the flex items will be on a single line. With other flex properties defaulting to their default values, the flex items are stretched filling the container.

In the flex-wrap example in Figure 2-7, we had two flex lines. All the flex items in a single line were the same height, but the individual flex lines were not of the same height: instead all the flex items were as tall as the tallest flex item within that same flex line.

By default, all flex items will appear to be the same height. We controlled this in Figures 2-9 and 2-10 in order to highlight the how flex lines are drawn. This stretching (or overwriting of that stretching) is caused by the stretch default value of the justify-content property, described in the next section.

In those examples, you’ll note the second row is not as wide as the flex container. When flex items are allowed to wrap onto multiple lines, by default all the items on one line will have the same cross dimension, which means all the items in a flex line of row and row-reverse will be the same height and all the items in a flex line of column or column-reverse will have the same width.

Figure 2-12 is an example in which flex-flow: column-reverse wrap-reverse is set. This means the main-axis is vertical, going bottom to top with a horizontal cross-axis going from right to left. Notice the extra space on the top left. New flex items get placed to the top of the previous ones, with new lines wrapping to the left of the previously filled row. By default, no matter the values of flex-flow, the empty space, if there is any, will be in the direction of main-end and cross-end. There are other flex properties that will allow us to alter that. Let’s look into those.

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

Flex Container

In Chapter 1 we learned how to use display property values flex and inline-flex to instantiate a flex container and turn the container’s children into flex items. We now understand how flex-direction sets the direction of the flex items within the flex container, setting the main-axis and cross-axis directions and how flex-wrap can be used to enable multiline flex containers and even invert the cross-axis direction. We also know how to use flex-flow to set both flex-direction and flex-wrap.

While we learned how to use flex-flow properties to handle multiline flex containers, we haven’t really discussed what happens to the extra space when the flex items don’t fill a row or column, and what happens to the extra space when not all the flex items have the same cross dimension.

Thus far in our examples, when the flex items did not fill the flex container, the flex items have been grouped toward the main-start on the main-axis. We can control that. Flex items can be flush against the main-end instead. They can be centered. We can even space the flex items 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.

The properties applied to individual flex items are discussed in Chapter 3.

The justify-content Property

The justify-content property enables us to define how flex items will be distributed along the main-axis of the flex container.

The distribution of elements along the main axis of the container is controlled with the justify-content property. If you remember from Figure 1-6, when an element is converted to a flex container, the flex items, by default, were grouped together at the main-start.

The justify-content defines how space is distributed. There are five values for the justify-content property: flex-start, the default value, and flex-end, center, space-between, and space-around.

As shown in Figure 2-13, by default or with justify-content: flex-start explicitly set, flex items are laid out 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 evenly distributes the flex items, as if there were noncollapsing margins of equal size around each item. More examples of the five justify-content values are demonstrated in Figure 2-14.

The five values of the justify-content property
Figure 2-13. The five values of the justify-content property
The overflow direction in a single-line flex container depends on the value of the justify-content property
Figure 2-14. The overflow direction in a single-line flex container depends on the value of the justify-content property

As the justify-content property is applied to the flex container, the flex items will be distributed in the same manner whether they’re on a filled first flex line or on a partially filled subsequent flex line in a wrapping flex container.

Those are the basics of justify-content property. But, of course, there’s more to the property and each of the values. What happens if there is only one flex item on a line? If the writing mode is right to left? If flex-flow: nowrap is set and the flex items overflow the flex container?

If nowrap is set, and the items overflow the line, the justify-content property helps control the appearance of the line overflow. Figure 2-14 illustrates what happens with the different justify-content when flex-flow: column nowrap is set and the flex items heights are taller than the container’s main dimension.

Let’s take a look at the five values.

Setting justify-content: flex-start (Figure 2-15) 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”.

Impact of setting justify-content: flex-start
Figure 2-15. Impact of setting justify-content: flex-start

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 the third example of Figure 2-15.

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 the third example of Figure 2-16. Any extra space on a flex line will be on the main-start side.

Impact of setting justify-content: flex-end
Figure 2-16. Impact of setting justify-content: flex-end

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 third example in Figure 2-17. 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 2-17. Impact of setting justify-content: center

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 edge of the container and the first item and the opposite edge of the container and the outer edge of the last item, as shown in the second example in Figure 2-18. 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.

Note

With justify-content: space-between, the first flex item is placed flush with main-start, so, if there is only one item, or if the flex items aren’t allowed to wrap and overflow the flex container, the appearance will be the same as flex-start—the comparison can be seen in Figure 2-14—which may be less than intuitive.

Impact of setting justify-content: space-between
Figure 2-18. Impact of setting justify-content: space-between

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 2-18, 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 noncollapsing 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 2-19.

Impact of setting justify-content: space-around
Figure 2-19. Impact of setting justify-content: space-around

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 2-14.

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 2-19. 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.

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, and space-between might be more helpful.

Figure 2-20 demonstrates the difference between the spacing concepts of center, space-around, and space-between. When set to center, the flex items are grouped flush against each other in the center of the main-dimension.

With space-between, you’ll note the first and last flex items on both flex lines abut main-start and main-end, respectively. The space between each of the flex items on the first flex line is 24 px: the 120 px of free space is divided into 5 equal gaps placed between the 6 flex items. The space between each flex item on the second flex line is 150 px: the 300 px of free space is divided into two and placed between the three flex items.

Comparing center, space-between, and space-around
Figure 2-20. Comparing center, space-between, and space-around

With space-around, the flex items do not necessarily abut the edges: if there is any extra space, it is put around every flex item. In all three examples in Figure 2-20, there are 120 px of free space and 6 items on the first line and 300 px of free space and 3 flex items on the second flex line. On the first line of the space-around example, the 120 px of free space are divided among the two sides of the six items, placing 10 px on the left and right of each item. This way, there are 10 px of space between main-start and the first item and the last item and main-end, and twice that, or 20 px, between each adjacent flex item. On the second flex line, the 300 px of free space is divided between the two sides of the 3 flex items, putting 50 px on the outer edges and twice that, or 100 px, between adjacent items.

It may also help to compare the overflow edge and edges of the five justify-content properties with a different main-axis. In Figure 2-21, all flex containers have the following CSS:

container {
  display: inline-flex;
  flex-flow: nowrap column-reverse;
  height: 200px;
}
The five values of justify-content property when flex-direction: column-reverse is set and flex items overflow the flex container
Figure 2-21. The five values of the justify-content property when flex-direction: column-reverse is set and flex items overflow the flex container

The layout when there is negative free space should now be more intuitive:

  • flex-start and space-between overflow at main-end.

  • flex-end overflows at main-start.

  • center and space-around overflow on both ends.

With justify-content: space-between, the first flex item is placed flush with main-start. If the flex items don’t fit on a line within the flex container, they will overflow on the main-end side, as shown in Figure 2-21. With justify-content: space-around, if there is only one flex item on a line, or more items than a nonwrapping flex line can hold, it will be centered. If there are multiple items, the outer spaces are half the size of the spaces between adjacent item.

In our examples, we’ve also prevented the flex items from shrinking, a default feature we haven’t yet covered. The height: 200px limited the height of the container ensuring the flex items could overflow their container. The display: inline-flex declaration provided for a flex container that was only as wide as its content. Had we included wrap instead of nowrap, the container would have doubled in width, allowing for two columns or flex lines.

justify-content Examples

We took advantage of the default value in Figure 1-7, creating a left-aligned navigation bar. By changing the default value to justify-content: flex-end we can right align the navigation bar, as shown in Figure 2-22.

Right- and left-aligned navigation in LTR and RTL languages using justify-content
Figure 2-22. Right- and left-aligned navigation in LTR and RTL languages using justify-content

For right-to-left writing modes, we don’t have to alter the CSS. As shown in Figure 2-21, and as discussed in Chapter 1, flex items are grouped toward main-start. In English, main-start is on the left. For Hebrew, main-start is on the right.

By simply adding a single line to our CSS, we altered the appearance of our navigation example, making the English version flush to the right and the Hebrew translation flush to the left:

nav {
  display: flex;
  justify-content: flex-end;
  border-bottom: 1px solid #ccc;
}

We could have centered that navigation, as shown in Figure 2-23:

nav {
  display: flex;
  justify-content: center;
  border-bottom: 1px solid #ccc;
}
Changing the layout with one property value pair
Figure 2-23. Changing the layout with one property value pair

The align-items Property

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.

With the align-items property, you can align flex items to the start, end, or center of the cross-axis of their flex line. Set on the container element, align-items is similar to justify-content but in the perpendicular direction, setting the cross-axis alignment for all flex items, including anonymous flex items, within the flex container (we’ll learn how to override this value for individual flex items when we cover align-self (“The align-self Property”).

With align-items, you can set all the items to have their cross-axis flush against the cross-start or cross-end of their flex line, or stretched flush to both. Or you can center all the flex items in the middle of the flex line. Stretched across the entire cross-axis is the default and is what we have seen in most of the examples thus far. There are five values, including flex-start, flex-end, center, baseline, and the default stretch, as shown in Figure 2-24.

The five values of the align-items property when you have a single row of flex items and single column of flex items
Figure 2-24. The five values of the align-items property when you have a single row of flex items and single column of flex items
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.

In Figure 2-24, you’ll 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, with the possible exception of baseline.

The general idea is flex-start places the flex items on the cross-start, flex-end puts them on the cross-end edge, center centers them on the cross-axis, the default stretch stretches the flex item from cross-start to cross-end, and baseline looks similar to flex-start but actually lines up the baselines of the flex items and then pushes the group of flex items toward cross-start.

With baseline, the flex items’ baselines are aligned: the flex item that has the greatest distance between its baseline and its cross-start side will be flush against the cross-start edge of the line. That’s the general idea—and explains nonwrapping flex containers pretty well—but there’s more to it than that.

In the multiline align-items figures that follow, the following code has been included:

flex-container {
  display: inline-flex;
  flex-flow: row wrap;
  border: 1px dashed;
  padding: 10px;
}
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 in Figures 2-25, 2-27, 2-28, 2-29 and 2-30, 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. 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 2-25.

align-items: stretch

align-items: stretch
Figure 2-25. align-items: stretch 

The default and the explicitly set align-items: stretch stretches all the stretchable flex items in a line to be as tall or wide as the tallest or widest flex item on the line. What does “stretchable” mean? While by default all the 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.

If set or defaulting to stretch, 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 stretch, growing to the size of that largest flex item on that same flex line. The cross-size of the flex items includes the margins, as demonstrated by items C, D, H, and I.

Note

The margins in the cross direction have an impact. In Figure 2-26, we’ve added 30 px of margin to the cross-start edge of C of flex item and 40 px to the cross-end edge of the D. You’ll note A, B, and E are flush against both cross edges, but the C and D appear pushed in. This is due to the margins: their outer margins are flush against cross-start and cross-end.

Effect of cross-axis margins on the align-items property
Figure 2-26. Effect of cross-axis margins on the align-items property

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 the reason C, D, H, and I may appear smaller than the other flex items on their flex lines. They’re not. The outer edge of the top and bottom margins are flush with the cross-start and cross-end 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 as they need to be to contain their flex containers. In the five align-items figures, the line height of the flex line containing only K is much smaller than the line containing E, which is smaller than the line containing F. K has only one line of text, and no margin, whereas E has five lines of text. The second line, which includes F with six lines of text, making it even taller than the first line.

align-items: flex-start

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 Figure 2-27.

align-items: flex-start
Figure 2-27. align-items: flex-start 

align-items: flex-end

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 Figure 2-28. In these examples, none of the flex items have a bottom margin greater than 0 px, so unlike our other examples, this example does not look jagged.

align-items: flex-end
Figure 2-28. align-items: flex-end 

align-items: center

As shown in Figure 2-29, 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 the margin, remembering 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 centered along the cross-axis, even though they are. In LTR and RTL languages, in the case of flex-direction: row and row-reverse, the midpoint is the midpoint of the top margin, top border, top-padding, content or height, bottom padding, bottom border, and bottom margin. For flex-direction: column, and column-reverse, the midpoint is the midpoint of the left margin, left border, left-padding, content or width, right padding, right border, and right margin.

align-items: flex-center
Figure 2-29. align-items: flex-center 
Note

Flex items may overflow their parent flex container along in the main-axis if nowrap is set and the main-size is constrained. Similarly, if the 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 next. The align-items aligns the flex items within the flex line and does not directly impact the overflow direction of the flex items within in the container.

align-items: baseline

The baseline value may be a little more confusing. With baseline, the flex items in each line are all aligned at their baselines, which is basically the bottom of the first line of text, if there is any. The flex item on each flex line with the biggest distance between its baseline and its cross-start margin edge is placed flush against the cross-start edge of the line, with all other flex items’ baselines lined up with the baseline of that flex item.

Instead of aligning the cross-start of each flex item flush against the cross-start of each line, the flex items are aligned so their baselines align. In many implementations, baseline will look like flex-start, but will differ from the flex-start value if the flex items have different margins, padding, or border on the cross-start side, or if the first lines of content of the flex items don’t all have the same line heights.

You’ll notice that A, B, C, D, and E all seem aligned at top. What you may have missed is that they are not flush to the top—they are not flush against the red line. D has a top margin of 20 px. The outer edge of D’s top margin is flush against the cross-start of the flex line, which is flush with the top of the flex container. 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. In the Figure 2-30 baseline example, the items with the largest distance on their own flex lines are D, J, and K. These items’ outer margins on the cross-start side are placed flush against the cross-start edge of their respective lines, and the other items in the same flex lines have their baseline lined up with D, J, and K’s baseline.

align-items: baseline
Figure 2-30. align-items: baseline

As A, B, C, D, and E all have the same line height, and D has the tallest top margin, they are aligned with D’s baseline, and D’s top margin is flush against the cross-start edge. When it comes to the first line, because they all have the same line height, border, and padding, it looks like they’re lined up like flex-start, but they are actually a little lower, accommodating for D’s top margin. The green line denotes where the baseline is.

In all the examples, we increased the font size for J to 3rem to create a flex item that had a different baseline from all the other flex items. Only when align-items: baseline is set does this impact the flex item alignment within the flex line, as shown in Figure 2-30. When align-items: baseline is set, the baselines of all the items in the second flex line are aligned with J’s baseline, as J is the flex item with the greatest space between the outer top margin and the bottom of the first line of text. Again, the green line denotes the approximate location of the baseline.

Additional Notes

The align-items property is set on the flex container and impacts all of the flex items within that flex container. 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 Chapter 3.

You cannot override the alignment for anonymous flex items (nonempty 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-content Property

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 allows us to dictate how any extra cross-direction space in a flex container is distributed between and around flex lines. This is different from the previously discussed align-items property which dictates flex item positioning within each flex line.

The align-content property determines how flex lines are aligned within a multi-line flex container. When there is extra space in the cross-axis direction, you can dictate whether the lines are grouped at cross-start, cross-end, centered, or stretched to take up all the available space, or distributed across the flex container with the extra space distributed between or around the flex lines.

Think of align-content as similar to how justify-content aligns individual items along the main-axis of the flex container, but for flex lines across the cross-axis of the container. This property only applies to multiline flex containers, having no effect on nonwrapping and otherwise single-line flex containers.

Figure 2-31 demonstrates the six possible values of the align-content property.

Values of flex container's align-content property
Figure 2-31. Values of the flex container’s align-content property

We’ve used the following CSS as the base for the preceding six examples, with no margins on the flex items:

flex-container {
  display: flex;
  flex-flow: row wrap;
  align-items: flex-start;
  border: 1px dashed;
  height: 480px;
}

Distribution of extra space

In Figure 2-31, each flex container has three flex lines. With a height of 480 px, the flex container is taller than the default combined heights of the 3 flex lines. The tallest items in each line—E, F, and K—are 150 px, 180 px, and 30 px, respectively, for a combined total of 360 px. Each flex container has an extra 120 px of free space in the cross-size direction. The cross-start side of each flex line is denoted with a red line, the cross-end side with a blue line; they may appear purple when they overlap. With five of the align-items values, the free space is distributed outside of the flex lines, as is more apparent in Figure 2-32. With stretch, the extra space is evenly distributed between all the flex lines, increasing their cross-size.

Distribution of extra space for the different values of align-content
Figure 2-32. Distribution of extra space for the different values of align-content

Figure 2-32 reiterates the six possible values of the align-content property, with align-items: stretch and flex: 1 set to allow the flex items to grow to take up their entire lines to make the impact of the align-content values more apparent (and generally, to be less of an eyesore):

flex-container {
  display: flex;
  flex-flow: row wrap;
  align-items: stretch;
  border: 1px dashed;
  height: 480px;
}
flex-items {
  flex: 1;
}

Just like in the previous example, with a height of 480 px, and with flex lines 150 px, 180 px, and 30 px tall, we have 120 px of free space along the cross-direction distributed differently depending on the value of the align-content property:

480 - (150 + 180 + 30) = 120

As shown in the first examples in both Figures 2-31 and 2-32, with flex-start the 120 px is on the cross-end side. With flex-end the extra 120 px of available space is at the cross-start side. With center, the lines are centered, with 60 px of extra space at both the cross-start and cross-end sides, as shown in the top-right example of both figures. With space-between, there is 60 px between adjacent pairs of flex lines, as shown in the bottom-left examples. With space-around, the space is evenly distributed around each line: the 120 px is distributed evenly, putting 20 px of non-collapsed space on the cross-start and cross-end sides of each flex line, so there are 20 px of extra space at the cross-start and cross-end sides of the flex container and 40 px of space between adjacent 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 px was added to each of the flex lines. You’ll note in the sixth example in both Figures 2-31 and 2-32, 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, as shown in Figure 2-33.

Figure 2-33 shows the size align-content values when the flex lines overflow their parent flex container. The only difference in the CSS between this and Figure 2-31 is the height of the flex container. We defined height: 240px to create flex containers not tall enough to encompass all their child flex items:

flex-container {
  display: flex;
  flex-flow: row wrap;
  align-items: flex-start;
  border: 1px dashed;
  height: 240px;
}

If the flex lines overflow the flex container, flex-start, space-between, and stretch overflow the cross-end side, stretch and center overflow evenly both the cross-end and cross-start sides, and only flex-end overflows only on the cross-start side.

Appearance of align-content property when lines are overflowing the container
Figure 2-33. Appearance of the align-content property when lines are overflowing the container

align-content: flex-start

With align-content: flex-start, the cross-start edge of the first line of flex items will be flush against cross-start, with each subsequent line placed flush against the preceding line, as shown in Figure 2-34.

Remember, wrap-reverse inverts the cross-direction; with flex-start, the excess space or overflowing lines, if any, is always at cross-end
Figure 2-34. Remember, wrap-reverse inverts the cross-direction; with flex-start, the excess space or overflowing lines, if any, is always at cross-end

In other words, all the flex lines will be grouped together at the cross-start edge of the flex container. Note all the extra space (the extra 120 px in this case) is at cross-end. Remembering the cross-direction is inverted with flex-direction: wrap-reverse (see “The flex-direction Property”), as shown in Figure 2-15. If there isn’t enough room for all the lines, they will overflow at cross-end.

align-content: flex-end

With align-content: flex-end, the cross-end edge of the last line of flex items is placed flush with the cross-end edge of the flex container, and each preceding line is placed flush with the subsequent line, leaving all the extra whitespace at cross-start. In other words, all the flex lines will be grouped flush against the cross-end edge of the flex container. Should the content overflow the flex container, it will do so on cross-start side.

align-content: center

Declaring align-content: center groups the flex lines together, so they are flush against each other, just like they are grouped together with flex-start and flex-end, but in the center of the flex container.

center, flex-start, and flex-end all have each line’s cross-end being flush against the subsequent line’s cross-start. Instead of all the lines being grouped at the container cross-start as in flex-start or at cross-end as in flex-end, with align-content: center the group of lines is centered between the flex container’s cross-start and cross-end, with equal amounts of empty space—60 px on each side in this case—between the cross-start edge of the flex container and the cross-start edge of the first flex line, and between the cross-end edge of the flex container and the cross-end edge of the last flex line, as shown in the top-right example in 2-31 and 2-32. If the flex items overflow the flex container, the lines will overflow equally in both directions past the cross-start and cross-end edges of the container, as shown in the center-left example in Figure 2-33.

align-content: space-between

When align-content: space-between is set, the flex lines are evenly distributed in the flex container. The even distribution is based on the available space, not the size of the lines; the extra space is divided equally among the lines, not proportionally.

If we remember back to justify-content: space-between, the first flex item is flush against main-start. The second flex item, if there is one, is flush against main-end. The rest of the flex items, if there are any, are spread out with equal amounts of the free space distributed between the flex items. This is similar to how align-content: space-between works. 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 the 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.

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.

The middle line, if there is an odd number of lines, is not necessarily centered, as the lines don’t necessarily all have equivalent cross dimensions. Rather, the spacing between any two adjacent lines is the same: there is the same amount of space between the first and second line as there is between any other adjacent flex line, as shown in the bottom left example in Figure 2-32. In this case, we have 120 px total of free space, which gets divided equally, with half, or 60 px, between the first and second flex lines, and 60 px between the second and third flex lines:

120px / 2 = 60px

If there isn’t enough space to encompass all the flex lines, the free space is negative and align-content: space-between appearance is identical to flex-start, with the overflow on the cross-end side.

align-content: space around

The space-around value distributes the lines within a multiline flex container evenly, as if all the flex lines had equal, noncollapsing 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 2-35.

Distribution of free space when align-content: space-around is set
Figure 2-35. Distribution of free space when align-content: space-around is set

In this case we have 120 px of free space distributed to 3 flex lines, with half of each flex lines extra space being added to the cross-start edge and half being added to the cross-end edge:

    (120px / 3 lines) / 2 sides = 20px per side

In this example, there is 20 px on the outer sides of the flex lines, with twice that between any two adjacent flex lines. There is 20 px between the cross-start edge and the first line, 20 px between the cross-end edge and the last line, and 40 px (twice 20 px) between the first and second flex lines and the second and third flex lines.

If there isn’t enough room for the flex lines and they overflow the flex container, the free space is negative, and align-content: space-around value appears identical to center, with the overflow evenly distributed between the cross-start and cross-end sides.

align-content: stretch

Omitting the align-content property, or setting it explicitly to the align-content: stretch default value, makes the lines stretch to take up all the extra available space.

If you take a close look at Figure 2-32, you’ll note that stretch and space-between are actually quite different. In space-between, the extra space is distributed between the lines. In stretch, the extra space is divided into the number of lines and added to the lines. The original lines were 150 px, 180 px, and 30 px tall, respectively. When set to stretch, the extra 120 px is added to the lines in equal amounts. As we have three flex lines and 120 px of extra space, each flex line grows by 40 px, giving us flex lines that are 190 px, 220 px, and 70 px, respectively, as shown in Figure 2-36.

When set to stretch, the extra space is distributed equally, not proportionally, to each line
Figure 2-36. When set to stretch, the extra space is distributed equally, not proportionally, to each line

That extra space, in this example, appears at the cross-end of each individual line since we included align-items: flex-start. Had we used align-items: flex-end instead, the extra space in each line would have been apparent at the individual lines’ flex-start.

If there isn’t enough space to fit all the flex lines, the lines will behave as if set to flex-start, with the first flex line flush against the cross-start edge of the flex container.

We have been taking a look at properties of the flex container. It’s time to take a look at properties directly applied to flex items.

1 Horizontal layout is incorrect for Mongolian. Because of this exception it’s not really a “preference.”