Skip to content

Latest commit

 

History

History
1116 lines (859 loc) · 25.5 KB

12. Flexbox.md

File metadata and controls

1116 lines (859 loc) · 25.5 KB

Flexbox

In this file, you will learn about:

  • Flex Container
  • Main & Cross Axises
  • Important Flex Container Properties
  • Understanding space-between & space-around & space-evenly Values
  • Flex Items
  • Important Flex Items Properties
  • flex Shorthand

If we set display: flex; to an element, this element will be turned so-called flex container. Inside of our flex container, we should have other nested elements and those elements are so-called flex items (or children).

Once we turned our elements into a flexbox construct, we can set different properties to these elements. Consider:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Styling</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="container">
        <div>Hamid</div>
        <div>Hamed</div>
    </div>
</body>

</html>
.container {
  display: flex;
}

We have flex-flow, justify-content, align-content and align-items properties for our parent element (i.e. .container class selector).

Then we have order, flex and align-self properties for flex items or children.

Flex Container

Consider this content and style:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Styling</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="container">
        <div class="class-1">div</div>
        <div class="class-2">width=400px</div>
        <div class="class-3">height=600px</div>
        <div class="class-4">width/height=300px</div>
        <div class="class-5">width=300px</div>
        <div class="class-6">width=300px</div>
    </div>
</body>

</html>
* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
}

.class-1,
.class-2,
.class-3,
.class-4,
.class-5,
.class-6 {
  margin: 1px 2px;
  border: 10px black solid;
}

.class-1 {
  background-color: rgba(0, 0, 0, 0.5);
  margin: 1px 0;
  color: white;
}

.class-2 {
  background-color: yellowgreen;
  width: 400px;
}

.class-3 {
  background-color: violet;
  height: 600px;
}

.class-4 {
  background-color: aqua;
  width: 300px;
  height: 300px;
}

.class-5 {
  background-color: darkviolet;
  width: 300px;
}

.class-6 {
  background-color: darkred;
  width: 300px;
}

If we see the page, we will see bunch of colors with different widths and heights. If we use flex for our container, we see strange thing in there. All elements get close to each other.

All those flex items get the highest height when one of them is tall.

Note: If we specify the height of an element, it would not be affected on the tallest item. It's totally separated from other flex items.

We can change it to inline-flex as value. It's like flex display, but when we want to resize the windows, container and the items don't resize anymore. We cover it later at this file.

Flex Direction

We can change the direction of container, for example:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-direction: row;
}

By default, the direction value is row. We can change it to column, for example:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-direction: column;
}

Flex Wrap

It's looks like we remove the flex display. But it doesn't. Another property is flex-wrap. We can set wrap and nowrap betwen our flex items, for example:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-wrap: wrap;
}

Now if change the size of the window, we can see flex items are wrapped. The initial value is nowrap.

If we want to reverse the order of items, we can use wrap-reverse value:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-wrap: wrap-reverse;
}

The order is reverse when the size of the window is decreased enough. If we turn the full screen, items order will be turned back. But we also see that the width/height=300px is at in bottom of the container (display would be top to bottom).

Note: We also have column-reverse and row-reverse as values of flex-direction (no flex-wrap) property:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-direction: column-reverse;
}

/* or */

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  display: flex;
  flex-direction: row-reverse;
  flex-wrap: wrap;
}

Main & Cross Axis

Look at this image (dir => row):

main-cross-axis

We have these two concepts here, the main axis goes top-left corner to right and the cross axis goes the same starting point to the bottom. It's in the default behavior of flex direcion.

Note: If we use flex-direction: row-reverse, the arrows will be reverse too. For example, the main axis goes top-right corner to left and the cross axis goes the same starting point to the bottom (like splitted picture).

For example, if we have HTML content like this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Styling</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="container">
        <div class="class-1">div</div>
        <div class="class-2">width=400px</div>
        <div class="class-3">height=600px</div>
        <div class="class-4">width/height=300px</div>
        <div class="class-5">width=300px</div>
        <div class="class-6">width=300px</div>
    </div>
</body>

</html>

This <div class="class-1">div</div> element, what we can see here, is that the first flex item starts in the top-left corner. This is a main axis. If we resize the window (smaller window), it wraps along the cross axis (top-left corner to buttom).

If we use flex-direction: row-reverse, all behaviors will be reversed, the cross axis still not changed. If we resize the window (smaller size), we see that the first flex item starts in top again. Thst's the image we show you to this explain this concept.

Look at this image (dir => column):

  • wrap:

    main-cross-axis

  • wrap-reverse:

That's the column direction which we see; the cross axis goes top-left corner to right and the main axis goes the same starting point to the bottom.

Note: If we use flex-direction: column-reverse, the arrows will be reverse too, but with some differences. For example, the cross axis goes bottom-left corner to right and the main axis goes the same starting point to the top.

Important: Don't confuse the row and column direction, if you see the from row or column sight, we can really understand these concepts (i.e. main and cross axises).

For example, if we have HTML content like this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Styling</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="container">
        <div class="class-1">div</div>
        <div class="class-2">width=400px</div>
        <div class="class-3">height=600px</div>
        <div class="class-4">width/height=300px</div>
        <div class="class-5">width=300px</div>
        <div class="class-6">width=300px</div>
    </div>
</body>

</html>

This <div class="class-1">div</div> element, what we can see here, is that the first flex item starts in the top-left corner. So the main axis starts in the top-left corner and the items are aligned along the main axis (i.e. the main axis goes from top to bottom).

If we use flex-direction: column-reverse, all behaviors will be reversed like mirror.; and the flex items are aligned along the main axis again.

Main Flex Container Properties for Flexbox

Before we dive deeper in flexbox, we want to introduce the nice property shorthand for mixed flex-direction and flex-wrap properties. That's flex-flow property:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  /* flex-direction: row;
  flex-wrap: wrap; */
  flex-flow: row wrap;
}

Once we understand this property, we want to introduce more properties, for example aligning the flex items:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-flow: row wrap;
  align-items: stretch;
}

The default value is stretch for items alignment. We can put them in center, for example:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
}

The interesting thing is that we see the height of flex items changed. Because there are no more stretched items in there. Indeed, it centered our flex items along the cross axis.

If we use this style:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-flow: column wrap;
  align-items: flex-start;
}

We see that the flex items are ordered at top-left corner to bottom-left corner (cause of cross axis). If we use flex-end in align-items, they go from top-right corner to bottom-right corner.

Note: You can practice flex-start and flex-end in row direction.

Important: align-items always refers to the cross axis.

But how about main axis? How can we change the items's alignment from main axis. We can do that with justify-content property.

Important: justify-content always refers to the main axis.

For example, we center all items along the main axis with:

.container {
  margin: 10px;
  padding: 10px;
  background-color: #ccc;
  border: 2px black solid;
  display: flex;
  flex-flow: row wrap;
  align-items: flex-end;
  justify-content: center;
}

Note: There is another value that we can use it for align-items and justify-content properties. That's baseline, it's for baseline of element. For example, if we use padding for .class-1 selector, we see the different result in our page.

Important: align-content property allows us to align our items along the cross axis. We don't want to dive deeper with this property.

space-between and space-around and space-evenly Values for Flex Items

Consider this content:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Styling</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="main">
        <div class="color1"></div>
        <div class="color2"></div>
        <div class="color3"></div>
    </div>
</body>

</html>

We want practice that flexbox in new way. We want to use space-between and space-around values in there, so if we have some styles like this:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

.main {
  display: flex;
}

.color1,
.color2,
.color3 {
  width: 200px;
  height: 200px;
}

.color1 {
  background-color: red;
}

.color2 {
  background-color: green;
}

.color3 {
  background-color: blue;
}

we see that thare are three boxes (RGB) which are near together. If we use space-between value, we see that some spaces are between these boxes.

.main {
  display: flex;
  align-items: center; /* like vertical-align */
  justify-content: space-between;
}

If we use space-around value, we see that some spaces are around each box (i.e. each flex item).

.main {
  display: flex;
  align-items: center;
  justify-content: space-around;
}

And if we use space-evenly value, we see that several spaces are evenly spaced around the items.

.main {
  display: flex;
  align-items: center;
  justify-content: space-evenly;
}

Flexbox Conversion

If you read our articles from older files, in Diving Depper file, we talk about lists and list items. For example:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Styling</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <header class="main-header">
        <nav>
            <ul>
                <li><a href="packages/index.html">Packages</a></li>
                <li><a href="customers/index.html">Customers</a></li>
                <li><a href="contact-us/index.html">Contact us</a></li>
            </ul>
        </nav>
    </header>
</body>

</html>
* {
  box-sizing: border-box;
}

.main-header {
  background-color: lightgreen;
  width: 100%;
}

.main-header > * {
  display: inline-block;
  padding: 10px;
}

.main-header a {
  width: 100%;
  text-decoration: none;
  color: red;
  font-weight: bold;
}

nav {
  width: 100%; /* or calc(100% - 10%) */
  text-align: right;
}

li {
  display: inline-block;
  padding: 0 10px;
}

a {
  width: 100px;
}

We want to convert this list items to flexbox. So we have:

* {
  box-sizing: border-box;
}

.main-header {
  background-color: lightgreen;
}

.main-header > * {
  padding: 10px;
}

.main-header a {
  width: 100%;
  text-decoration: none;
  color: red;
  font-weight: bold;
}

nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

li {
  display: inline-block;
  padding: 0 10px;
}

a {
  width: 100px;
}

What's the different? Let's see the nav selector. We have clean and flexible code now. We don't use 100% as width.

important: We can also use flexbox for mobile view (with flex-direction: column and so on).

Special Behavior of Flexbox

If you go to Positioning file, we quoted that:

The z-index only work if we just set a position of non-static value. Because we moving an element in z-axis (depth).

But in flexbox, all flex items can have this property even if no position property was applied. For example:

* {
  box-sizing: border-box;
}

.main-header {
  background-color: lightgreen;
}

.main-header > * {
  padding: 10px;
}

.main-header a {
  width: 100%;
  text-decoration: none;
  color: red;
  font-weight: bold;
}

nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

ul {
  z-index: -10;
}

li {
  display: inline-block;
  padding: 0 10px;
}

a {
  width: 100px;
}

If you see the ul selector, we set z-index: -10 and the unordered list will be hidden (behind the main nav). If you are careful, you'll see we don't use position property. Because the parent of the ul (i.e. nav) has flex display. Indeed, it's flex container.

Main Flex Item Properties for Flexbox

Until now, we worked with flex container, but now we want to work with single item inside the flex container, i.e. flex item. It's time to work with them (i.e. flex items). There are three most important properies for flex items in flexbox:

  • order
  • align-self
  • flex-grow
  • flex-shrink
  • flex-basis

order property

We can change the order of flex container's children (i.e. flex items) with order property. The value of this property is 1 to n, for example for RGB colors, we want to change the color order:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

.main {
  display: flex;
  align-items: center;
  justify-content: space-evenly;
}

.color1,
.color2,
.color3 {
  width: 200px;
  height: 200px;
}

.color1 {
  background-color: red;
  order: 3;
}

.color2 {
  background-color: green;
  order: 2;
}

.color3 {
  background-color: blue;
  order: 1;
}

Now our boxes colored BRG instead of RGB. Because the order of the:

  • Blue box: 1
  • Green box: 2
  • Red box: 3

order property allows us to change the order of the elements that the elements initially have based on the code in HTML; and by adding numbers, we say that the bigger number we apply to the order, the later the element will be positioned. For example:

.color1 {
  background-color: red;
}

.color2 {
  background-color: green;
}

.color3 {
  background-color: blue;
  order: -1;
}

In this example, the blue box is positioned as the first element. If we change it to 1 like:

.color3 {
  background-color: blue;
  order: 1;
}

we see that the blue box goes the last element. Because red and green boxes has 0 order value (based on HTML order).

Note: The default value of order property is 0 zero.

align-self property

We can change the individual element position with align-self property. For example, we want to move the red box to the bottom (along the cross axis), for example:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Styling</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="main">
        <div class="color1"></div>
        <div class="color2"></div>
        <div class="color3"></div>
    </div>
</body>

</html>
* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

.main {
  background-color: #ccc;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 400px;
}

.color1,
.color2,
.color3 {
  width: 200px;
  height: 200px;
}

.color1 {
  background-color: red;
  align-self: flex-end;
}

.color2 {
  background-color: green;
}

.color3 {
  background-color: blue;
}

First of all, we set height for our flex container (.main selector) and set background color (light gray) for that container. Then we set align-self: flex-end to red box.

As you can see, the red box goes to the bottom along the cross axis (in relation to the cross axis).

Important: align-items referred to all elements, but align-self allows us to define the position of a single element which is part of a flex container. Both align-items and align-self refer to the cross axis.

flex-grow property

This property is very good for the flexed item. If we use this property, it's like we're stretching it. INded, it sets the flex grow factor. For example;

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

.main {
  background-color: #ccc;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 400px;
}

.color1,
.color2,
.color3 {
  width: 200px;
  height: 200px;
}

.color1 {
  background-color: red;
}

.color2 {
  flex-grow: 1;
  background-color: green;
}

.color3 {
  background-color: blue;
}

If we reload the page, we see that the green box stretched like gum. This element used the remaining space available and don't care about element width value.

If we have multiple grow factors like:

.color1 {
  background-color: red;
}

.color2 {
  flex-grow: 2;
  background-color: green;
}

.color3 {
  flex-grow: 3;
  background-color: blue;
}

we see that the blue box is bigger than the green box. What happens in there? We have 5 parts in there. Because we have 2 for green box and 3 for blue box and how this remaining total space should be divided.

So for 2/5 of it, will be applied to our green box and for 3/5 of it, will be applied to our blue box.

Note: Negative numbers are invalid.

Important: If we use wrap in flex-wrap property in our flex container like:

.main {
  background-color: #ccc;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 400px;
  flex-wrap: wrap;
}

and when we shrink the window size, the blue box goes to the second line with full width. Because lots of free spaces in the second line.

Note: Default value for flex-grow is 0.

flex-shrink property

It something like that the reverse of the flex-grow property. For example:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

.main {
  background-color: #ccc;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 400px;
}

.color1,
.color2,
.color3 {
  width: 200px;
  height: 200px;
}

.color1 {
  background-color: red;
}

.color2 {
  background-color: green;
}

.color3 {
  flex-shrink: 2;
  background-color: blue;
}

We set flex-shrink: 2 and it means that the blue box can't be smallest as it with size (limit the width shrinking size). Indeed, the bigger number is equal the reduce the limitation:

.color3 {
  flex-shrink: 10;
  background-color: blue;
}

Important1: Negative numbers are invalid.

Important2: Both flex-grow and flex-shrink are for width. Not the height.

Note: Default value for flex-shrink is 1. The 0 value means that the element can't shrink all the time.

flex-basis property

This property defines the size of an element depending on the main axis. So flex-basis in not the width or the height, it can be both width and height which is dependent on the flex direction:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

.main {
  padding: 10px;
  background-color: #ccc;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 400px;
}

.color1,
.color2,
.color3 {
  width: 200px;
  height: 200px;
}

.color1 {
  background-color: red;
}

.color2 {
  background-color: green;
}

.color3 {
  flex-basis: 400px;
  background-color: blue;
}

In this example, all boxes have 200px width and height. We set 400px as flex basis and we now see the blue box in main axis in wider (i.e. doubled). If we have full screen, we see that the red and green boxes have width of 200px and blue box has 400px.

Important: If we set width and height manually, flex-basis overwrite them and don't look at them in main axis. In cross axis the width and height are affected, for example:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

.main {
  padding: 10px;
  background-color: #ccc;
  display: flex;
  /* flex-direction: column; */
  align-items: center;
  justify-content: center;
  height: 400px;
}

.color1,
.color2,
.color3 {
  width: 200px;
  height: 200px;
}

.color1 {
  background-color: red;
}

.color2 {
  background-color: green;
}

.color3 {
  height: 600px;
  flex-basis: 300px;
  background-color: blue;
}

If we want flex-basis doesn't affect on width and heigh, we can use flex-basis: auto as value.

The flex Shorthand

We talked alot about the flex items. Now we want to work with use some properties in one property. To do that, we use the flex property. The skeleton of this property is:

.flex-item {
  flex: flex-grow flex-shrink flex-basis;
}

for example:

.color3 {
  background-color: blue;
  flex: 0 1 200px;
}

Summary

Flexbox:

  • Changes the way elements are displayed on a website
  • Flexbox consists of the flex container and flex items

Flex Container:

  • Adding display: flex to an element will turn it into a flex container:

    • flex-direction
    • flex-wrap
    • flex-flow
    • align-items
    • justify-content
    • align-content
    • and so on

Flex Items:

  • All elements/children of the flex container will become flex items

  • Behavior can be changed by properties applied to the flex container and applied to individual flex items:

    • order
    • align-self
    • flex-grow
    • flex=shrink
    • flex-basis
    • flex
    • and so on

Main and Cross Axises:

  • flex-direction defines main axis
  • Properties refer to main or cross axis
  • Behavior of flex items changes depending on flex-direction