Нормальное описание Flexbox-модели
10-02-2016Время чтения ~ 8 мин.CSS, HTML, LESS, SASS 17642
Почти все руководства по Flexbox стараются вместить в себя описание всех его свойств и возможностей. Это приводит к тому, что вебмастеру довольно сложно соориентироваться какие свойства правильно использовать.
Flexbox — мощная штука, которая охватывает достаточно большой пласт задач, но на практике требуется буквально несколько основных его возможностей. В 90% случаев Flexbox используется как замена float-модели блоков, то есть там, где требуется расположить несколько блоков рядом. Плюсом Flexbox будет и то, что его возможности позволяют легко строить адаптивные сетки, вертикальное выравнивание, произвольный порядок и т.п.
На сегодняшний день можно сказать, что flex полноценно поддерживают все современные браузеры, включая и IE11.
HTML-разметка Flexbox
Flexbox оперирует двумя понятиями: контейнер (flex container) и элементы (flex items). То есть всегда, где используется flex, создается основной контейнер.
Особенностью Flexbox-модели является то, что элементы не требуется специальным образом задавать. Например во float-модели (понятно, что это условное именование), было как раз наоборот — требовалось задавать float-свойства именно элементов. Во Flexbox - задается только контейнер, а элементы будут заданы автоматически — все непосредственные потомки.
Типовой вариант html-разметки:
<div style="display: flex;"> <div>1</div> <div>2</div> <div>3</div> </div>
Результат (я немного раскрасил для наглядности):
Блоки элементов (flex items) во Flexbox приобретут специальное свойство, делающее их похожими на inline-block. Именно поэтому хоть у нас и DIV, который в обычном состоянии занял бы 100% ширины, в данном примере занял ширину, соответствующему своему содержимому.
У flex-контейнера может быть свойство justify-content, которое позволяет задать способ размещения элементов. Значение flex-start — это значение по умолчанию (как в примере выше). Значение flex-end — обратное. То есть выравнивание будет с конца.
<div style="display: flex; justify-content: flex-end;">
Значение center размещает элементы по центру:
<div style="display: flex; justify-content: center;">
Более интересные значения у space-around и space-between. Они распределяют свободное место между блоками. Первое учитывает отступы с краёв, а второе прижимает блоки к краю контейнера.
<div style="display: flex; justify-content: space-around;">
<div style="display: flex; justify-content: space-between;">
У контейнера может быть еще одно свойство flex-direction, которое задает направление элементов. Значение п умолчанию row, то есть построчно. Есть значение column — в колонку.
<div style="display: flex; flex-direction: column;">
Значения row-reverse и column-reverse делают реверс, то есть меняют порядок элементов.
<div style="display: flex; flex-direction: row-reverse;">
На практике column практически не используются. Во всяком случае мне ни разу не пришлось им воспользоваться.
Вариант
<div style="display: flex; justify-content: space-between;">
по сути является привычной «резиновой» раскладкой, которая может применяться как для отдельных блоков страницы, так и модульной сетки в целом.
Управлять шириной элементов можно через привычное свойство width.
<div style="display: flex; justify-content: space-between;"> <div style="width: 30%;">1</div> <div style="width: 30%;">2</div> <div style="width: 30%;">3</div> </div>
Теперь об очень важном моменте. Ширина элемента (width) во Flexbox носит лишь «рекомендательный» характер, а не обязательный. Задавая ширину вебмастер лишь указывает желаемую ширину, а Flexbox уже сам решит что делать, если она окажется некорректной. Например, если суммарная ширина элементов превысит 100% (страшный сон вебмастера, использующего float-вёрстку!), во Flexbox ничего страшного не произойдет — блоки останутся на местах, автоматически заняв оптимальное расположение.
На этом основано одно из свойств элементов flex-grow — т.н. жадность элемента, которая указывается числом — чем оно больше, тем больше и «жадность». По умолчанию для всех элементов это 0. Свойство flex-grow крайне удобная штука, поскольку позволяет задавать ширину элементов относительно других без указания точных значений. Например при верстке блока, где ширина «абстрактная» и мы знаем только, что один элемент должен быть больше других. Такие задачи — довольно частые в вебмастерской практике.
<div style="display: flex; justify-content: space-between;"> <div style="flex-grow: 3;">1</div> <div style="flex-grow: 1;">2</div> <div style="flex-grow: 1;">3</div> </div>
Этот же способ применяется там, где ширину задавать невозможно. Простой пример — иконки или пункты меню. Мы не можем рассчитать ширину каждого элемента, поскольку просто не знаем их количество. В этом случае будет достаточно указать свойство flex-grow.
Flexbox обладает ещё одним интересным свойством order, которое указывает порядок элемента. С его помощью можно перетусовать элементы как угодно.
<div style="display: flex; justify-content: space-between;"> <div style="order: 2;">1</div> <div style="order: 3;">2</div> <div style="order: 1;">3</div> </div>
Через order можно менять расположение блоков модульной сетки, например поменять расположение сайдбара слева или справа.
Теперь рассмотрим свойство контейнера flex-wrap. Через него можно управлять поведением элементов в случае заполнения всей ширины. По простому — flex-wrap разрешает делать перенос элементов на новую строку. По умолчанию это значение nowrap, то есть перенос запрещен. Перенос разрешен для wrap и wrap-reverse (тоже самое, только делает реверс элементов).
Перенос часто используется для создания адаптивной сетки. Например есть три блока по 30%. На широких экранах они будут занимать, скажем по 300px. На планшетах, чья ширина меньше — пусть по 200px, а на телефонах еще меньше, скажем 80px. Всё потому, что ширина рассчитывается именно в процентах от ширины экрана.
Оптимальным же будет поведение, когда для десктопов перенос запрещен и блоки в одну строку, как и задумано. Для планшетов и телефонов, перенос уже разрешен и ширину элементов нужно сделать больше, например по 50%. А вот для телефонов ширину сделать уже 100%, поскольку места и так мало. Таким образом на любом экране блоки будут смотреться уже нормально.
Данный CSS-код основан на @media, когда css-классы определяются только для определенных экранов. Вот примерно так (код на LESS):
@media @SCREEN_TABLET { .wXX-tablet { ... } } @media @SCREEN_PHONE { .wXX-phone { ... } } <div class="w30 w50-tablet w100-phone">...</div> <div class="w30 w50-tablet w100-phone">...</div>
Свойство flex-wrap здесь как раз и будет играть ключевую роль. Приведу пример на классах Berry CSS (см. описание flex):
<div class="flex flex-wrap-tablet"> <div class="w30 w50-tablet w100-phone">1</div> <div class="w30 w50-tablet w100-phone">2</div> <div class="w30 w100-tablet w100-phone">3</div> </div>
Другим примером использования flex-wrap будет равномерное заполнение блока фиксированными элементами. Например вывод миниатюр в галерее.
<div style="display: flex; flex-wrap: wrap;"> <div style="width: 100px;">1</div> <div style="width: 100px;">2</div> <div style="width: 100px;">3</div> <div style="width: 100px;">4</div> <div style="width: 100px;">5</div> <div style="width: 100px;">6</div> <div style="width: 100px;">7</div> <div style="width: 100px;">8</div> <div style="width: 100px;">9</div> <div style="width: 100px;">10</div> </div>
Flexbox позволяет управлять и высотой элементов (или расположением по вертикали). Такие задачи встречаются гораздо реже. По-умолчанию высоты элементов индивидуальны.
Если нужно выровнять блоки по высоте, то у контейнера выставляется свойство align-items. Оно имеет значения: flex-start, flex-end, center, baseline и stretch и похожи на те, что описаны выше, только работающие по вертикали. Для выравнивания используется stretch.
<div style="display: flex; justify-content: space-between; align-items: stretch;"> <div>1</div> <div>2</div> <div style="height: 200px;">3</div> </div>
Данное поведение очень похоже на выравнивание ячеек в таблицах (table), поэтому используется примерно в этом же контексте, например при выравнивании прайсовых блоков.
Значение center может использоваться для выравнивания блоков по центральной линии. Его удобно использовать, если блоки разные по высоте.
<div style="display: flex; justify-content: space-between; align-items: center;"> <div style="width: 25%; height: 40px;">1</div> <div style="width: 25%; height: 60px;">2</div> <div style="width: 25%; height: 80px;">3</div> </div>
И последнее, что может пригодится вебмастеру — выравнивание блока по вертикали по центру. Вертикльное выравнивание, всегда было головной болью, но с Flexbox всё решается очень просто. Стандартно центрирование по горизонтали выполнялось с помощью margin: 0 auto;
Собственно auto и работало только по-горизонтали. Но в Flexbox теперь работает в любом направлении.
<div style="display: flex; height: 150px; border: 1px solid gray;"> <div style="width: 50px; height: 50px; margin: auto;"></div> </div>
В заключении приведу ссылку на официальную документацию CSS Flexible Box Layout Module, где можно посмотреть все возможности Flexbox.
Спасибо MAX, и в правду супер!