Created:
Last modified:
Basic Flex in CSS
I use display: grid on a daily basis and am very comfortable with it. I use
display: flex less often and so am less comfortable with it. It's time for that
to change!
Flex basics
The main axis of a flex container depends on the direction given to it. The default direction is row. When the writing-mode and direction are lr / ltr
this means flex items (child elements of a flex container) start rendering from right to left. If the
direction is set to column items will render from top to bottom. If the writing
ode and direction are changed to rl / rtl and the flex direction is set to row then flex items will display from right to left instead.
From here on I will be talking only in lr / ltr.
Basic display flex set up
The main axis runs in the flex-direction given. For row this means left to right, for column this means top to bottom. The cross axis is then the opposite of this, for row this means top to bottom, for column left to right.
display: flex;
flex-direction: row; *default*
display: flex;
flex-direction: column
Reversing things
Setting the flex-direction to row-reverse or column-reverse causes the flex items to render in the opposite order than they are
written in the HTML.
display: flex;
flex-direction: row-reverse;
display: flex;
flex-direction: column-reverse
Writing Right to Left
display: flex;
flex-direction: row;
writing-mode: rl;
direction: rtl;
display: flex;
flex-direction: column;
writing-mode: rl;
direction: rtl;
Sizing on the cross axis
Flex items will automatically take up the available size of the cross-axis. This means if one of the items
is much larger in that direction, and there is available space, all items will take up the excess space
automatically. This is easy to see in the above flex-direction: column example,
as each column automatically stretches across the width of the cross axis, despite having very little
content. Below we can see this for flex-direction: row by adding more text to
the box.
is
for
Apple
and
Aardvark
Wrapping
Something I find a little odd, personally, is that the default for flex-wrap is
nowrap, meaning if flex items take up more space on the main axis than the
document can display the items will overflow. That I find it odd is very possibly due to less experience
with flex. I'd have just thought the automatic should be to not cause the items to overflow, likely causing
the page be able to scroll where we don't want it to.
Now because of how much I hate pages overflowing, I have set the below flex container with overflow: auto so that the flex items will overflow and cause the flex container to
scroll, not the whole page.
And then the same items, but with flex-wrap: wrap set:
Below I have added flex-grow: 1 to the flex items to highlight how each new
line that the flex container wraps onto is see as a separate flex container. This means that the sizing of
the flex items per row is based on fellow flex items on the same row, not those above or below.
Short hands
Flex settings come with the option to use short hands to discribe multiple settings in one row. flex-flow: row wrap sets flex-direction: row and flex-wrap: wrap.
Growing, Shrinking and staying the same
Flex items can take a variety of properties to aid in automatic sizing. By default flex items simply
take up the default space for that item, not stretching across it's main axis. The default settings are
flex-grow: 0, flex-shrink: 1 and flex-basis: auto.
Growing
If we want each of the items to share the available space along the main axis evenly, we can set flex-grow: 1. In fact we can set that value to any positive number. So long as all
items have the same value, the items will share the available space evenly.
Now say we want B to be larger than the others, we can set the flex-grow property for that flex item to be a larger number, in this case I've set
it to flex-grow: 1. The remaining available space will be devided between any
items given a positive flex-grow property, and as we are only setting this on
one item, that item will receive all available space.
However if there is another flex item which also has the a positive flex-grow
property value, the available space is shared between these flex items based on that value.
nth-child(1): { flex-grow: 0 };
nth-child(2): { flex-grow: 1 };
nth-child(3): { flex-grow: 2 };
Shrinking
Like with flex-grow, flex items have an optional property flex-shrink to control if and how fast an item might shrink. In a situation where
other flex items have a smaller flex-shrink value and/or a positive flex-grow value, the item with the smaller flex-shrink
value will shrink faster in comparison to the other items.
nth-child(1): { flex-grow: 1 };
nth-child(2): { flex-shrink: 1 };
nth-child(3): { flex-grow: 1 };
nth-child(1): { flex-grow: 1 };
nth-child(2): { flex-grow: 2; flex-shrink: 2 };
nth-child(3): { flex-shrink: 3 };
The smallest a flex item can shrink to is it's min-content value.
nth-child(1): { flex-grow: 10 };
nth-child(2): { flex-shrink: 1 };
nth-child(3): { flex-grow: 1 };
nth-child(1): { flex-grow: 10 };
nth-child(2): { flex-shrink: 1; width: 1px; padding: 0 };
nth-child(3): { flex-grow: 1 };
Interestingly, according to the specifications, when flex-shrink is applied,
items shrink in proportion to their ability to shrink. So a larger item will shrink faster than a smaller
one..?
nth-child(1): { flex-grow: 10 };
nth-child(2): { flex-shrink: 1 };
nth-child(3): { flex-grow: 1 };
Flex-basis
Yet another property of flex items is the flex-basis property. It's default
value is auto. If it is not explicitly set, and the item hasn't been given a
width value then the flex-basis value is set to the
size, in fact the max-content size of the item along it's main axis.
A value of content can be given to flex-basis which
means that the initial value will be the max-content on the flex item, even if that item has been given an
explicit width value:
nth-child(1): { flex-basis: 0; width: 20rem; };
nth-child(2): { flex-basis: auto; width: 20rem; };
nth-child(3): { flex-basis: auto; width: 100%; }
nth-child(4): { flex-basis: content; width: 20rem; }
nth-child(5): { flex-basis: 20rem; width: 100%; };
Putting them altogether
As discussed, flex items have the available properties flex-grow, flex-shrink and flex-basis. There is also a short-hand
for this, flex where the first given value represents flex-grow, the
second flex-shrink and the third flex-basis.
For the below example the flex-basis property is set to 'auto', meaning the
initial size is based on the max-content width. Available space is then shared
evenly between the elements, adding onto their original widths.
* { flex: 1 1 auto }
Setting flex-basis to 0 means that if there is any available space, it is
shared in such a way that smaller items are given more, until they match the size of a larger item, and then
the remaining space is distributed evenly between items. This means that given enough available space all
items will be the same size.
* { flex: 1 1 0 }
In the below example, because flex-basis is set to 0, the available space is
devided between the flex items depending on their flex-grow value. This value is
used as a ratio when dividing the available space, and in this example the space will be distributed in
6ths. Therefore the first item will get 1/2 (3/6), second item will get 1/3 (2/6) and the final item will
get 1/6 of any available space.
nth-child(1) { flex: 3 1 0 }
nth-child(2) { flex: 2 1 0 }
nth-child(3) { flex: 1 1 0 }
Here we're playing with different rates of shrinking. The first flex item has flex-shrink set to 0, so it won't ever shrink, the second is set to 1 and the third
set to 3. So the available space each of the last two items has to shrink to accomodate the first items
width when the window or container is sized down. The rate at which they decrease in size depends on their
flex-shrink value. A larger value means more available space will be removed
from this item than a smaller valued item. The available space is divided by 4 (given the 1 and 3 set to
these two items) with 3/4 of the needed space is taken from the second item, 1/4 from the third.
nth-child(1): { flex: 1 0 auto; width: 200px };
nth-child(2): { flex: 1 1 auto; width: 200px };
nth-child(3): { flex: 1 3 auto; width: 200px };
A nice explanation of this can be found on the CSS Reference website.
nth-child(1): { flex: 1 0 auto; width: 200px };
nth-child(2): { flex: 1 1 auto; width: 400px };
nth-child(3): { flex: 1 3 auto; width: 600px };