Place things around the page is essential in making a site, and doing it
manually can be a bit of a pain. Let's learn how to customize the
position of elements in your page in a more flexible and modern way.
After reading this guide you should have a good enough understanding of
Flexbox and its features to use it on your own project.
Flexbox or "Flexible Box Module" is a css tool used to align many items
easily along one direction. It is basically a somewhat automatic layout
that will place the various elements along the page in a responsive way
according to the width of the user screen.
The main drawback? The fact that it is somewhat better suited to arrange
items along only one direction, so if your site will have lots of
vertical AND horizontal movement flexbox will not shine. For that Grid
is more appropriate, or a mix of the two. Check out my
Grid Guide here.
Let's start with the basics: you'll want to create a class and to activate flexbox in it.
.flexbox { display: flex;
flex-direction: column; }
In that example "display:flex" is the command that you need to enable
flex. The second thing you need to do is to choose a direction for the
elements to flow towards.
As we said the flexbox shines to align things over one direction only:
here is where you choose which direction that is!
By default it is actually already row, so you would usually write this
only if you wanted to specify something different.
There are 4 directions that you can choose from: row and column are the basics. And then there are "row-reverse" and "column-reverse" which are basically the exact same direction, but instead of ordering the elements as 1-2-3 they'd do 3-2-1.
<div class="flexbox flex-row-reverse">
<div class="box1">
Box 1
</div>
<div class="box2">
Box 2
</div>
<div class="box3">
Box 3
</div>
</div>
Basically we just wrapped a div with the flexbox enabled and here we go: the page will now automatically try to arrange the items based on our chosen direction. There is much more customization available of course, so now we'll go through it.
Let's start with a situation where we might have many elements on one row flex container. What would happen?
They are all squished together! Same thing could happen if the flexbox was a column. But what if would like these to go to the next line automatically if they don't fit in one line?
Say hello to the flex property "flex-wrap:" accepting the values "nowrap" (the default one), "wrap" and "wrap reverse".
Nice! We were able to spread them over multiple lines although... they did not spread very evenly. Let's look at how to improve on that, but first a "pro-tip"!
Changing things one by one is always good, but the two commands that we have just learned are used so often together while working with flexbox, that a new command merging them was created: "flex-flow".
Basically instead of using "flex-direction: column" and "flex-wrap: wrap-reverse" for example, to have the same effect you can just write:
flex-flow: column wrap-reverse;
So you've made your flexbox container and chosen a direction were things
should go to. Great! Now what if you don't want all the things to just
stay squished at the top left corner of your container? You gotta set
their "justify-content" value!
The important take away here is: if you want to arrange elements
along your specified direction, you should use
this.
Let's see which options "justify" takes.
All these boxes have no padding or margin but have a small black border, to better show the effect of flexbox on content. There also is a transparent box around the elements to better show their placement on the chosen direction.
Squished to the top left!
Squished to the top right!
Squished in the middle!
Dividing elements by giving each the max amount of distance available.
Dividing elements by cushioning them inside 2 equal spaces. There are thus 2 spaces between each element and 1 space from the page's border.
The most even spacing: the elements are given equal distances, both between themselves and the page's border.
You have established a flex-direction (let's say row), but what you don't know is that you have some degree of control also on the other axis: the so called "cross axis" (in this case column).
Let's first look at the most visually noticeable one: "align-items" and it's properties.
Pushing all the items at the top of the cross-axis. Here that means above, on a row it would be left.
Pushing all the items at the bottom of the cross-axis.
Placing all the items in the middle of the cross-axis.
This is the default setting for a flexbox. Every element is stretched at the size of the biggest element of the group.
Baseline aligns the content of each element, so that it will all align itself over the same line. No matter the container size. To explain a bit further, fonts sit on an invisible straight like called "baseline". This option will ensure all the different elements will align on this same line.
There is a more subtle way to influence the elements along the cross axis. You can basically choose the spacing between the elements on multiple lines, with "align-content". It's important to know that this setting would have no effect if your content is all on one line, so it's useful only if paired to something like flex-wrap.
Squished towards the top of the container, no spaces.
Squished towards the end of the container, no spaces.
Squished towards the middle of the container, no spaces.
The default setting: no spaces, elements stretched on the cross-axis to all have the same size.
Now we see spaces. Max distance available between all elements, pushed to the sides fully.
Even spaces. Equal size paddings are given to both sides of any element, meaning two elements have both their paddings between them.
We can use options to modify the content of the flexbox containers individually!
All the elements of a container can be aligned together with a nice
"align-items" to behave in a certain way along the cross-axis.
But there is actually a way to target a specific element of the group
and to place only that element in a different alignment of your choice!
Meet align-self. Every parameter already used
in align-items is available, so here are two examples.
Placing all the items in the middle of the cross-axis, other than that disobedient blue box which is going "flex-end".
Every element is stretched at the size of the biggest element of the group. But not the pesky green box which is "baseline". It's also interesting to notice how a baseline without another element to "baseline" with, doesn't really work and just looks like flex-start.
We are unlocking endless amounts of freedom already, but there is more. What if I told you that you can even move items inside the same flex direction! For this trick we will need a new volunteer: "order".
Every element in a flexbox group has a hidden rank, which chooses where
it is placed in the line. Every element by default has hidden rank of 0.
By using "order" we can specify a different rank: the smaller the number
the more to the left it will go (negative numbers are allowed). The
bigger the number, the more to the right.
This is the last fine tuning available on flexbox and it's perhaps more
complex than the other ones.
At the core it's giving you the control over the shrinking and growing
of the elements in a flexbox. More specifically it's also giving you
control of how they change size in proportion to each other.
This is particularly useful to manage the otherwise empty space that
could be present in a group of elements.
The command that you will use for these options is
"flex: ;". It's important to notice that "flex" is not
applied to a container of elements, but directly on the elements that we
wish to influence.
Flex accepts two types of values:
For situation (B) it's just a matter of memorizing what they do, and it's actually the most comfortable way to use flex as these settings cover most scenarios.
But let's delve deeper into case (A) so that we can understand exactly what we are doing with this flex setting.
A flex command in (A) will usually look something like this:
And what it's saying it's actually this:
"flex: 0 1 auto" are actually the default settings for any flexbox container. If the elements are not specifically set to behave differently, the whole group would behave as if they had flex: 0 1 auto as parameters.
While shrink and grow only accept 0 (disabled) or 1 (enabled) as values, the third value (flex-basis) is a bit more... flexible.
Flex basis fundamentally can be three things:
Let's see this commands in action to better understand them and at the
same time learn the short hands of Flex (B).
In the next examples every element has been given directly the flex
attribute shown above.
Every flexbox container would behave like this by default, and so do all the examples above in the page. Here the elements are not allowed to grow to fill the empty space, but they are allowed to shrink so that they won't overflow out of the container. The basis answers to the specified size first, and to the content inside after.
Let's see more precisely what happens when a box can't grow, but can shrink.
With Growth: 0 and Shrink: 1, the 200px wide box never stretched to fill the whole initial container. It did instead shrink inside the tinier container to avoid overflowing.
This setting does not allow elements to grow, but neither to shrink.
It's particularly noticeable by playing with the size of the browser
that this setting is different from "initial". If the screen is too
narrow, the elements will actually break free from the container.
Interesting to notice that while the items will overflow on the main
flex-direction, the container will still just stretch itself to fit even
the tallest of elements, and not overflow on the cross-axis.
Let's see more precisely what happens when a box can't grow and can't shrink either.
With Growth: 0 and Shrink: 0, the 200px wide box never stretched to fill the whole initial container. Unable to shrink itself, it overflowed outside the container size.
The most responsive of settings. Here the boxes are free to fill the empty space, shrink if necessary and will respond to size and content.
How about what happens when a box can grow and can also shrink?
With Growth: 1 and Shrink: 1, the 200px wide box stretched to fill the whole initial container! It did also shrink inside the tinier container to avoid overflowing. Be like water my friend.
This is the most different setting. In fact in here we are actually
saying to each element to not behave automatically, but to grow in
proportion to each other in a specific way.
By saying to an element to "flex:4" and to another one to "flex:8", you
are basically saying to the second one to grow at twice the rate of the
other. Each value here is a proportion between the other elements, and
the flex-basis is set to 0.
So in summary of the previous section: by creating a flexbox container and wrapping it around other elements, you can arrange them in a responsive way along a specified direction and even customize their behaviour to some degree.
Alternatively, without adding anything more than "display: flexbox", you would get a flexbox container with these default values:
Basically then, without any value other than "display:flex", these are the hidden settings that would be applied:
.default-flex-settings {
display: flex;
flex-direction: row;
justify-content: flex-start;
flex: 0 1 auto;
align-items: stretch;
align-content: stretch;
flex-wrap: nowrap;
}
There is no better way to start understanding these concepts in depth
than to start messing around with them.
Thankfully there are some very nice resources that will allow you to
literally play with flexbox and to understand more visually what you
just read!
Try these free browser games out and check back here for reference on how some concepts work.