Finally, flexbox

Flexbox, short for flexible boxes‚ÄĒwhich folks will¬†often just shorten all¬†the way to¬†flex‚Ā†‚ÄĒis a¬†later (mid-2010s, depending on¬†how you count) addition to¬†CSS.

Flex was created to facilitate and allow CSS layouts that the box model (with its floats and position) either made difficult, brittle, or even impossible. It is a display property. It’s extremely useful.

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 and 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 and end, justify and 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.


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¬†well‚ÄĒoften being a¬†little bit more verbose in¬†your code will make things easier to¬†understand, especially starting out.

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.


After specifying an element as flex, we can set its main axis with flex-direction.

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;¬†:

The first list is display: block; by default. Also note that we gave them all a min-height, to show start/end!

You can also combine these with a reverse option, which visually reorders the items along the main axis, flipping the start and end:


Since flexbox is one-dimensional, by default it will¬†try to¬†cram everything into one line‚ÄĒeven when there is not enough room!

But you can tell it to wrap onto additional lines by adding a flex-wrap: wrap; property (which is set to nowrap by default):

Without the height restriction, the last one would just grow taller, by default.

You can use this to make grids, and it is often sufficient. But but the more recent CSS grid properties will give you more control! We’ll talk about grid soon.

There is also a reverse option here, which will wrap items from end to start:

You could do some weird layouts with these, but keep in mind the order is still only visual.


So most of what we‚Äôve seen here is somewhat possible using floats and positioning‚ÄĒthough not at all easily and only when you know the size/count of your content.

But justify-content is where flexbox starts to¬†allow novel layouts, by dividing up the extra/available free space between elements‚ÄĒakin to¬†distribute options in¬†Figma/Adobe applications. justify-content does this on¬†our main axis:

The start / end values have some nuance with different writing directions, but this doesn’t come up often.

When our main axis is vertical, with flex-direction: column; :

These only works with the height to¬†justify within‚Ā†‚ÄĒotherwise the container would cinch up to¬†the content height, as¬†usual.


And then perpendicular to justify along the main axis, flexbox has align-items to position elements along the cross axis. It has similar values:

And for the vertical:

The align-items: baseline; wouldn’t do anything, here.


When we have a¬†flex element with flex-wrap set, we can also position the lines within the parent/container‚ÄĒakin to¬†justify-content with each line:

These wouldn’t do anything without the height and the flex-wrap.

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 all our :not(:first-child) selectors 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):

Note the last one, gap are really minimums and only apply when there isn’t otherwise space.

Note that the justify, align, and gap properties are also shared (in name and behavior) with display: grid;, when we get there!

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.


Kind of like the reverse properties‚ÄĒyou can individually apply an¬†order 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:

With the last one, since the default is order: 0;, negative numbers move stuff up to the front!

Other order 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 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 is a¬†little like width and height‚ÄĒdepending on¬†your main axis. This property 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 basis with length units like % and px :

You are usually fine just specifying width / height.


Finally, we have an¬†individual override for an¬†align-items property set on¬†the parent‚ÄĒwhich adjusts (with the same keywords/values) the alignment of the specific child item it is applied¬†to: