Когда нужно использовать Flexbox

Очень интересная статья про то, когда всё-таки нужно использовать flexbox, а когда grid. Всё с примерами и объяснениями. В общем, как надо. Эта статья интересна именно тем, что появляется в переходный момент, когда существуют старые добрые флоаты, flexbox и grid. И все они уже довольно хорошо поддерживаются современными браузерами.

Адаптивный перевод статьи Use Cases For Flexbox
Автор: Rachel Andrew.
Кстати, очень советую почитать её книги и статьи.

Также советую почитать. Решающая CSS битва: Grid против Flexbox

И Вёрстка на Flexbox в CSS. Полный справочник (там же вы найдете детальное объяснение того, как работают замысловатые flex-grow и flex-shrink)

Так что использовать, Grid или Flexbox?

Это до сих пор главный вопрос, который я задаю на своих курсах и в основном вижу, что люди больше стремятся использовать новые методы разработки шаблонов и уже далее, в процессе, становится понятно, что этим вопросом нужно задаваться как можно реже. Просто чем больше компонентов вы разрабатываете, тем свободнее вы ориентируетесь в методах их создания и тем увереннее будут ваши решения.

А если вы только пришли к этому вопросу, то вам стоит помнить, что CSS Grid и Flexbox оба являются частью CSS. Указывая display: gridили display: flex, вы зачастую применяете больше того, чего у них общего, нежели их различия. Grid и Flexbox используют свойства, которые входят в спецификацию Box Alignment (Модуль выравнивания в CSS), оба они основаны на концепциях, описанных в CSS Intrinsic & Extrinsic Sizing (Формирование свойственных и внешних, зависимых от них, размеров элементов).

Так что задавая вопрос, что использовать Grid или Flexbox, вы отчасти спрашиваете что-то типа, что должно быть в моём дизайне font-size или color? Скорее всего вам надо использовать оба, если потребуется. И уже точно тут никто не будет укорять вас в том, что вы выбрали неверный метод.

Мы не выбираем между Vue.js и React, Bootstrap или Foundation. Мы просто используем CSS, чтобы сверстать шаблон и нам нужно использовать его составляющие, которые будут иметь смысл при применении их в конкретной части нашего дизайна. Рассмотрите каждый компонент и решите, что и где лучше использовать или какие комбинации будут более подходящими.

Это мог бы быть Grid или это мог бы быть Flexbox. Это мог бы быть внешний grid контейнер, включающий грид-элементы, которые становятся flex-элементами, ну или наоборот. Вообще нет проблемы в том, чтобы вкладывать grid в flex-элемент, если этого требует адекватность вёрстки вашего дизайна.

Так для чего на самом деле нужен Flexbox?

Вот, как описывается flexbox в своей спецификации:

Flex-шаблон на первый взгляд похож на блочный. Ему не хватает многих тексто-ориентиованных или документа-ориентированных свойств, которые могут применяться в блочной вёрстке, например такие, как флоаты или колонки. Но в противовес, flex даёт простоту и мощный инструментарий для распределения места и выравнивания контента, именно такими методами, в которых зачастую нуждаются современные веб-приложения и сложные веб-страницы.

Я думаю, что ключевая фраза тут “распределение места и выравнивание контента”. Flexbox по своей сути берёт несколько элементов разных размеров и умещает их в контейнер, у которого сам по себе варьирующийся размер. Flexbox же ‘неженка’. Он пытается создать лучший шаблон из возможных для наших элементов, давая самым большим из них места побольше, а тем кто поменьше — места поменьше, соответственно, при этом стоя на страже читабельности всего контента.

Иногда люди находят flexbox сложным и странным. Зачастую так бывает, потому что люди пытаются использовать его как систему сеток — стараясь вернуть контроль над формированием размера и распределением места. Естественно, когда вы так делаете, flexbox может казаться странным и тяжёлым для понимания, потому что попросту вы боретесь с тем, что flexbox делает flexbox’ом, а именно с его гибкостью.

Следовательно, шаблоны подходящие для flex-разметки, это те, в которых нет нужды в pixel-perfect размерах для каждого элемента. Нам просто надо хорошо отобразить каждый рядом друг с другом.

Я думаю, что ключевая фраза тут “распределение места и выравнивание контента”. Flexbox по своей сути берёт несколько элементов разных размеров и умещает их в контейнер, у которого сам по себе варьирующийся размер. Flexbox же ‘неженка’. Он пытается создать лучший шаблон из возможных для наших элементов, давая самым большим из них места побольше, а тем кто поменьше — места поменьше, соответственно, при этом стоя на страже читабельности всего контента.

Иногда люди находят flexbox сложным и странным. Зачастую так бывает, потому что люди пытаются использовать его как систему сеток — стараясь вернуть контроль над формированием размера и распределением места. Естественно, когда вы так делаете, flexbox может казаться странным и тяжёлым для понимания, потому что попросту вы боретесь с тем, что flexbox делает flexbox’ом, а именно с его гибкостью.

Следовательно, шаблоны подходящие для flex-разметки, это те, в которых нет нужды в pixel-perfect размерах для каждого элемента. Нам просто надо хорошо отобразить каждый рядом друг с другом.

[codepen_embed height="460" theme_id="0" slug_hash="EdPjgE" default_tab="css,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/EdPjgE/'>Smashing Flexbox Series 4: Items sharing space</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

Также, есть моменты, где вам понадобится “охватить” строки, однако при этом нет нужды в строгой сетке. Если мы возьмём примеры на grid’ах и flexbox, в которых будем использовать синтаксис авто заполнения грида и затем flex-контейнер с обернутыми flex-строками. То мы сразу увидим разницу между этими двумя методами.

В гриде, элементы выстроятся по строкам и колонкам. В то время, как количество колонок изменяется в зависимости от места, элементы всегда идут в следующую доступную грид-ячейку. По факту, нет способа указывать грид-элементу продолжительность треков, если в таком auto-flow сценарии есть пустые ячейки для заполнения.

[codepen_embed height="460" theme_id="0" slug_hash="LgGVyX" default_tab="html,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/LgGVyX/'>Smashing Flexbox Series 4: Grid example</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

А вот в flex-примере, последние элементы берут любое пространство, которое остаётся между ними; в этому случае у нас нет горизонтального или вертикального выравнивания.

[codepen_embed height="460" theme_id="0" slug_hash="vVLOZq" default_tab="html,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/vVLOZq/'>Smashing Flexbox Series 4: wrapped flex items flex-basis 150px;</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

Если у нас выствлен flex-basis на auto и какой-либо из flex-элементов больше, им также будет распределено больше места, так что выравнивание может быть довольно разным от строки к строке.

[codepen_embed height="460" theme_id="0" slug_hash="JmGdEa" default_tab="html,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/JmGdEa/'>Smashing Flexbox Series 4: Wrapped items</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

А вот очень ясный пример того, когда нам надо использовать Flexbox, а не Grid. Если требуется обернуть элементы, но забрать место, которое им нужно построчно. Это вообще не очень подходит для гридов. Тут могут быть длиные слова и предложения, забирающие нужное им место, при это не будучи привязанными к строгой сетке.

[codepen_embed height="460" theme_id="0" slug_hash="EdPVNz" default_tab="css,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/EdPVNz/'>Smashing Flexbox Series 4: tags example</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

На данный момент, Flexbox также является лучшим способом для вертикального и горизонтального центрирования на элементах внутри контейнера.

[codepen_embed height="460" theme_id="0" slug_hash="BqjoxY" default_tab="css,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/BqjoxY/'>Smashing Flexbox Series 4: centered</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

Возможно, в будущем мы сможем это делать без добавления контейнеру display: flex. Ну а сейчас, это скорее необходимость, чем данность, хотя эта лишняя строчка в CSS совсем не проблема.

Flexbox очень хорош с работой над маленькими, одномерными компонентами. Такими как наборы полей форм, иконки или любой другой информации, которую легко добавить и сделать гибкой, без нужды в тщательном выстраивании размеров для каждого.

[codepen_embed height="460" theme_id="0" slug_hash="vVLNbZ" default_tab="css,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/vVLNbZ/'>Smashing Flexbox Series 4: simple row of form elements</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

Вы также можете выбрать Flexbox в ситуациях, где вам нужно держать контент в “подвале” контейнера, вместо того, чтобы он скакал туда-сюда по компоненту. В примере ниже, flex-контейнер показывает контент, как колонку, растягивая середину, которая выталкивает футер вниз компонента.

[codepen_embed height="460" theme_id="0" slug_hash="xyZYwY" default_tab="css,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/xyZYwY/'>Smashing Flexbox Series 4: sticky footer card</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

В процессе разработки, я нахожу flexbox полезным для многих мелких задач, когда нужно знать, что всё правильно выровнено и что место между элементами верно распределено. Вы вообще могли бы использовать одномерный грид-контейнер для некоторых из примеров выше и даже не париться о резонности своего решения.

Я считаю, уж что flexbox делает хорошо, так это справляется с ситуациями, когда нужно добавить несколько дополнительных элементов, которые изначально не предполагались в дизайне. Для примера, если бы у меня был компонент навигации, использующий Grid, то нужно было бы достаточно треков для всех элементов, так как мне бы не хотелось, чтобы новая строка создалась в случае, когда у меня было бы “слишком много” элементов. А вот в Flexbox, пока я позволяю элементам быть “гибкими” от flex-basis 0 (или auto), то элементы бы допускали добавление других, новых элементов в строку, предоставляя им пространство.

Когда мне НЕ использовать Flexbox?

Мы посмотрели на несколько случаев, где по моему мнению, вам нужно использовать Flexbox, а не Grid, а теперь мы посмотрим на случаи, когда Flexbox будет не лучшим выбором. Мы уже посмотрели на пример Flexbox vs. Grid, где элементы выровнены горизонтально и вертикально, сопоставив с элементами, забирающими место построчно. И именно это отличие будет самым первым, на которое нужно обратить внимание.

Пример на гридах сделан двухмерно. В общем это одновременно шаблон на строках и колонках. А вот пример на Flexbox сделан одномерно. Мы обернули флекс-строки, но распределение места происходит на построчной основе. Каждая строка обязательно ведёт себя как новый флекс-контейнер по-указанному flex-direction.

Следовательно, если вашему компоненту нужен двумерный шаблон, то вам лучше использовать Grid, а не Flexbox. Совершенно не важно большой или маленький ваш компонент. Какой вывод точно нужно сделать из этой статьи, так это забыть про стереотип о том, что Grid нужно использовать для разметки всего шаблона, а Flexbox для компонентов. У вас может быть малюсенький компонент, для которого нужна двумерная разметка, а для основной структуры страницы лучше подойдет одномерный, то есть flexbox подход.

Ещё один момент, при котором Grid можно рассматривать, как лучшее решение, это когда вы применяете ширину или flex-basis как единицу длины для флекс-элементов, для того, чтобы выстроить их с другой строкой флекс-элементов или просто каким-нибудь образом ограничить “гибкость” (флексбоксность). Зачастую это говорит о том, что вам либо нужен двумерный шаблон или то, что управление через грид контейнер лучше подходит для этого случая.

Для примера, мы могли бы наш флекс-шаблон сделать похожим на гридовый , ограничив “флексбоксноть” (лучше этот термин, потому что он указывает на гибкость и растягиваемость элементов в flexbox) элементов. Выставляя flex-grow на 0 и указывая размер элементов в процентах — похожим образом мы бы могли выставлять размеры в потоковом гриде. В общем, если вы поняли, что если вы так делаете, то вам стоит рассмотреть способ на гридах, как более удачный подход, созданный именно для такого типа шаблонов.

[codepen_embed height="460" theme_id="0" slug_hash="jeWZyM" default_tab="html,result" user="rachelandrew"]See the Pen <a href='https://codepen.io/rachelandrew/pen/jeWZyM/'>Smashing Flexbox Series 4: wrapped flex items with percentage widths</a> by rachelandrew (<a href='https://codepen.io/rachelandrew'>@rachelandrew</a>) on <a href='https://codepen.io'>CodePen</a>.[/codepen_embed]

Учитывая всё выше сказанное, помните, что зачастую просто нет ясного ответа на вопрос, как правильно и как нет. Иногда единственное, что вы можете сделать, это попробовать разные способы и на практике увидеть, что же лучше подходит компоненту. Помните, что вы также можете менять методы построения шаблона, используя Flexbox в одном моменте, а Grid в других.