📜 ⬆️ ⬇️

Build with flexbox

In this tutorial, we will examine some real and once really difficult moments that are now easily solved through the use of flexbox.



Introduction


Some time ago I wrote a flexbox introductory article on SitePoint. In this article I tried to find out and answer the question:

Are we ready to use flexbox?

Last time I said that you should use this opportunity very carefully, but insisted that you need to become familiar with its syntax and implement it in modern projects. Now I am glad that I can give a positive answer to my question:
')
Yes, we are ready to use flexbox!

If you're not familiar with flexbox, here's a quick explanation. CSS module for building flexible markup is a module that allows you to easily place blocks on the screen, within the allocated space. This is a great achievement compared to the classic block model, since flexbox allows you not to use the float property at all. Blocks can be combined into rows or divided into columns. Each flexbox element can have a specific order. And you can immediately control the alignment, indentation and size of these elements.

Perhaps, in this article I will not be able to consider every aspect of this module, so I suggest you get to know it in more detail by going to the MDN website. And in this tutorial, we will look at common markup problems and see how easy and quick they can be solved. Each markup template I’m going to talk about will be responsive, which will further emphasize the ease with which you can create markup using flexbox. Here is what we look at:


Ok, let's get started!

Simple grid system


Today, grid systems are present in most project layouts, and the classic block model behavior in CSS has forced us to resort to using floating or inline-block elements, each of which has its own drawbacks. Flexbox allows us to easily create a really cool and scalable grid system by writing just a few lines in CSS. Let's look at this in more detail.

Imagine that we have the following simple markup:

<div class="grid"> <div class="grid__row"> <div class="grid__item">1</div> <div class="grid__item">2</div> ... </div> </div> 

With the traditional grid creation approach, we would have to somehow determine how many elements could fit on one line, and then set the width for each grid element. And with the help of flexbox, we can add as many elements to a string as we want, and their width will adapt itself to the total width of the string. In other words, we can have the following markup, and at the same time we don’t need to worry about specifying the number of elements in each line in CSS:

 <div class="grid"> <div class="grid__row"> <div class="grid__item">1</div> <div class="grid__item">2</div> </div> <div class="grid__row"> <div class="grid__item">1</div> <div class="grid__item">2</div> <div class="grid__item">3</div> </div> <div class="grid__row"> <div class="grid__item">1</div> <div class="grid__item">2</div> <div class="grid__item">3</div> <div class="grid__item">4</div> </div> </div> 

And now let's look at the CSS code. I used some properties purely for aesthetic purposes (for example, frames and internal indents), but otherwise everything is very simple:

 .grid { border: solid 1px #e7e7e7; } .grid__row { display: flex; } .grid__item { flex: 1; padding: 12px; border: solid 1px #e7e7e7; } 

Something like that! And our grid is ready for use. By adding display: flex to the .grid__row containers, we create a so-called flex-container, and each child element in the container immediately becomes a flex-element. By applying the flex: 1 property to flex elements, we force them to occupy an equal amount of space relative to the total width of the container. Now you can have as many rows as you like in the grid, and each of them can have its own number of elements. And it will be a simple fully responsive grid system without any additional CSS.

And what can be said about breakpoints and column markings? If we want the grid elements to line up in columns, not lines, then we can simply declare the flex-direction: column property for containers with the .grid__row class. In this case, we can create a very simple responsive grid, making some changes. And our markup will look like this:

 <div class="grid"> <div class="grid__row grid__row--sm"> <div class="grid__item">1</div> ... </div> <div class="grid__row grid__row--md"> <div class="grid__item">1</div> ... </div> <div class="grid__row grid__row--lg"> <div class="grid__item">1</div> ... </div> </div> 

And our CSS is like this:

 .grid { border: solid 1px #e7e7e7; } .grid__row { display: flex; flex-direction: column; } .grid__item { flex: 1; padding: 12px; border: solid 1px #e7e7e7; } @media all and ( min-width: 480px ) { .grid__row--sm { flex-direction: row; } } @media all and ( min-width: 720px ) { .grid__row--md { flex-direction: row; } } @media all and ( min-width: 960px ) { .grid__row--lg { flex-direction: row; } } 

And voila. A super-simple responsive grid system the size of just a few CSS lines. This system is so impenetrable that you can even mesh each other without worrying about the consequences:

 <div class="grid"> <div class="grid__row grid__row--sm"> <div class="grid__item"> <div class="grid"> <div class="grid__row grid__row--lg"> <div class="grid__item">Nested 1</div> ... </div> </div> </div> <div class="grid__item">2</div> </div> <div class="grid__row grid__row--md"> <div class="grid__item">1</div> ... </div> </div> 

Look at this in action .

Three-column site layout


The layout of the three-column site is quite famous in web design, and even in the era of web applications and other fun, this layout still plays an important role in the web - this markup is constantly used on sites that have a lot of content. Back in 2006, a three-column layout was remarkably disassembled and described on the A List Apart website. It uses float elements, negative margins and min-width values ​​so that the combined dimensions of the elements do not conflict with each other and do not break the markup. And all this, given the current need to create responsive markup, meant using a large number of calculations, derailing and other tricks to make it all work correctly. And if you decided to change the width of the side column, you had to perform all the calculations again.

Flexbox allows you to get rid of a significant headache, because we can define column or line markup, and also explicitly specify the order of the elements in CSS, even if they are arranged in a different order in our markup. Here is a typical example of creating a three-column layout:

 <body class="holy-grail"> <header class="holy-grail__header"></header> <main class="holy-grail__body"> <div class="holy-grail__content"></div> <div class="holy-grail__sidebar holy-grail__sidebar--first"></div> <div class="holy-grail__sidebar holy-grail__sidebar--second"></div> </div> <footer class="holy-grail__footer"></footer> </body> 

In my demo example, the markup is inside the document, so there are no body or main tags in it, as shown above. But in this case, we are interested in the names of the classes and the sections of our markup themselves, and not the elements themselves. In particular, pay attention to the classes that are used for the two side columns, and the order in which they follow in the markup. Let's take a look at what is happening here:

  1. We have a parent container, .holy-grail, and in it we have three flex-elements. These are elements with the .holy-grail__header, holy-grail__body, and holy-grail__footer classes.
  2. These three elements are located one above the other and occupy 100% of the screen width. Thus, the column direction must be specified for the flex container.
  3. The body of our markup, .holy-grail__body, is an internal flex-container. Its child flex-elements should have column markings on small screens and lower case markings on wide screens.

Considering the above, let's build the markup:

 .holy-grail { display: flex; flex-direction: column; } .holy-grail__header, .holy-grail__footer { flex: 0 0 100%; } .holy-grail__body { display: flex; } .holy-grail__sidebar { /*     */ } .holy-grail__sidebar--first { order: 1; } .holy-grail__sidebar--second { order: 3; } .holy-grail__content { order: 2; } @media all and ( min-width: 720px ) { .holy-grail__body { flex-direction: row; } .holy-grail__sidebar { flex: 0 0 180px; } .holy-grail__content { flex: 1; } } @media all and ( min-width: 960px ) { .holy-grail__sidebar { flex: 0 0 240px; } } 

It really is that easy! As I already mentioned, we initially define two flex-containers (for small screens). For the first breakpoint, we change the flex-direction for wrapping the columns to lower case, and set the side columns to 180px using the abbreviated entry, the flex property. This entry will allow us to limit the values ​​for the flex-grow and flex-shrink properties, as well as explicitly specify the width. For content, the flex property is used: 1 to fill the available space. The arrangement of flex elements in the right order also turned out to be a trifle thanks to the order property. Perhaps there are only additional styles that you want to add from an aesthetic point of view ... but otherwise it’s really simple and effective. Did I mention that by default, flexbox creates columns of the same height? Take a look at this demo .

Rubber navigation with varying width of the search field


In our next example, we will create something fun, including a beautiful transition. We will create a rubber navigation that stretches to the full width, and in it we will place a search field that will smoothly stretch in the focus state. Using the power of flexbox, we can add as many menu items as we want without changing the CSS. I will use some classes to achieve the desired result. As a small bonus, I'm going to make our navigation fully responsive by adding a toggle button for it! This is what HTML will look like:

 <nav class="flexy-nav"> <button id="flexy-nav__toggle" class="flexy-nav__toggle">Toggle Nav</button> <ul id="flexy-nav__items" class="flexy-nav__items"> <li class="flexy-nav__item"><a href="#" class="flexy-nav__link">Item 1</a></li> <li class="flexy-nav__item"><a href="#" class="flexy-nav__link">Item 2</a></li> <li class="flexy-nav__item"><a href="#" class="flexy-nav__link">Item 3</a></li> <li class="flexy-nav__item"><a href="#" class="flexy-nav__link">Item 4</a></li> </ul> <form action="" class="flexy-nav__form"> <input class="flexy-nav__search" type="text" placeholder="Type search terms and hit enter..."> </form> </nav> 

Let's break down this markup before we get to CSS. We have a main flex-container with a class .flexy-nav. The button is used as a switch, the unnumbered list contains the main menu items, and the form contains a search field. For smaller screens, we need to use column markings for all three elements, and also we need each menu item to be in a separate column. On wide screens, we need to hide the toggle button, line up the elements of the list into a line, and set the form to a fixed width. List items will be evenly distributed among the remaining space. When we switch to the text field (search field), we would like it to stretch smoothly across the width, and all the elements of the list, conversely, smoothly narrowed. Here is the CSS:

 /*   */ input, button { font: inherit; border-radius: none; box-shadow: none; appearance: none; } button { cursor: pointer; } /*   */ .flexy-nav { display: flex; flex-direction: column; } /*   */ .flexy-nav__items { display: none; flex: 1; flex-direction: column; list-style: none; margin: 0 0 4px 0; padding: 4px; text-align: center; } .flexy-nav__items--visible { display: flex; } .flexy-nav__item { background-color: #f1f1f1; border-bottom: solid 1px #e7e7e7; } .flexy-nav__item:last-child { border-bottom: 0; } .flexy-nav__link { padding: 8px; display: block; } /*   */ .flexy-nav__toggle { margin: 0 0 4px 0; padding: 4px; color: #fff; background-color: #f07850; border: none; } .flexy-nav__toggle:hover, .flexy-nav__toggle:focus { outline: none; background-color: #c93f11; } /*       */ .flexy-nav__form { height: 48px; } .flexy-nav__search { display: block; margin: 0; padding: 0 4px; width: 100%; height: 48px; color: #6d6d6d; background-color: #fff; border: solid 2px #e7e7e7; } .flexy-nav__search:focus { outline: none; border: solid 2px #6d6d6d; } /* - */ @media all and (min-width: 768px) { .flexy-nav { flex-direction: row; } .flexy-nav__items { display: flex; flex-direction: row; margin: 0; padding: 0; height: 48px; } .flexy-nav__item { flex: 1; margin-right: 4px; border-bottom: none; } .flexy-nav__link { padding: 0; line-height: 48px; } .flexy-nav__toggle { display: none; } .flexy-nav__form { flex: none; } .flexy-nav__search { width: 240px; transition: width 0.3s; } .flexy-nav__search:focus { width: 360px; } } 

As promised, here is a ridiculously simple, piece of JavaScript code that will allow us to show / hide navigation on small screens:

 (function() { var toggle = document.querySelector("#flexy-nav__toggle"); var nav = document.querySelector("#flexy-nav__items"); toggle.addEventListener("click", function(e) { e.preventDefault(); nav.classList.contains("flexy-nav__items--visible") ? nav.classList.remove("flexy-nav__items--visible") : nav.classList.add("flexy-nav__items--visible"); }); })(); 

So simple. We have just created a beautiful and scalable rubber navigation using flexbox, as well as built a smooth transition when changing the width of the search field. We can add or remove links for as long as we want, as well as resize the search field on the fly. And at the same time, the functionality of our menu will not suffer at all. Ah, here they are the delights of flexbox. Do not forget to watch the corresponding demo example .

Vertical alignment


Let's recognize the fact that vertical alignment in traditional CSS is simply no good. Inline-block elements can sometimes help with this, there are also hacks with absolute positioning, and there are still outdated table markings (which are currently unacceptable for many cases from a semantic point of view). All these methods have their own peculiarities, and they will definitely require from you additional “dances with tambourines” so that everything works as it should.

Flexbox will easily take it upon yourself. We will look at two examples of vertical alignment:

  1. First, we consider the creation of the so-called “media object”, which uses a user avatar (located on the left) and a user name + some information (located on the right). We will use flexbox so that the image and body of the media object are perfectly aligned vertically.
  2. Then we simply consider the vertical (horizontal) alignment of an element of fixed width and variable height inside the container. The element will remain located exactly in the center, despite the increase in height.

Let's start with the first example. As already mentioned, we need to position the user avatar on the left and the description on the right. And no matter how long or short the description will be. We need it to always be perfectly aligned with the avatar. Here is the standard markup:

 <div class="user"> <div class="user__avatar"></div> <div class="user__description"> <h2 class="user__username">John Doe</h2> <p class="user__excerpt">I'm John Doe...</p> </div> </div> <div class="user"> <div class="user__avatar"></div> <div class="user__description"> <h2 class="user__username">Harry Potter</h2> <p class="user__excerpt">I'm Harry Potter...with a really long description...</p> </div> </div> 

Before we move on to CSS, notice that we’ll use a property unfamiliar to this. This property is align-items, and it allows us to align elements along the so-called flex-line in the perpendicular direction. In other words, if our flex-line is horizontal, we can align our elements in a direction that is perpendicular to this line. In our case, we need to align the items in the center, so we will use the value of align-items: center. Here is the CSS:

 .user { display: flex; align-items: center; } .user:last-child { margin-bottom: 0; } .user__avatar { flex: 0 0 96px; width: 96px; height: 96px; background-color: #e7e7e7; } .user__description { flex: 1; margin-left: 24px; padding: 12px; border: solid 1px #e7e7e7; } 

Just like that. You can arrange the text as you like, make the descriptions very long or resize the avatar. It does not matter, the functionality will remain the same. Rate this feature in action .

Let's move on to the second example. This time, imagine that we have a banner located at the very top of the markup. And we want to place a header inside the banner. On small screens, the height of the banner will be 180px, and it will change twice more, to a value of 480px. And with all the changes in the height of the banner, we need the text inside to be ideally centered (both horizontally and vertically). Here is the standard markup:

 <div class="banner"> <div class="banner__content"> <h2 class="banner__title">Symmetrical Perfection</h2> <span class="banner__sub">A beautiful sight, achieved with flexbox.</span> </div> </div> 

This time we also used the justify-content property, which will allow us to distribute the space around the elements along the flex-line. Here is the CSS:

.
 banner { display: flex; align-items: center; justify-content: space-around; height: 180px; background-color: #e7e7e7; } .banner__content { text-align: center; } .banner__title, .banner__sub { margin: 0; padding: 0; line-height: 1.5; } @media all and ( min-width: 480px ) { .banner { height: 240px; } } @media all and ( min-width: 768px ) { .banner { height: 360px; } } @media all and ( min-width: 960px ) { .banner { height: 480px; } } 

No matter how high the banner will be. Content will always be perfectly centered horizontally and vertically. This is the power of flexbox. Do not forget to see a demo example .

Support and vendor prefixes


You need to know your market and audience ... this is key. Flexbox is supported in all modern browsers, including IE10 and higher. If you are creating modern web applications, then flexbox is a powerful tool, and I highly recommend using it. If you are creating or redesigning a website, then check your attendance statistics to get to know your audience. Currently there is a chance that about 99% of your audience will use modern browsers.

As for vendor prefixes, flexbox has a lot of them. It is very unwise to seriously use flexbox and at the same time manually register all vendor prefixes. Personally, I use the project collector (Gulp) to automatically prefix.

Conclusion


That's all! On this I finish this article. If you want to find a real site on which flexbox is used, you may not even start searching. On the new site callmenick.com flexbox is used almost everywhere! Thank you for reading the article to the end. Do not forget that you can see demo examples, as well as download the source at the links below. If you have any questions, comments or suggestions, please leave them in the comments.

Link to the original article: http://callmenick.com/post/flexbox-examples

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


All Articles