CSS Grid and Flexbox: comparison in practice. Flexbox - the practicality of adaptive layout What tags to use in html flexbox

About how easy it is to work with Flexbox using the example of layout of a news website template.

Believe me, there is no need for a detailed analysis of all aspects of working with Flexbox if you want to start using it now. In this tutorial, the author is going to introduce you to some of the properties of Flexbox and create a “news layout” like the one you might have seen on The Guardian website.

The reason why the author uses Flexbox is the large number of possibilities it provides:
- ease of creating adaptive columns;
- creating columns of the same height;
- the ability to press the contents to the bottom of the container.

Let's go!

1. Start by creating two columns

Creating columns when CSS help always entailed certain difficulties. For a long time, floats and/or tables were (and are) widely used to perform this task, but each of these methods had (and has) its drawbacks.

In turn, Flexbox simplifies this process, having a number of advantages such as:

Writing cleaner code: all we have to do is create a container with a rule display: flex;
- flexibility: we can resize, stretch and align columns by changing a couple of lines of CSS;
- semantic markup;
- in addition, using Flexbox there is no need to cancel the wrapping to avoid unpredictable behavior of the layout.

Let's get started by creating two columns, one of which will take up 2/3 of the width of our container, and one of which will take up 1/3 of it.

2/3 column
1/3 column

There are two elements here:

Container columns;
- two child elements column, one of which has an additional class main-column, which we will use later to make the column wider.

Columns ( display: flex; ) .column ( flex: 1; ) .main-column ( flex: 2; )
Because the main-column has a flex value equal to 2 , then this column will take up twice as much space as the second one.

Let's add a little visual design and, in the end, we get:

Click to see in action

2. Make each column a flexbox container

Each of the two columns will contain several vertically arranged articles, so from these two elements we, in turn, must also make flexbox containers.

So, we need the articles:

Positioned vertically inside the container column;
- took up all available space.

Rule flex-direction: column specified for the container, along with the rule flex: 1, specified for a child element, allows the article to fill all available vertical space, while the height of the first two columns remains unchanged.


Click to see in action

3. Making a container from an article

Now, to expand our capabilities even further, let's represent each article as a flexbox container. Each such container will contain:

Title;
- paragraph;
- information panel with the author’s name and number of comments;
- some kind of adaptive picture.

Here we use Flexbox to push the information bar to the bottom of the element. Here, look at the result we expect to get.

And here is the code itself:


.article ( display: flex; flex-direction: column; flex-basis: auto; /* Sets the initial size of the element depending on its content */ ) .article-body ( display: flex; flex: 1; flex-direction: column; ) .article-content ( flex: 1; /* The content fills the remaining space, thereby pushing the infobar to the bottom */ )
Elements inside an article are arranged vertically due to the use of a rule flex-direction: column.

We also applied the property flex: 1 to element article-content, thereby stretching it to all available space and pressing article-info to the bottom. The height of the columns in this case does not matter.


Click to see in action

4. Add several nested columns

In fact, we need the left column to include several more columns. Therefore, we need to replace the second element responsible for the article with a container columns, which we used earlier.


Since we want the first nested column to be wider, we'll add the class to the element nested-column, and in CSS we indicate:

Nested-column ( flex: 2; )
Now this column will be twice as wide as the second one.


Click to see in action

5. Making the first article with a horizontal layout

Our first article is actually big. In order to effectively use the space on the monitor screen, let's change its orientation to horizontal.

First-article ( flex-direction: row; ) .first-article .article-body ( flex: 1; ) .first-article .article-image ( height: 300px; order: 2; padding-top: 0; width: 400px)
Property order plays a big role in this case because it allows you to change the order of HTML elements without changing the HTML markup. In fact, article-image in the code it comes before the element article-body, but acts as if he is standing after him.


Click to see in action

6. Making an adaptive layout

Now everything looks the way we wanted, albeit a little squished. Let's fix this by adding flexibility to our layout.

One of the great things about Flexbox is that you can simply delete a rule display:flex in the container in order to completely disable it (Flexbox), while the rest of its properties (such as align-items or flex) will remain working.

As a result, we can activate the adaptive layout by using Flexbox only when necessary.

So we're going to delete display:flex from selectors .columns And .column, instead "packing" them into a media query:

@media screen and (min-width: 800px) ( .columns, .column ( display: flex; ) )
That's all! On screens with a low resolution, all articles will be located on top of each other, and on screens with a resolution of over 800 pixels - in two columns.

7. Adding finishing touches

To make the layout look more attractive on large screens, let's add some CSS tweaks:

@media screen and (min-width: 1000px) ( .first-article ( flex-direction: row; ) . first-article . article-body ( flex: 1; ) . first-article . article-image ( height: 300px ; order: 2; padding-top: 0; width: 400px; .main-column (flex: 3; .nested-column (flex: 2; )
The content of the first article is aligned horizontally: the text is on the left side, and the image is on the right. Also, the main column is now wider (75%). The same goes for the nested column (66%).

And here is the final result!


Click to see in action

Conclusion

Now you can see for yourself that you can use Flexbox in your projects without even delving into all its intricacies, and the created layout is a clear example of this. At least, the author really hopes so.

Flexbox can rightfully be called a successful attempt to solve a huge range of problems when building layouts in CSS. But before we move on to its description, let's find out what's wrong with the layout methods we use now?

Any layout designer knows several ways to align something vertically or make a 3-column layout with a rubbery middle column. But let's admit that all these methods are quite strange, look like a hack, are not suitable in all cases, are difficult to understand and do not work if certain magical conditions that have developed historically are not met.

This happened because html and css developed evolutionarily. In the beginning, web pages were like single threaded text documents, a little later, dividing the page into blocks was done with tables, then it became fashionable to typeset with floats, and after the official death of ie6, techniques with inline-block were also added. As a result, we inherited an explosive mixture of all these techniques, used to build layouts for 99.9% of all existing web pages.

Multi-line organization of blocks inside a flex container.

flex-wrap

All the examples that we gave above were built taking into account the single-line (single-column) arrangement of blocks. It must be said that by default a flex container will always arrange the blocks inside itself in one line. However, the specification also supports multiline mode. The flex-wrap CSS property is responsible for multi-line content inside a flex container.

Available values flex-wrap:

  • nowrap (default value): blocks are arranged in one line from left to right (in rtl from right to left)
  • wrap: blocks are arranged in several horizontal rows (if they do not fit in one row). They follow each other from left to right (in rtl from right to left)
  • wrap-reverse: same as wrap, but the blocks are arranged in the reverse order.

flex-flow is a convenient shorthand for flex-direction + flex-wrap

In essence, flex-flow provides the ability to describe the direction of the main and multi-line transverse axis in one property. Default flex-flow: row nowrap .

flex-flow:<‘flex-direction’> || <‘flex-wrap’>

CSS

/* i.e. ... */ .my-flex-block( flex-direcrion:column; flex-wrap: wrap; ) /* this is the same as... */ .my-flex-block( flex-flow: column wrap)

align-content

There is also an align-content property, which determines how the resulting rows of blocks will be vertically aligned and how they will divide the entire space of the flex container.

Important: align-content only works in multi-line mode (i.e. in the case of flex-wrap:wrap; or flex-wrap:wrap-reverse;)

Available values align-content:

  • flex-start: rows of blocks are pressed to the beginning of the flex container.
  • flex-end: rows of blocks are pressed to the end of the flex container
  • center: rows of blocks are in the center of the flex container
  • space-between: the first row of blocks is located at the beginning of the flex container, the last row of blocks is at the end, all other rows are evenly distributed in the remaining space.
  • space-around: rows of blocks are evenly distributed from the beginning to the end of the flex container, dividing all available space equally.
  • stretch (default value): The rows of blocks are stretched out to take up all the available space.

The CSS properties flex-wrap and align-content should be applied directly to the flex container, not to its children.

Demo of multi-line properties in flex

CSS rules for child elements of a flex container (flex blocks)

flex-basis – the basic size of a single flex block

Sets the initial major axis size for a flex block before transformations based on other flex factors are applied to it. Can be specified in any length units (px, em, %, ...) or auto (default). If set as auto, the block dimensions (width, height) are taken as a basis, which, in turn, can depend on the size of the content, if not specified explicitly.

flex-grow – “greed” of a single flex block

Determines how much larger an individual flex block can be than adjacent elements, if necessary. flex-grow accepts a dimensionless value (default 0)

Example 1:

  • If all flex boxes inside a flex container have flex-grow:1 then they will be the same size
  • If one of them has flex-grow:2 then it will be 2 times larger than all the others

Example 2:

  • If all flex boxes inside a flex container have flex-grow:3 then they will be the same size
  • If one of them has flex-grow:12 then it will be 4 times larger than all the others

That is, the absolute value of flex-grow does not determine the exact width. It determines its degree of “greediness” in relation to other flex blocks of the same level.

flex-shrink – the “compressibility” factor of a single flex block

Determines how much the flex block will shrink relative to adjacent elements inside the flex container if there is not enough free space. Defaults to 1.

flex – shorthand for the flex-grow, flex-shrink and flex-basis properties

flex: none | [<"flex-grow"> <"flex-shrink">? || <"flex-basis"> ]

CSS

/* i.e. ... */ .my-flex-block( flex-grow:12; flex-shrink:3; flex basis: 30em; ) /* this is the same as... */ .my-flex-block( flex: 12 3 30em )

Demo for flex-grow, flex-shrink and flex-basis

align-self – alignment of a single flex block along the transverse axis.

Makes it possible to override the flex container's align-items property for an individual flex block.

Available align-self values ​​(same 5 options as align-items)

  • flex-start: the flex block is pressed to the beginning of the transverse axis
  • flex-end: the flex block is pressed against the end of the cross axis
  • center: flex block is located in the center of the cross axis
  • baseline: flex block is aligned to baseline
  • stretch (default value): The flex block is stretched to take up all available space along the cross axis, taking into account min-width / max-width if set.

order – the order of a single flex block inside a flex container.

By default, all blocks will follow each other in the order specified in the html. However, this order can be changed using the order property. It is specified as an integer and defaults to 0.

The order value does not specify the absolute position of the element in the sequence. It determines the weight of the element's position.

HTML

item1
item2
item3
item4
item5

In this case, the blocks will follow one after another along the main axis in the following order: item5, item1, item3, item4, item2

Demo for align-self and order

margin: auto vertically. Dreams Come True!

You can love Flexbox at least because the familiar horizontal alignment via margin:auto works here for verticals too!

My-flex-container ( display: flex; height: 300px; /* Or whatever */ ) .my-flex-block ( width: 100px; /* Or whatever */ height: 100px; /* Or whatever * / margin: auto; /* Magic! The block is centered vertically and horizontally */ )

Things to Remember

  1. You should not use flexbox where it is not necessary.
  2. Defining regions and changing the order of content in many cases is still useful to make dependent on the page structure. Think it through.
  3. Understand flexbox and know the basics. This makes it much easier to achieve the expected result.
  4. Don't forget about margins. They are taken into account when setting axis alignment. It is also important to remember that margins in flexbox do not “collapse” as they do in a normal flow.
  5. The float value of flex blocks is not taken into account and has no meaning. This can probably somehow be used for graceful degradation when switching to flexbox.
  6. Flexbox is very well suited for the layout of web components and individual parts of web pages, but it has not shown its best side when laying out basic layouts (position of article, header, footer, navbar, etc.). This is still a controversial point, but this article shows the shortcomings quite convincingly xanthir.com/blog/b4580

Finally

I think that flexbox, of course, will not supplant all other layout methods, but, of course, in the near future it will occupy a worthy niche in solving a huge number of problems. And of course, you need to try working with him now. One of the next articles will be devoted to specific examples working with flex layout. Subscribe to news;)

The Flexbox Layout (Flexible Box) module aims to provide more effective method arrangement, alignment and distribution of free space between elements in a container, even when their size is unknown in advance and/or dynamic (hence the word "flex").

The basic idea of ​​flex layout is to give a container the ability to change the width/height (and order) of its elements in order to best fill the available space (basically to fit on all types and sizes of screens). A Flexbox container expands elements to fill free space or shrinks them to avoid overflow.

Most importantly, Flexbox is directionally agnostic, unlike conventional layouts (boxes based on vertical positioning and inline elements based on horizontal positioning). While they work well enough, they lack the flexibility to support large or complex applications (especially when it comes to changing orientation, resizing, stretching, shrinking, etc.).

Note. Flexbox is more suitable for application components and small layouts, while CSS Grid is designed for larger layouts.

Basics and terminology

Because Flexbox is an entire module and not a single property, it contains a lot of different things, including a whole bunch of properties. Some of them are meant to be set to their container (the parent element, known as a "flex container"), while others are meant to be set to child elements (known as "flex elements").

While a conventional layout system is based on block and line directions, Flexbox is based on "flex-flow directions". Please take a look at this graphic from the specification which explains the basic idea of ​​Flexbox.

Basically the elements will be located along main axis(from main-start to main-end) or transverse axis(from cross-start to cross-end).

Browser support

CSS Flexible Box Layout Module

Chrome for Android

The Blackberry browser, starting from version 10, supports the new syntax.

Properties for the container

Properties for elements

Properties for the parent element (Flex container)

display

Defines a flex container; string or block depends on the value passed. Enables flex context for all of its direct child elements.

Container ( display: flex; /* or inline-flex */ )

Please note that CSS columns do not affect the flex container.

flex-direction


Sets the main axis, thus determining the direction of the elements located in the container. Flexbox (besides its optional wrapper) is a unidirectional layout concept. Think of flex items primarily as horizontal rows or vertical columns.

Container ( flex-direction: row | row-reverse | column | column-reverse; )

  • row (default)- from left to right in ltr ; from right to left in rtl;
  • row-reverse- from right to left in ltr; from left to right in rtl;
  • column- the same as row , only from top to bottom;
  • column-reverse- the same as row-reverse , only from bottom to top;

flex-wrap


By default, items will only attempt to fill one row. You can change this behavior and allow elements to wrap to the next line, if necessary.

Container( flex-wrap: nowrap | wrap | wrap-reverse; )

  • nowrap (default)- all flex elements will be located on one line;
  • wrap- flex elements will be located on several lines, from top to bottom;
  • wrap-reverse- flex elements will be located on several lines, from bottom to top;

justify-content


Defines the alignment along the major axis. This helps distribute the free space left after all fixed-width and non-fixed-width flex items have reached maximum size. It also helps provide some control over the alignment of elements when they overflow a line.

Container ( justify-content: flex-start | flex-end | center | space-between | space-around; )

  • flex-start (default)- elements are pressed to the beginning of the line;
  • flex-end- elements are pressed to the end of the line;
  • center- elements are located centrally along the line;
  • space-between- elements are placed evenly on the line; the first element is at the beginning of the line, last element is at the end of the line;
  • space-around- elements are placed evenly on a line with equal space next to them. Note that visually the space is not equal, as all elements have the same space on both sides. The first element will have one unit of space on the container side, but two units between it and the next element, because the next element also has one unit on both sides.

align-items


This property determines the behavior of flex items along the cross axis on current line. Think of it as , but for the transverse axis (perpendicular to the main axis).

Container ( align-items: flex-start | flex-end | center | baseline | stretch; )

  • flex-start - elements are placed at the beginning of the transverse axis;
  • flex-end elements are placed at the end of the transverse axis;
  • center - the elements are located in the center of the transverse axis;
  • baseline- elements are aligned along the baseline;
  • stretch (default)- stretch to fill the entire container (still respect min-width / max-width);

align-content


Note. This property has no effect when there is only one row of flex items.

Container ( align-content: flex-start | flex-end | center | space-between | space-around | stretch; )

  • flex-start- lines are located at the beginning of the container;
  • flex-end- lines are located at the end of the container;
  • center- lines are placed in the center of the container;
  • space-between- lines are distributed evenly, the first line is located at the beginning of the container, and the last line at the end;
  • space-around- the lines are distributed evenly, with the same distance between them;
  • stretch (default)- lines are stretched across the entire width to take up the remaining space;

Properties for child elements (Flex elements)

order


By default, all elements are arranged in their original order. However, the order property controls the order in which elements are arranged within the container.

Item (order: ; }

flex-grow


The property determines the element's ability to increase in size if necessary. It takes a dimensionless value as a proportion, which determines how much free space inside the container the element should occupy.

If all elements have their flex-grow property set to 1, then the free space inside the container will be evenly distributed among all elements. If one of the elements has a value set to 2 , then the element will take up twice as much space as the others (at least it will try).

Item(flex-grow: ; /* default 0 */ )

Negative numbers cannot be specified.

flex-basis

Determines the default size of an element, before allocating the remaining space. This could be length (20%, 5rem, etc.) or keyword. The auto keyword means "look like my width or height property". The content keyword means that "the size is based on the content of the element" - this keyword is not very well supported yet, so it is difficult to test, and even more difficult to know what its brothers min-content , max-content and fit-content do.

Item ( flex-basis: | auto; /* default auto */ )

If set to 0, the extra space around the content will not be taken into account. If set to auto, additional space will be allocated based on the value.

flex

This is short for , and . The second and third parameters (flex-shrink and flex-basis) are optional. The default value is set to 0 1 auto .

Item ( flex: none | [<"flex-grow"> <"flex-shrink">? || <"flex-basis"> ] }

align-self


This property allows you to override the default alignment (or one set using the property) for individual flex items.

Please look at the property explanation to understand the available values.

Item ( align-self: auto | flex-start | flex-end | center | baseline | stretch; ) .item ( align-self: auto | flex-start | flex-end | center | baseline | stretch; )

Note that float , clear and vertical-align have no effect on a flex element.

Examples

Let's start from the very beginning simple example, problem solver, which occurs almost every day: perfect centering. It couldn't be easier if you're using Flexbox.

Parent ( display: flex; height: 300px; ) .child ( width: 100px; height: 100px; margin: auto; )

This depends on the margin being set to auto on the flex container eating up extra space. Thus, setting the vertical margin to auto on an element will make the element perfectly centered on both axes.

Now let's use a few more properties. Consider a list of 6 elements, all with a fixed size aesthetically, but they can be automatic. We want them to be evenly distributed along the horizontal axis so that when the browser is resized everything will be fine (no media queries!).

Flex-container ( display: flex; flex-flow: row wrap; justify-content: space-around; )

Ready! Everything else is just some design problems. Below is an example on CodePen, be sure to go there and try resizing the windows to see what happens.

Let's try something else. Imagine we have a right-aligned navigation at the very top of the screen, but we want it to be centered on medium-sized screens and in a single column on small screens. As easy as pie.

Navigation ( display: flex; flex-flow: row wrap; justify-content: flex-end; ) @media all and (max-width: 800px) ( .navigation ( justify-content: space-around; ) ) @media all and (max-width: 500px) ( .navigation ( flex-direction: column; ) )

Let's try to do something even better by playing with the flexibility of our flex items! How about a three-column mobile-first layout with a header and footer that spans the entire width of the screen, and does not depend on the original order of the elements.

Wrapper ( display: flex; flex-flow: row wrap; ) .header, .main, .nav, .aside, .footer ( flex: 1 100%; ) @media all and (min-width: 600px) ( .aside ( flex: 1 auto; ) ) @media all and (min-width: 800px) ( .main ( flex: 2 0px; ) .aside-1 ( order: 1; ) .main ( order: 2; ) .aside- 2 ( order: 3; ) .footer ( order: 4; ) )

Related Properties

Errors

Of course, Flexbox is not without its bugs. The best collection I've seen is Philip Walton and Greg Whitworth's Flexbugs. This is an Open Source place to track all bugs, so I think it's best to just leave a link.

Danny Markov

The design is quite simple - it consists of a center-aligned container, inside of which we have a header, a main section, side panel and a basement. Here are the main "tests" we should run while keeping the CSS and HTML as clean as possible:

  1. Place four main sections of the layout.
  2. Make the page responsive (the sidebar falls below the main content on small screens).
  3. Align header content - left navigation, right button.

As you can see, for the sake of comparison, we kept everything as simple as possible. Let's start with the first test.

Test 1: Laying out page sections

Flexbox solution

Add display: flex to the container and set the vertical direction of the child elements. This positions all the sections underneath each other.

Container ( display: flex; flex-direction: column; )

Now we need to make sure that the main section and the sidebar are located next to each other. Since flex containers are usually unidirectional, we need to add additional element.

We then set this element's display: flex and flex-direction to the opposite direction.

Main-and-sidebar-wrapper ( display: flex; flex-direction: row; )

The last step is to set the dimensions of the main section and sidebar. We want the main content to be three times the width of the sidebar, which is easy to do with flex or percentages.

As you can see, Flexbox did everything well, but we also needed quite a lot of CSS properties plus an additional HTML element. Let's see how CSS Grid will work.

CSS Grid Solution

There are several options for using CSS Grid, but we will use the grid-template-areas syntax as the most suitable for our purposes.

First we'll define four grid-areas, one for each section of the page:

header ( grid-area: header; ) .main ( grid-area: main; ) .sidebar ( grid-area: sidebar; ) footer ( grid-area: footer; )

Now we can set up our mesh and define the location of each area. The code may seem quite complicated at first, but once you become familiar with the grid system, it becomes easier to understand.

Container ( display: grid; /* Define the size and number of columns of our grid. The fr unit works like Flexbox: the columns divide up the available space in the row according to their values. We will have two columns - the first is three times the size of the second. */ grid-template -columns: 3fr 1fr; /* Link the previously made areas to places in the grid. The first line is the header. The second line is divided between the main section and the sidebar */ grid-template-areas: "header header" main sidebar" "footer footer"; /* The spacing between grid cells will be 60 pixels */ grid-gap: 60px; )

That's all! Our layout will now follow the above structure and we've set it up so that we don't have to deal with margin or padding.

Test 2. Making the page responsive

Flexbox solution

This step is strictly related to the previous one. For a Flexbox solution, we will have to change the flex-direction and adjust the margin.

@media (max-width: 600px) ( .main-and-sidebar-wrapper ( flex-direction: column; ) .main ( margin-right: 0; margin-bottom: 60px; ) )

Our page is pretty simple, so there's not a lot of work in the media query, but a more complex layout would require a lot of rework.

CSS Grid Solution

Since we've already defined grid-areas , we just need to redefine their order in the media query. We can use the same speaker setup.

@media (max-width: 600px) ( .container ( /* Align grid areas for mobile layout */ grid-template-areas: "header header" "main main" "sidebar sidebar" "footer footer"; ) )

Or we can redefine the entire layout from scratch if we think this solution is cleaner.

@media (max-width: 600px) ( .container ( /* Convert the grid to a single-column layout */ grid-template-columns: 1fr; grid-template-areas: "header" "main" "sidebar" "footer"; ) )

Test 3: Aligning Header Components

Flexbox solution

We have already done a similar layout with Flexbox in one of our old articles -. The technique is quite simple:

Header ( display: flex; justify-content: space-between; )

The navigation list and button are now aligned correctly. All that remains is to place the items inside