This article aims to explain the 20% of flexbox that you'll use 80% of the time.
What is Flexbox?
Flexbox is a way to describe how elements should be displayed inside another element. The outer element is called the flexbox container, and the inner elements are known as flexbox items.
How does it work?
A flexbox container is created by adding a display
CSS property with a value of flex
on it. Any direct child elements inside this container inherently become flex items. A flex item itself could also be a flex container for its child elements, but consider that as a completely isolated flexbox relationship. A flexbox relationship is always a single level deep between a parent element and one or more children.
After declaring your flexbox container, all flex items will by default be placed horizontally next to one another, starting at the left and stretching to the height of the container.
Flexbox Container properties
To dictate whether flex items should be laid out horizontally or vertically, you set the flex-direction
property to either row
(horizontal default) or column
(vertical). There are also reverse "row" and "column" options available that will lay items out horizontally, from right to left (row-reverse
) or vertically from bottom to top (column-reverse
), assuming you use a horizontal left to right writing mode.
Assuming you use the default flex-direction: row
declaration. To specify how items should be placed on the horizontal axis (known as the main axis), think about the justification options you normally have in a rich text editor, i.e. aligned left, aligned right or centered. In flexbox, you use the justify-content
property on the container to do the same. The default is justify-content: flex-start
that aligns the items at the start of your main axis. Other possible values are flex-end
, your best friend center
, and lesser-used space-between
, space-around
and space-evenly
.
To specify how flex items should be placed vertically in the container, on what is known as the cross axis, you use the align-items
property. The available values are very similar to what you get for justify-content
, with a few exceptions: flex-start
, flex-end
, center
, stretch
and baseline
. By default flex items will stretch the full height of the container. To place items at the top or bottom along the cross axis, use flex-start
or flex-end
respectively. Traditionally, it has been quite hard to vertically centre items using only CSS, but with flexbox, you set align-items: center
and call it a day. The baseline
option is worth knowing about, but you'll use less often. If you have neighbouring flex items containing different sized text and you want to align them based on the bottom of the text, use baseline
.
Have you noticed that we've already catered for most layout requirements, and so far we didn't specify a single CSS property on any flex item? Everything has been on the flex container. Amazing.
With that said, if you need to align items individually, you can set the align-self
property on an item. It takes all the available values that the container's align-items
supports.
It is worth mentioning again that all the examples so far assume a left-to-right writing mode and the default horizontal row flex-direction. When either of these change, the concepts remain the same, only your perspective changes. What I mean is that in a right-to-left writing mode using flex-direction: column-reverse
, items will be justified along the main axis from bottom to top, but now aligned along the cross axis from right to left.
What I've found is that it is easier to grasp the fundamentals first using the standard flex-direction: row
. After that, you can swap the flexbox axes around in your mind to visualize how reversed columns would work.
The last flexbox container property worth talking about is flex-wrap
. By default flex items will not wrap to a new row when they run out of horizontal space. They rather get very cosy and squash together as far as possible until the CSS layout engine decides that's enough.
To tell these items rather wrap to a new row, set flex-wrap: wrap
. As I mentioned, the default is flex-wrap: nowrap
.
That wraps up all the container properties that we're going to talk about. The rest of the properties are all set for individual flex items.
Flexbox Item Properties
The cosy behaviour of flex items to squash together can be overridden with the flex-shrink
property. This property dictates in what proportion an item should shrink inside the container when space becomes scarce. The default is flex-shrink: 1
, which means all items shrink equally. If one of the items is set to flex-shrink: 2
while the rest keep a value of 1
, this item will shrink twice as fast. It is important to note that the value is a unitless value that represents the shrinkage proportion and not something like 10px
or 50%
.
In contrast to flex items' cosy shrink behaviour, they tend to be slightly shy by nature and will not "occupy all spaces" if any free space is available. In more official terms, all flex items have a flex-grow
value of 0
set, which restricts it from growing. Just as with flex-shrink
, flex-grow
is a unitless value that dictates in which proportion an item should grow within a container if any free space is available. It is important to note that if you have two flex items, one with a flex-grow
value of 1
and the other of 2
, that does not mean the one item will be twice as big as the other. It means, from all the available space (if any), the one will receive two portions and the other, one portion.
The final flex item property we'll cover is flex-basis
. You can think of flex-basis
as the width of an item along the main axis. This property needs to be set with any of the standard CSS units, for example px
, rem
, %
, vw
, etc. The default is flex-basis: auto
which means the item takes the width of the content it contains, similar to a display: inline-block
element.
A caveat to this rule is when a width
is specified, in which case the width would trump the default flex-basis: auto
. Another interesting thing to be aware of is that if you have a min-width
specified along with a non-default flex-basis
, the min-width
will always take precedence.
Of course, there is a lot more to flexbox, like shorthand syntax for some of the properties we looked at. Feel free to dig deeper once you're comfortable with these.