📜 ⬆️ ⬇️

Practical application of FlexBox

Hi, Habr!

One fine evening, not foreshadowing anything interesting, in our chat we received a proposal from the author of the publication “Translating into code 5 really useful templates of adaptive markup” written by him in the spring of 2012 to write an article-remake, but using FlexBox and the accompanying explanation of what and works. After a certain amount of doubt, the interest of deeper understanding of the specification still won, and I safely sat down to type those same examples. During the immersion in this area, many nuances began to emerge that turned into something more than just transform mockups. In general, in this article I want to talk about such a wonderful specification called “CSS Flexible Box Layout Module” and show some of its interesting features and application examples. All who are interested, I kindly invite you to Habrakat.

What I would like to draw attention to, for the layout of the layout on the FlexBox, the developer will need some degree of adaptation. On his own example, he felt that many years of experience playing a cruel joke. FlexBox requires a slightly different idea about the alignment of elements in the stream.

Technical part


Before proceeding to some examples, it is worth figuring out what properties are included in this specification and how they work. Since some of them are not very clear from the beginning, and some are surrounded by myths that have nothing to do with reality.
')
So. There are two main types of items in FlexBox: Flex Container and its child elements are Flex Items. To initialize the container, it is enough to assign, via css, the display: flex element ; or display: inline-flex; . The difference between flex and inline-flex is only in the principle of interaction with the elements surrounding the container, like display: block; and display: inline-block ;, respectively.

Two axes are created inside the flexible container, the main axis (main-axis) and the perpendicular or cross axis (cross axis). Mostly flexible elements are lined up exactly along the main axis, and then along the cross axis. By default, the main axis is horizontal and has a direction from left to right, and the cross axis is vertical and directed from top to bottom.



The direction of the axes can be controlled using the flex-direction css property. This property takes a number of values:
row (default): The main axis of the flexible container has the same orientation as the inline axis of the current row direction mode . The start (main-start) and end (main-end) directions of the main axis correspond to the beginning (inline-start) and the end (inline-end) of the inline axis (inline-axis).
row-reverse : Everything is the same as in row, only main-start and main-end are swapped.
column : same as row, only now the main axis is directed from top to bottom.
column-reverse : same as row-reverse, only the main axis is directed upwards.
How it works can be seen in the example on jsfiddle .

By default, all the flexible elements in the container fit into one line, even if they do not fit in the container, they fall outside its boundaries. This behavior is switched using the flex-wrap property. This property has three states:
nowrap (default): flexible elements line up from left to right.
wrap : flexible elements are built in multi-line mode, the transfer is carried out in the direction of the cross axis, from top to bottom.
wrap-reverse : same as wrap, but the transfer is from bottom to top.
See an example .

For convenience, there is an additional flex-flow property in which you can simultaneously specify flex-direction and flex-wrap . It looks like this: flex-flow: <flex-direction> <flex-wrap>

Elements in the container can be aligned using the justify-content property along the main axis. This property accepts as many as five different options.
flex-start (default): flexible elements are aligned at the beginning of the main axis.
flex-end : elements are aligned at the end of the main axis
center : elements are aligned to the center of the main axis
space-between : the elements occupy the entire available width in the container, the extreme elements are pressed tightly against the edges of the container, and the free space is evenly distributed between the elements.
space-around : flexible elements are aligned in such a way that free space is evenly distributed between the elements. But It is worth noting that the space between the edge of the container and the extreme elements will be two times less than the space between the elements in the middle of the row.
Of course, an example of how this property works can be done here .

That's not all, we also have the ability to align elements along the cross axis. By applying the property align-items , which also takes five different values, you can achieve interesting behavior. This property allows you to align elements in the line relative to each other.
flex-start : all elements are pressed to the beginning of the line
flex-end : elements are pressed to the end of the line
center : elements are centered on the line
baseline : elements are aligned to the baseline of the text
stretch (default): elements stretch to fill the entire string.

Another similar property to the previous one is align-content . Only it is responsible for the alignment of entire lines relative to the flexible container. It will have no effect if the flexible elements occupy one line. The property takes six different values.
flex-start : all lines are pressed to the beginning of the cross-axis
flex-end : all lines are pressed to the end of the cross-axis
center : All pac lines are centered on the cross axis
space-between : lines are distributed from the top edge to the bottom leaving free space between the lines, while the outermost lines are pressed to the edges of the container.
space-around : lines are evenly distributed across the container.
stretch (default): lines stretch taking up all available space.
You can try how align-items and align-content work in this example . I specifically presented these two properties in one example, since they interact quite closely each performing their task. Notice what happens when elements fit into one line and several.

With the parameters of the flexible container sorted out, it remains to deal with the properties of flexible elements.
The first property we’ll look at is order . This property allows you to change the position in the stream to a specific element. By default, all flexible elements have order: 0; and are built in the order of the natural flow. In the example, you can see how the elements are reversed if you apply different order values ​​to them.

One of the main properties is flex-basis . With this property, we can specify the base width of the flexible element. The default is auto . This property is closely related to flex-grow and flex-shrink , which I will discuss later. Accepts widths in px,%, em, and other units. In fact, this is not strictly the width of the flexible element, it is a kind of starting point. Regarding which is the stretching or shrinkage of the element. In auto mode, the element gets the base width relative to the content inside it.

Flex-grow on several resources has a completely incorrect description. It says that it allegedly sets the ratio of the sizes of the elements in the container. In fact, it is not. This property sets the element magnification factor when there is free space in the container. By default, this property has a value of 0. Let's imagine that we have a flexible container that has a width of 500px, inside it there are two flexible elements, each of which has a base width of 100px. Thus, 300px of free space remains in the container. If we specify the first element flex-grow: 2 ;, and the second element we specify flex-grow: 1 ;. As a result, these blocks will occupy the entire available width of the container, only the width of the first block will be 300px, and the second only 200px. What happened? What happened was that the available 300px of free space in the container was distributed between the elements at a ratio of 2: 1, + 200px to the first and + 100px to the second. Actually this is how it works.

Here we smoothly turn to another similar property, namely flex-shrink . The default value is 1. It also sets the factor for changing the width of elements, only in the opposite direction. If the container has a width less than the sum of the base width of the elements, then this property becomes effective. For example, the container has a width of 600px, and flex-basis elements of 300px. The first element is flex-shrink: 2 ;, and the second flex-shrink: 1 ;. Now compress the container by 300px. Hence the sum of the widths of the elements is 300px more than the container. This difference is distributed in a ratio of 2: 1; it turns out subtracting 200px from the first block, and 100px from the second block. The new size of the elements is 100px and 200px, for the first and second elements, respectively. If we set flex-shrink to 0, then we prohibit the element from shrinking to sizes smaller than its base width.

In fact, this is a very simplified description of how this all works, so that the general principle is clear. In more detail, if anyone is interested, the algorithm is described in the specification.

All three properties can be written in abbreviated form using the expression flex . It has the following form:
flex: <flex-grow> <flex-shrink> <flex-basis>;
And also we can write two more abbreviated versions, flex: auto; and flex: none; what flex means : 1 1 auto; and flex: 0 0 auto; respectively.

The last property of flexible elements remained align-self . Everything is simple, it is the same as the align-items on the container, allowing you to override the alignment for a particular element.

All tired! Examples come on!


With the technical part figured out, it turned out pretty long, but it is necessary to penetrate into this. Now you can go to the practical application.
During the layout of the very "five really useful templates of adaptive markup," we had to solve typical situations that the developer encounters quite often. With flexbox, the implementation of these solutions becomes easier and more flexible.
Take all the same 4th layout, because it has the most interesting elements.



To begin with, we denote the main page width, center it, press the footer to the bottom of the page. As always in general.

html { background: #ccc; min-height: 100%; font-family: sans-serif; display: -webkit-flex; display: flex; flex-direction: column; } body { margin: 0; padding: 0 15px; display: -webkit-flex; display: flex; flex-direction: column; flex: auto; } .header { width: 100%; max-width: 960px; min-width: 430px; margin: 0 auto 30px; padding: 30px 0 10px; display: -webkit-flex; display: flex; flex-wrap: wrap; justify-content: space-between; box-sizing: border-box; } .main { width: 100%; max-width: 960px; min-width: 430px; margin: auto; flex-grow: 1; box-sizing: border-box; } .footer { background: #222; width: 100%; max-width: 960px; min-width: 430px; color: #eee; margin: auto; padding: 15px; box-sizing: border-box; } 


Due to the fact that we have specified flex-grow for .main: 1; it stretches to the full height available, thereby pressing the footer to the bottom. The bonus in this solution is that the footer may be a non-fixed height.

Now let's place the logo and menu in the header.
 .logo { font-size: 0; margin: -10px 10px 10px 0; display: flex; flex: none; align-items: center; } .logo:before, .logo:after { content: ''; display: block; } .logo:before { background: #222; width: 50px; height: 50px; margin: 0 10px 0 20px; border-radius: 50%; } .logo:after { background: #222; width: 90px; height: 30px; } .nav { margin: -5px 0 0 -5px; display: -webkit-flex; display: flex; flex-wrap: wrap; } .nav-itm { background: #222; width: 130px; height: 50px; font-size: 1.5rem; color: #eee; text-decoration: none; margin: 5px 0 0 5px; display: -webkit-flex; display: flex; justify-content: center; align-items: center; } 


Since the header is flex-wrap: wrap; and justify-content: space-between; the logo and menu are scattered on different sides of the header, and if there is not enough space for the menu, it will elegantly shift under the logo.

Next, we see a big post or banner, I find it difficult to say what it is specifically, but not the essence. We have a picture on the right and a text with a title on the left. I personally adhere to the idea that any elements should be as flexible as possible, no matter if it is an adaptive layout or static. So we have a sidebar in this post in which the picture is placed, strictly speaking, we can’t say exactly how wide we need it, because today we have a big picture, tomorrow is small and every time we redo an element from scratch reluctance. So we need to sidebar bar took the right place for him, and the rest of the place went to the content. So do:

 .box { font-size: 1.25rem; line-height: 1.5; font-style: italic; margin: 0 0 40px -50px; display: -webkit-flex; display: flex; flex-wrap: wrap; justify-content: center; } .box-base { margin-left: 50px; flex: 1 0 430px; } .box-side { margin-left: 50px; flex: none; } .box-img { max-width: 100%; height: auto; } 


As you can see for .box-base, where we have the title and the text, I specified the base width using flex-basis: 430px; , and also prohibited block shrinkage using flex-shrink: 0; . With this manipulation, we said that the content cannot be less than 430px in width. And since I specify flex-wrap: wrap; for .box ; At that moment, when the sidebar and content will not be placed in the .box container, the sidebar will automatically fail under the content. And this is all without the use of @ media ! I think this is really very cool.

We still have three-column content. There are several solutions to this problem, I will show one of them, in the other layouts there is another option.
Create a container, call it .content and configure it.
 .content { margin-bottom: 30px; display: -webkit-flex; display: flex; flex-wrap: wrap; } 


The container has three columns, .banners, .posts, .comments
 .banners { flex: 1 1 200px; } .posts { margin: 0 0 30px 30px; flex: 1 1 200px; } .comments { margin: 0 0 30px 30px; flex: 1 1 200px; } 


I set the columns to a base width of 200px so that the columns do not taper straight too much, let them better be transferred under each other as needed.

According to the layout, we with content, cannot do without @ media, so we’ll adjust the behavior of the columns a little more for widths <800px and <600px.
 @media screen and (max-width: 800px) { .banners { margin-left: -30px; display: -webkit-flex; display: flex; flex-basis: 100%; } .posts { margin-left: 0; } } @media screen and (max-width: 600px) { .content { display: block; } .banners { margin: 0; display: block; } .comments { margin: 0; } } 


That's all the magic with regard to building a FlexBox layout. Another task that I liked is in the 5th layout, specifically it concerns the adaptation of content.



We see how on the desktop resolution posts are built in a grid of three in a row. When the width of the viewport becomes less than 800px, the grid turns into a column with posts, where the photo of the post is built on the left and right side of the content of the post, alternately. And with a width of less than 600px, the photo of the post hides completely.
 .grid { display: -webkit-flex; display: flex; flex-wrap: wrap; justify-content: space-between; } .grid-itm { margin-bottom: 30px; flex-basis: calc(33.33% - 30px * 2/3); display: -webkit-flex; display: flex; flex-wrap: wrap; } .grid-img { margin: 0 auto 20px; flex: 0 1 80%; } .grid-cont{ flex: 0 1 100%; } .grid-title { text-align: center; } @media screen and (max-width: 800px) { .grid-itm { flex-wrap: nowrap; flex-basis: 100%; } .grid-img { flex: 0 0 auto; } .grid-itm:nth-child(even) .grid-img { margin: 0 0 0 30px; order: 2; } .grid-itm:nth-child(odd) .grid-img { margin: 0 30px 0 0; } .grid-cont { flex: 1 1 auto; } .grid-title { text-align: left; } } @media screen and (max-width: 600px) { .grid-img { display: none; } } 


In fact, this is just a small part of what can be implemented on the FlexBox. The specification allows you to build very complex page layouts while using simple code.

Few links


Examples of templates can be seen on the link to github .
Knowledge absorbed from here .

I hope my post will help someone and will allow them to use new technologies in full force.
I have it all. Thank you for attention!

Source: https://habr.com/ru/post/242545/


All Articles