A Long Time Coming #
Flexbox, short for flexible boxes—which folks will often just shorten all the way to flex—is a later (mid-2010s, slow adoption) addition to CSS.
-
CSS Flexbox Layout Guide – CSS Tricks
This page is a classic! It probably bought Chris Coyier a house. -
Basic Concepts of Flexbox – MDN
Can’t go wrong. -
Flexbox Froggy
A little game.
Flex was created to facilitate and allow CSS layouts that the box model (despite its float
and position
) either made difficult, brittle, or even impossible. It is a display property. It’s extremely useful and widely-used.
And let us tell you—being a web designer was a whole lot harder before flex came on the front-end scene. (Hence the “Finally.”) Notice, for instance, that we haven’t talked about any vertical centering at all yet—you don’t want to know! And you don’t have to worry about it. Flex encapsulates a lot of practical, helpful design paradigms in its system.
Main /Cross Axes #
Flexbox is a one-dimensional layout system—meaning it is (usually) focused on arranging items either horizontally in rows, or vertically in columns.
These are called the axes. The one running in the direction of your flex items is your main axis; perpendicular to this is your cross axis:
.some-container {
display: flex;
flex-direction: row; /* Default! */
}
.some-container {
display: flex;
flex-direction: column; /* Rotated! */
}
Start /End, Justify/Align #
Flex also lets us position elements along/within the axes, in both directions—in relation to the start
or the end
of the direction.
For the main axis, you justify
; for the cross axis, you align
:
.some-container {
display: flex;
flex-direction: row; /* Default! */
}
For rows (the default): justify
moves items left /right, align
moves top/bottom.
.some-container {
display: flex;
flex-direction: column; /* Rotated! */
}
For columns (rotated): justify
moves items top/bottom, align
moves left /right.
Shorthand #
Like a lot of CSS, flex has shorthand properties.
But again, we would avoid them—the system can be hard enough to understand. This will be true when we get to grid
as
Container (Parent) Properties #
Unlike most (…all?) of the CSS we’ve been introduced to, flex is applied on a parent element—but actually adjusts the layout of the children. An element with display: flex;
is really telling you what its kids are going to be doing.
There is also display: inline-flex;
which behaves the same, but the parent behaves as an inline
element while its children are flexing. You don’t see it used very much.
flex-direction
#
After specifying an element as flex, we can set its main axis with the flex-direction
property. By default (you don’t have to write it), this behaves as flex-direction: row;
—so you’ll generally only be adding it when you want something going vertical, with flex-direction: column;
:
You can also combine these with a -reverse
suffix, which visually reorders the items along the main axis, flipping the start
and end
:
Keep in mind that all flex reordering is only visual—it obviously can’t change the order in your HTML. This means that keyboard navigation and screen readers still sequence through the items as they are in your code. So for good, logical accessibility, keep in mind the semantic reading order!
flex-wrap
#
Since flexbox is one-dimensional, by default it will try to cram everything into one flex-wrap: wrap;
property/nowrap
by default):
There is also a -reverse
suffix when wrapping, which will sequence items from end
to start
:
justify-content
#
So most of what we’ve seen here is… somewhat possible using float
and position
—though not at all easily and only when you know the size/counts of your content.
But the justify-content
property is where flexbox starts to allow novel layouts, by dividing up the extra /available free space between elements—akin to distribute options in Figma /justify-content
does this on our main axis:
When our main axis is vertical, with flex-direction: column;
:
align-items
#
And then perpendicular to justify
along the main axis, flexbox has the align-items
property to position elements along the cross axis. It has similar values:
And for the vertical:
align-content
#
When we have a flex element with flex-wrap
set, we can also position the lines within the parent/container with the align-content
property—akin to justify-content
with each line:
And align-content
can also be used with a vertical/flex-direction: column;
axis, not shown here. This doesn’t often come up, as you have to specify/know a height to force a column wrap.
gap
, row-gap
, and column-gap
#
While you could use margin to separate your flex children, it would apply to the items on the outer edges, too. (Hence our many :not(:first-child)
selectors for margin
in the examples, so far.)
Flex added support for intuitive gap
properties, which fix this problem—by applying spacing only between children. This is particularly helpful with dynamic, wrapping content and responsive designs—where you won’t always know which element ends or starts a line (to take their margin off):
Item (Child) Properties #
Flexbox is usually applied on the parent/container. But once you’ve set display: flex;
on an element, there are also some individual override properties that can be given to its children, flex items.
order
#
Kind of like the -reverse
suffix—you can individually apply the order
property to a flex item (child). Items with the same/tied order (like everything with the default of order: 0;
) will be displayed in their HTML/source order:
Other order-based selectors (like :first-child
) won’t be fooled by this reordering—as you can see, we used them here. They still use the HTML order. And again, this change is only visual—so don’t use it when screen reader/content sequence accessibility is a concern!
flex-grow
and flex-shrink
#
These properties tell the flex items to… grow
or shrink
, if necessary—defining the amount of available/remaining space in the container an element should take up—filling the whole container, like bento boxes.
It takes a unitless proportional value, akin to fractions or a factor/multiplier. If you give one flexed child flex-grow: 1;
it will take up all the extra space; another element with flex-grow: 2;
would then take twice as much of that space as the first one (the available space with 3 total units):
And flex-shrink
works the same way—defining what proportion an element should shrink when forced to by the flex layout. The most use you’ll see of this is flex-shrink: 0;
, which tells all the other items to shrink instead!
flex-basis
#
The flex-basis
property is a little like width
and height
—depending on your main axis. It defines what the child item’s content box size should be before any remaining space is distributed.
This defaults to auto
, which falls back to any specified width
or height
—and if those aren’t present, will just use the size of the content. You specify this flex-basis
with length units like %
and px
:
align-self
#
Finally, we have an individual override for an align-items
property set on the parent—the align-self
property—which adjusts (with the same keywords/values) the alignment of the specific child item it is applied to:
This is a lot of stuff! Flex can sometimes be tough to wrap one’s head around, but it is so much better than float
and width
and margin
shenanigans.
Much of what you look at on the web is laid out in flex (and its followup which we keep hinting at, CSS Grid).