Creating Flexible Layouts with Flexbox
The following introduction to Flexbox is an extract from Tiffany’s new book, CSS Master, 2nd Edition.
Before CSS Grid came along, there was Flexbox (which is officially known as the CSS Flexible Box Layout Module). Flexbox was designed to manage layout in one direction—a row (flex-direction: row
or row-reverse
) or a column (flex-direction: column
or column-reverse
). That’s in contrast to Grid, which accounts for rows and columns.
A basic flexible box layout is simple to create: add display: flex
or display: inline-flex
to the containing element. These values for display
will trigger a flex formatting context for that containing element’s children. As with Grid, both flex
and inline-flex
are inside display modes. We set these values on the container, which behaves like a block-level or inline-level box, respectively. The children of that container are then arranged according to the rules of flex layout.
Note: Older versions of Blink-based browsers such as Chrome (≤ 28), and WebKit-based browsers like Safari (≤ 8), require a vendor prefix. If your project still supports those browsers, you’ll need to use display: -webkit-flex
or display: -webkit-inline-flex
. Older versions of Firefox (≤ 21) also require a prefix. Use -moz-flex
and -moz-inline-flex
to support those browsers.
By adding display: flex
or display: inline-flex
to a containing element, its immediate children become flex items, as shown in the image below. Flex items may be element children or non-empty text nodes. For instance, the markup below generates three flex item boxes that each behave according to the rules of flex layout:
<div style="display: flex">
<span>This text is contained by a SPAN element.</span>
<b>This text is contained by a B element.</b>
This text node is still a flex item.
</div>
If no other properties are set, each flex item will have the same height as its tallest element (as determined by content). It will also stack horizontally (or vertically when the document has a vertical writing mode) without wrapping, and with no space between the edges of each box. Flex items may overflow the container.
display: flex
applied to the ul
containing element
This may not seem like such a big deal, but it simplifies the code necessary for a range of user interface patterns. Let’s look at a couple of examples.
A New Media Object Component
Take the following media object code:
<div class="media__object">
<img src="video-thumb1.jpg">
<div class="media__object__text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
</div>
Before Flexbox, we might have paired the preceding markup with the following CSS:
.media__object img {
float: left;
height: auto;
width: 150px;
}
.media__object__text {
padding-left: 170px;
}
/* Let's use the clearfix hack! */
.media__object::after{
content: ' ';
display: block;
clear: both;
}
This layout works, but it has one major drawback: it requires us to constrain the width of our images so that we know how much padding to use. That limits our ability to use this same component in multiple contexts. You may want an image 150px wide when this component is used for a “Related Stories” widget, and one that’s only 75px wide for comments.
Let’s try this using Flexbox. Here’s our updated CSS:
.media__object {
display: flex;
}
.media_object img {
margin-right: 20px;
}
That’s a lot less CSS. An added bonus is that we don’t have to worry about how wide or tall our image is. Nor do we have to concern ourselves with clearing floats. Whether the image is 200px wide or 20px wide, .media__object__text
will abut the margin box of our img
element.
Creating Flexible Form Components with flex
Another use case for Flexbox is creating flexible, vertically aligned form components. Consider the interface pattern shown in the image below.
Here, we have a form input control and an adjacent button. Both are vertically aligned, and our button is 150px wide.
What if we want our input
element to expand to fill the available space in its container? Without Flexbox, we’d need some JavaScript and hand-waving to update the width of input
in response to changes in the width of its parent. With Flexbox, however, we can just use flex
.
The flex
property is actually shorthand for three other properties.
flex-grow
indicates that an element should grow if necessary and must be a positive integer. Its initial value is0
.flex-shrink
indicates that an element should shrink if necessary and must be a positive integer. Its initial value is1
.flex-basis:
indicates the initial or minimum width (when the flex axis is horizontal) or the height of an element (when it’s vertical). It may be a length or percentage, orauto
, and its initial value isauto
.
Though it’s possible to set each of these individually, the specification strongly recommends using the flex
shorthand. Here’s an example:
div {
display: flex;
}
input[type="text"], button {
border: 0;
font: inherit;
}
input[type="text"] {
flex: 1 0 auto;
}
button {
background: #003;
color: whitesmoke;
display: block;
text-align: center;
flex: 0 0 150px;
}
Here, we’ve used flex: 1 0 auto
for our input
element. Since its flex-grow
value is 1
, it will grow to fill the available space of its parent. For the button
element, however, we’ve used flex: 0 0 150px
. The 0
values for flex-grow
and flex-shrink
prevent the width of the button from increasing or decreasing, while the flex-basis
value of 150px
sets its width.
As you can see in the image below, our button remains the same size, but the width of input
expands to fill the remaining space.
flex: 0 0 150px
The tricky bit about flex-grow
and flex-shrink
values is that they’re proportional. Yes, flex: 1 0 auto
means our input
element will be wider than our button. But changing the value of our button’s flex
property to flex: 1 0 auto
doesn’t necessarily mean that both elements will have the same size, as shown in the following image.
Instead, flex items will be resized to fill the container, taking their used min-width
and max-width
values into account (which may be their initial values).
Unfortunately, we can’t use fr
units with the flex
or flex-basis
properties. Use length or percentage values instead.
Vertical Centering with Flexbox
Finally, let’s take a look at how to vertically center content with Flexbox. Vertically centering elements is one of the more difficult tasks to achieve with CSS, particularly if the height of your content is unknown. But with Flexbox, we require just one additional line of CSS—align-items: center
:
.flex-container {
display: flex;
align-items: center;
}
Now our flex items and their contents are vertically centered within the flex container, as shown in the image below.
align-items: center
Creating Grid-like Layouts with Flexbox
In most cases, you’ll want to use Grid to create grid-like layouts. However, you may find yourself wanting boxes that align when there’s an even number of items, but expand to fill the available space when there’s an odd number.
Here’s the markup we’ll use:
<ul class="flex-aligned">
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
<li>E</li>
<li>F</li>
<li>G</li>
</li>
By default, flex items don’t wrap. To achieve the layout above, we’ll need to make them wrap using the flex-wrap
property. It accepts three values: nowrap
(the inital value), wrap
, and wrap-reverse
. We’ll use wrap
here:
.flex-aligned {
display: flex;
flex-wrap: wrap;
}
Now we just need to indicate how our flex items should behave, and what their maximum width should be. Since we want a maximum of four columns, we’ll set our flex-basis
value to 25%
. And since we want our flex items to expand to fill the available space, we’ll set flex-grow
to 1. We’ll keep flex-shrink
at 0 so that our boxes never occupy less than 25% of their container:
.flex-aligned li {
flex: 1 0 25%;
}
Learning More about Flexbox
There’s a lot more to Flexbox than what we’ve covered here. CSS-Tricks’ “A Complete Guide to Flexbox” digs into all the properties and values. You can also check out Philip Walton’s “Solved by Flexbox”, which showcases UI patterns that are made easier with Flexbox.
Choosing flex
or grid
As you develop page or component layouts, you may find yourself wondering when it’s better to use Flexbox and when to use Grid.
- Use Grid when you want to arrange elements into rows and columns that align both horizontally and vertically.
- Use Flexbox when you want to arrange items in a row or a column, when you wish to align items vertically or horizontally, but not both.
Jen Simmons’ video “Flexbox vs. CSS Grid — Which is Better?” walks you through some things to consider when choosing between Grid and Flexbox. Rachel Andrew’s “Should I use Grid or Flexbox?” is another great resource for understanding both.
In practice, your projects will probably mix both of these techniques, as well as floats. For instance, you may use Grid to define the overall page layout, while using Flexbox for your navigation menu or search box, and floats to place tables or images.