Flexbox Full Tutorial

This write-up is taken from the beautifully built course here: https://scrimba.com/g/gflexbox

Below are the 3 files used in this tutorial

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flexbox Intro</title>
    <link rel="stylesheet" href="style.css">
    <link rel="stylesheet" href="basic.css">
</head>
    <body>
        <nav class="container">
            <div>Home</div>
            <div>Search</div>
            <div>Logout</div>
        </nav>
    </body>
</html>

style.css

.container {
    border: 5px solid #ffcc5c;
}

basic.css

.container > div {
  padding: 10px;
  text-align: center;
  font-size: 2em;
  color: #ffeead;
}

html, body {
  background-color: #ffeead;
  margin: 10px;
}

.container > div:nth-child(1) {
  background-color: #96ceb4;	
}

.container > div:nth-child(2) {
  background-color: #ff6f69;
}

.container > div:nth-child(3) {
  background-color: #88d8b0;
}

We will be working entirely in our style.css and index.html

Our starting page looks like this:

Let's add display:flex to our style.css

.container {
    display: flex;
    border: 5px solid #ffcc5c;
}

Notice this changes the default of our divs from stacking vertically to lining up horizontally.

Flexbox Axis

A flexbox container always has a direction. It is important to know that these containers essentially two axis', the main axis which is the content that spans from left to right, or horizontally, and the cross axis which is the content that spans from top to bottom, or vertically.

The css properties will be used to position our items along one of these two axis'.

flex-direction

.container {
    border: 5px solid #ffcc5c;
    display: flex;
    flex-direction: <what goes here?>
}

One property you can use to with flexbox is flex-direction. This has 4 possible choices:

row - The default. Main axis and cross axis act as explained above.

row-reverse - Reverses the direction of the main axis

column - Causes the main axis to act vertically.

column-reverse - Same as column just with a reversed direction

justify-content

.container {
    border: 5px solid #ffcc5c;
    display: flex;
    justify-content: <what goes here?>
}

justify-content is used for positioning the elements along their axis'. 6 possible options are:

flex-start - The default. Positions the elements at the start of the main axis.

flex-end - Positions the elements at the end of the main axis.

notice how this differs from row-reverse, it is simply pushing them to the end, not changing their order

center - Positions the elements in the center of the main axis.

space-around - Positions the elements across the main axis with some space on both sides of each element.

space-between - Similar to space-around but without the space on the outer margins.

space-evenly - Similar to space-around but with perfectly even spacing both between and around each element.

Positioning Items Individually

The first thing we want to do when positioning items individually is to give each item it's own class.

index.html

<div class="container">
            <div class="home">Home</div>
            <div class="search">Search</div>
            <div class="logout">Logout</div>
        </div>

Next, go into our style.css and select one.

style.css

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.logout {
  margin-left: auto;
}

Which will result in something like this

or you can grab a couple by targeting the neighboring elements class name

.search {
  margin-left: auto;
}

Cool, right? If we had 10 elements it would work in the same way, whichever class is targeted, all of the following classes would be grouped with it.

You can target it from the opposite side using the following code.

.container {
  border: 5px solid #ffcc5c;
  display: flex;
  *justify-content: flex-end;*
}

.home {
  margin-right: auto;
}

It looks the same, however it is pulling it from the right side rather than the left.

Responsiveness & The Flex Property

If we want our elements to fill the empty space and become responsive, we will use the flex property.

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.container > div {
  flex: 1;
}

What is happening is each div element is being divided evenly with 1 section or fraction of the row.

It is important to note that flex in this instance is a shorthand of flex-grow, flex-shrink, and flex-basis but we will talk about those later.

If we add more elements, it will continue to distribute them evenly across the row.

<div class="container">
            <div class="home">Home</div>
            <div class="search">Search</div>
            <div class="logout">Logout</div>
            <div class="profile">Profile</div>
        </div>

If you want to give a little more space to a specific element you can do so by targeting it like this:

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.container > div {
  flex: 1;
}

.container > .search {
  flex: 2;
}

Now our search element has 2 fractions/sections of the row while the rest each only get 1.

If you try to just select .search rather than .container > .search it will not work because the .search is less specific than the .container > .div so it will get overridden by that code. So be sure to select in in this way, using the .container > .search format.

A more realistic and efficient way of doing this is to target just one item, like so:

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.search {
  flex: 2;
}

This has the same effect but by specifying the width of one element, it defaults the rest to one fraction size each.

or you can do the inverse:

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.home {
  flex: 1;
}

.logout {
  flex: 1;
}

The Cross Axis

The cross axis controls the elements from top to bottom. This includes even just one row of elements. For example, if I added a height 100% to our .container then it would make our row span the height of the page.

However, you would also have to add a height 100% to the html,body because otherwise it only makes it fit into just the height of the container which defaults to the content within it. So by setting it to html and body it assures that it will be referring to the full size of the page and will look like this:

align-items

One main tool for controlling elements along the cross axis is align-items. There are 4 main options you can use with this:

stretch - The default, stretches the elements to fill the whole height of the page.

flex-start - This pushes the elements to the top/start of the cross axis.

flex-end - This pushes the elements to the bottom/end of the cross axis.

center - This pushes the elements to the middle/center of the cross axis.

side-note (if you want to center an item in the middle of a container, use both align-items: center; and justify-content:center;)

align-self

To control the items individually you can use align-self, below is an example:

.container {
  border: 5px solid #ffcc5c;
  display: flex;
  height: 100%;
  align-items: center;
}

.logout {
  align-self: flex-start;
}

.home {
  align-self: flex-end;
}

which would look like this

flex-direction w/ align-items && justify-content

Using the flex-direction: column basically switches the roles of align-items and justify-content

column - This changes the direction of the row to act like a column, or in other words it switches the main-axis to the cross-axis.

if you apply a height:100%; to the .container, html, body then you can control the items with justify-content in the same ways that you would use align-items.

for example

.container {
  border: 5px solid #ffcc5c;
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100%;
}

Would look like this

align-items will also now act as if it were justify-content.

flex-wrap

First, let's try and set a specific width to each of our items

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.container > div {
  width: 300px;
}

Now if our window only has a width of less than 900px then it will just scale down each element to have an equal portion.

But if we make the window larger than 900px then it will do this

That is because it is set to the default of nowrap. Let's take a look at the other options available to us from flex-wrap.

nowrap - The default. Makes it so you can only have one row, or one column along your given main axis.

wrap - This causes the items to wrap when there is no longer space for their given width.

flex-grow, flex-shrink, flex-basis

These are all part of the flex property.

Let's start with this code.

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.home {
  flex: 1;
}

.logout {
  flex: 1;
}

This looks like:

Now in reality, what this actually would look like is this:

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.home {
  flex: 1 1 0;
  
  or
  
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
  
}

.logout {
  flex: 1 1 0;

  or
  
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
  
}

flex-basis - This will set the base width of each element.

flex-grow - This will determine how much of the extra space will be distributed to the items. So flex-grow: 0 would not use any of the space. If you did flex-grow:1 it would absorb all the space. But the flex-grow properties are also relational to the other elements in the container. So consider the following example

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.home {
  flex-grow: 1;
  flex-basis: 200px;
}

.logout {
  flex-grow: 2;
  flex-basis: 200px;
}

This would look cause the logout to absorb twice as much empty space as the home.

flex-shrink - This is basically the inverse of the flex-grow property. So it determines how much the elements will shrink once the page is smaller than their combined width or basis. Consider the below example

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.home {
  flex-shrink: 0;
  flex-basis: 200px;
}

.logout {
  flex-shrink: 1;
  flex-basis: 200px;
}

Notice that the .home does not shrink but the .logout does

To summarize the flex property.

This code

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.home {
  flex-grow:1;
  flex-shrink:1;
  flex-basis: 200px;
}

.logout {
  flex-grow:1;
  flex-shrink:1;
  flex-basis: 200px;
}

is the same as this code

.container {
  border: 5px solid #ffcc5c;
  display: flex;
}

.home {
  flex: 1 1 200px;
}

.logout {
  flex: 1 1 200px;
}

Order

I will be using this html

<body>
        <div class="container">
            <div class="item1">1 Home</div>
            <div class="item2">2 Search</div>
            <div class="item3">3 Logout</div>
        </div>
    </body>

Now in our CSS we can use the order property:

.item2 {
  order: 1;
}

which will move our .search to the 3rd spot.

By default, html is ordered at 0 for each element. So when we change the order to 1, it puts it at the end. If we made it order: -1 then it would put that element at the beginning.

So you can order as many items as you want by changing the order based on the order of each element, for example:

.item1 {
  order: 1;
}

.item2 {
  order: 0;
}

.item3 {
  order: -1;
}

This would put them in reverse order

And that's it!