The Basics of Flexbox

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.


Table of Contents:


  • What is it?
  • 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.


  • How to use it?
  • 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.


    flex-direction: row

    Box 1
    Box 2
    Box 3

    Box 1
    Box 2
    Box 3


    'flex-direction: column' and 'flex-direction: column-reverse'

    Box 1
    Box 2
    Box 3

    Box 1
    Box 2
    Box 3

    <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.


  • How can we customize the flex container?
  • Let's start with a situation where we might have many elements on one row flex container. What would happen?

    Blue Box 1
    Green Box 1
    Red Box 1
    Blue Box 2
    Green Box 2
    Red Box 2
    Blue Box 3
    Green Box 3
    Red Box 3
    Blue Box 4
    Green Box 4
    Red Box 4
    Blue Box 5
    Green Box 5
    Red Box 5

    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".

    Blue Box 1
    Green Box 1
    Red Box 1
    Blue Box 2
    Green Box 2
    Red Box 2
    Blue Box 3
    Green Box 3
    Red Box 3
    Blue Box 4
    Green Box 4
    Red Box 4
    Blue Box 5
    Green Box 5
    Red Box 5


    Blue Box 1
    Green Box 1
    Red Box 1
    Blue Box 2
    Green Box 2
    Red Box 2
    Blue Box 3
    Green Box 3
    Red Box 3
    Blue Box 4
    Green Box 4
    Red Box 4
    Blue Box 5
    Green Box 5
    Red Box 5

    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"!

    Pro-Tip: The "flex-flow" command

    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;


    Moving things along the flex direction: "justify-content".

    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.

    justify-content: flex-start;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!

    Squished to the top left!

    justify-content: flex-end;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!

    Squished to the top right!

    justify-content: center;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!

    Squished in the middle!

    justify-content: space-between;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!

    Dividing elements by giving each the max amount of distance available.

    justify-content: space-around;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!

    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.

    justify-content: space-evenly;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!

    The most even spacing: the elements are given equal distances, both between themselves and the page's border.


    Moving things on the other direction "Part 1": "align-items".

    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.

    align-items: flex-start;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!
    padding:50px 0px 10px 20px;

    Pushing all the items at the top of the cross-axis. Here that means above, on a row it would be left.

    align-items: flex-end;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!
    padding:50px 0px 10px 20px;

    Pushing all the items at the bottom of the cross-axis.

    align-items: center;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!
    padding:50px 0px 10px 20px;

    Placing all the items in the middle of the cross-axis.

    align-items: stretch;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!
    padding:50px 0px 10px 20px;

    This is the default setting for a flexbox. Every element is stretched at the size of the biggest element of the group.

    align-items: baseline;

    Nice Box
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here!
    padding:50px 0px 10px 20px;

    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.


    Moving things on the other direction "Part 2": "align-content".

    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.

    align-content: flex-start;

    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.

    Squished towards the top of the container, no spaces.

    align-content: flex-end;

    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.

    Squished towards the end of the container, no spaces.

    align-content: center;

    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.

    Squished towards the middle of the container, no spaces.

    align-content: stretch;

    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.

    The default setting: no spaces, elements stretched on the cross-axis to all have the same size.

    align-content: space-between;

    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.

    Now we see spaces. Max distance available between all elements, pushed to the sides fully.

    align-content: space-around;

    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.
    Boxing
    This
    is taller.
    A bit longer.

    Even spaces. Equal size paddings are given to both sides of any element, meaning two elements have both their paddings between them.


  • How can we make small adjustments to the content?
  • We can use options to modify the content of the flexbox containers individually!

    Going against the current: align-self

    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.

    "align-self: flex-end;" on "align-items: center;"

    Nice Box
    I'm a rebel!
    How about me?
    Hello,
    I'm the tallest here.
    And this time it's
    by far!
    padding:50px 0px 10px 20px;

    Placing all the items in the middle of the cross-axis, other than that disobedient blue box which is going "flex-end".

    "align-self: baseline;" on "align-items: stretch;"

    You'll never catch me alive!
    This one box here is a bit longer
    How about me?
    Hello,
    I'm the tallest here.
    And this time it's
    by far!
    padding:50px 0px 10px 20px;

    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.


    Choosing your own place: "order"

    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.

    "align-self: flex-end;" on "align-items: center;"

    Box#1

    order:1;
    Box#2

    order:3;
    Box#3

    order:-1;
    Box#4

    order:2;
    Box#5

    order:0;
    Box#6

    order:-2;

    Growing and shrinking Elements: "flex: ;"

    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:

    1. One or multiple numbers.
    2. One keyword, which will act as a shorthand for more complex default settings.

    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:

    flex: 0 1 auto;

    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.

    About "flex-basis": setting the initial length of a flexible item.

    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.

    flex: initial;
    Equal to flex: 0 1 auto;

    Box with a height of 70px.
    Box
    300px high
    and mighty
    King
    of boxes.
    Box
    padding: 50px 0px 10px 20px;
    This situation is adequate to the status of a box such as mine. I demand 300px of width!
    height:100px;
    width: 150px;

    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.

    Box width: 200px,
    container width: 300px;

    Box width: 200px,
    container width: 150px;

    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.


    flex: none;
    Equal to flex: 0 0 auto;

    Box with a height of 70px.
    Box
    300px high
    and mighty
    King
    of boxes.
    Box
    padding: 50px 0px 10px 20px;
    This situation is adequate to the status of a box such as mine. I demand 300px of width! I hope your screen is sufficiently large though.
    height:100px;
    width: 150px;

    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.

    Box width: 200px,
    container width: 300px;

    Box width: 200px,
    container width: 150px;

    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.


    flex: auto;
    Equal to flex: 1 1 auto;

    Box with a height of 70px.
    Box
    300px high
    and mighty
    King
    of boxes.
    Box
    padding: 50px 0px 10px 20px;
    This situation is more than adequate to the status of a box such as mine. I only demanded 300px of width, but I got even more!
    height:100px;
    width: 150px;

    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?

    Box width: 200px,
    container width: 300px;

    Box width: 200px,
    container width: 150px;

    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.


    flex: 2; flex:4; flex:8; flex: 4; flex: 2; flex: initial;
    Equal to: flex-basis set to 0, the items occupy space in proportion to their flex number.

    Box with a height of 70px.
    Box
    300px high
    and mighty
    King
    of boxes.
    Box
    padding: 50px 0px 10px 20px;
    This situation is completely unfitting to the status of a box such as mine. I demand 300px of width! I would kindly ask you to call your supervisor so that we may solve this issue promptly.
    height:100px;
    width: 150px;

    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.


    Recap and Default Settings for flexbox

    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:

    1. Items display in a row (the flex-direction property's default is row).
    2. The items start from the start edge of the main axis. Which means justify-content: flex-start.
    3. The items do not stretch on the main direction, but can shrink. This means that the flex-grow property is set to 0, while flex-shrink is set to 1 and items can be squeezed if needed.
    4. The flex-basis property is set to auto. This means that the browser will first look if there is any specified size of the elements to arrange them. If there isn't, then it will use the size of the content to choose a size. Overall this means the default is "flex: 0 1 auto;", which is the same as "flex: initial;".
    5. The items will stretch to fill the size of the cross axis (the opposite of the specified direction). This for example means that if an element is bigger than the others, the others will by default stretch to its dimensions. So align-items: stretch; is the default.
    6. Same is true for align-content which is set to stretch, giving the elements no spacing by default over multiple lines. This setting is also initially unused since the content is nowrap by default.
    7. The flex-wrap property is set to nowrap. So the content will rather squeeze in the main direction, than distribute over multiple lines.

    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;
    }



    Play Around with Flexbox!

    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.

    Go Back to Top