Flexbox
CSS layouts can be tricky when working with items that need to span across their parent element.
Flexbox is a powerful tool with CSS that allows for interesting layouts and common things to be a lot easier than using positioning, floats, and the traditional box model.
Opting in to Flexbox
Flexbox works on the concept of flex parents and flex children.
Flex Parent elements are created by display: flex;
.
Note that element acts similar to the display: block
in the way that the box model effects the current element.
However when we set an element to display: flex
, all of its direct children now become "flex items".
This means that for flex items, the traditional box model is changed.
Child
Child
Child
Child
<div style="display: flex; background: red;">
<p style="padding: 1rem; background: blue; color: white;">Child</p>
<p style="padding: 1rem; background: white; color: blue;">Child</p>
<p style="padding: 1rem; background: blue; color: white;">Child</p>
<p style="padding: 1rem; background: white; color: blue;">Child</p>
</div>
Breaking Down Flexbox Basics
Once a flex parent has been created, the first thing that we see is that all of its children begin to line up as if they were floated (without us having to float all of those items). This is the first hint at what flexbox is doing.
The "Flex Axis" and flex-direction
The flex items begin to lay themselves out ACROSS a "flex axis" in the parent. This "flex axis" is an invisible line that goes from the left edge to the right edge of the "flex parent" element.
This axis can be changed with the flex-direction
property which has four different values:
row
(default) - Elements line up from left to rightrow-reverse
- Elements line up from right to leftcolumn
- Elements line up from top to bottomcolumn-reverse
- Elements line up from bottom to top
To continue investigating flexbox we will need to look at a few more properties.
Child
Child
Child
Child
<div style="display: flex; flex-direction: column; background: red;">
<p style="padding: 1rem; background: blue; color: white;">Child</p>
<p style="padding: 1rem; background: white; color: blue;">Child</p>
<p style="padding: 1rem; background: blue; color: white;">Child</p>
<p style="padding: 1rem; background: white; color: blue;">Child</p>
</div>
Breaking Down the flex
Property
To see flexbox items do something interesting, let's set our "flex children" to have a property of flex: 1;
.
Now, we can see that the flex children take up the full width of the flex parent.
Child
Child
Child
Child
<div style="display: flex; background: red;">
<p style="padding: 1rem; flex: 1; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 1; background: white; color: blue;">Child</p>
<p style="padding: 1rem; flex: 1; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 1; background: white; color: blue;">Child</p>
</div>
What's actually happening under the hood is actually more complicated than it looks at first glance.
The flex
property is actually a compound property that is setting things for flex-grow
, flex-shrink
, and an optional value for flex-basis
.
The flex-grow
property describes how the flex container divies up any extra whitespace after the "flex items" line themselves up.
On the other hand flex-shrink
, tells the browser what to do if the the flex parent doesn't have enough room for all of the "flex item" children.
Then the flex-basis
says what point should be used to start making the decision to grow or shrink (think of this as sort of being like width
if the parent flex-direction
is set to row
).
So if we want items to grow but not shrink we could set flex: 1 0
.
Now what does that 1
mean?
This is the multiplier which decides the priority of how elements grow or shrink.
For instance look a slightly modified example from the one above:
Child
Child
Child
Child
<div style="display: flex; background: red;">
<p style="padding: 1rem; flex: 3; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 1; background: white; color: blue;">Child</p>
<p style="padding: 1rem; flex: 1; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 1; background: white; color: blue;">Child</p>
</div>
Note how the first item is larger than the items the come later.
This is because the flex: 3
states that the first element will take up 3px of extra whitespace for every 1px given to the other flex: 1
elements.
NOTE
flex-grow
andflex-shrink
multipliers do not give a perfect size multiplier, instead they describe the way that extra whitespace or shrinking should be done.
Easy Grids with Flexbox
Working with flexbox the use of grids becomes trivial. Let's look at a "Three Up" example:
Child
Child
Child
<div style="display: flex; background: red;">
<p style="padding: 1rem; flex: 1; background: white; color: blue;">Child</p>
<p style="padding: 1rem; flex: 1; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 1; background: white; color: blue;">Child</p>
</div>
Ok... So this is a bit of a lie watch what happens to our "Three Up" when there are four child elements:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
<div style="display: flex; background: red;">
<p style="padding: 1rem; flex: 1; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; flex: 1; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 1; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; flex: 1; background: blue; color: white;">Child</p>
</div>
So if we want to keep this as a "Three up grid", we will need to set the flex-basis
to 33%
and the flex-shrink
to 0
so that the items don't shrink:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
<div style="display: flex; background: red;">
<p style="padding: 1rem; flex: 1 0 33%; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; flex: 1 0 33%; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 1 0 33%; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; flex: 1 0 33%; background: blue; color: white;">Child</p>
</div>
Still no dice, so we'll need another property to help make this work.
flex-wrap
The flex-wrap
property is placed on the Flex Container and describes what to do with child Flex Items that overflow out of bounds on the flex-direction
axis.
So, by changing the flex-wrap
on our parent div, we can get our "Three Up" to start working again:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
<div style="display: flex; flex-wrap: wrap; background: red;">
<p style="padding: 1rem; flex: 1 0 33%; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; flex: 1 0 33%; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 1 0 33%; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; flex: 1 0 33%; background: blue; color: white;">Child</p>
</div>
Now we are fighting our own flex-grow
property.
Since the Fourth item drops to the next row, it then tries to take up the full row since that is what flex-grow
does!
So let's change flex-grow
to 0
:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
<div style="display: flex; flex-wrap: wrap; background: red;">
<p style="padding: 1rem; flex: 0 0 33%; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; flex: 0 0 33%; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 0 0 33%; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; flex: 0 0 33%; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 0 0 33%; background: white; color: blue;">Child</p>
</div>
Right now this probably doesn't seem too different than floats, but compare the difference in the grid item heights:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
<div style="background: red;">
<p style="width: 33%; float: left; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="width: 33%; float: left; background: blue; color: white;">Child</p>
<p style="width: 33%; float: left; background: white; color: blue;">Child Child Child Child Child Child Child Child Child</p>
<p style="width: 33%; float: left; background: blue; color: white;">Child</p>
<p style="width: 33%; float: left; background: white; color: blue;">Child</p>
</div>
align-items
Notice in the float example, the grid items aren't the same height, instead they are only as tall as the content that we put inside.
By using flexbox, all of our grid items will be the same height.
To change this, we can change the align-items
property on the Flex Container.
stretch
stretch
is the default and makes all items span the same height (assuming flex-direction: row
).
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
flex-start
flex-start
aligns the top edge of our flex items (assuming flex-direction: row
).
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
flex-end
flex-end
aligns the bottom edge of our flex items (assuming flex-direction: row
).
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
center
center
lines up the center of the different items (assuming flex-direction: row
).
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
align-self
When working with aligned flex items, there are times where you may want to break out of default align-items
that is set by the parent.
In this example, the third item uses align-items: flex-end
to pin to the bottom instead of the center
value specified by the parent flex container.
Child
Child Child Child Child Child Child Child Child Child
Child
Child
Child
<div style="display: flex; align-items: center; flex-wrap: wrap; background: red;">
<p style="padding: 1rem; flex: 0 0 33%; background: white; color: blue;">Child</p>
<p style="padding: 1rem; flex: 0 0 33%; background: blue; color: white;">Child Child Child Child Child Child Child Child Child</p>
<p style="padding: 1rem; align-self: flex-end; flex: 0 0 33%; background: white; color: blue;">Child</p>
<p style="padding: 1rem; flex: 0 0 33%; background: blue; color: white;">Child</p>
<p style="padding: 1rem; flex: 0 0 33%; background: white; color: blue;">Child</p>
</div>
Justifying content
When working with grids, there are times where we may not have an even amount of items to divide into rows.
When we had five items, we could expand across the last row by leaving flex-grow
something other than 0
.
But there are other things that we can do too.
justify-content: flex-end
:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
justify-content: center
:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
justify-content: space-between
:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
justify-content: space-around
:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child
align-content
align-content
describes how the group of flex items interact with the cross axis if there is any extra room.
This only takes effect if there is extra room to spare along the cross axis.
The values work in the same way as justify-content
but it acts on the flex items as a whole, not individual items.
For example align-content: flex-end;
:
Child Child Child Child Child Child Child Child Child
Child
Child Child Child Child Child Child Child Child Child
Child
Child