Flexbox
Предпосылки и предназначение
Flexbox layout (Flexible Box - гибкий блок) - модуль созданный для обеспечения более гибкой верстки, в контексте выравнивания и распределения пространства между элементами в контейнере, даже когда их размер неизвестен и/или динамический (что и означает слово "flex", гибкий).
Основная идея flex верстки дать контейнеру способность изменять ширину/высоту (и порядок) своих элементов, чтобы наилучшим образом заполнять доступное пространство (главным образом, чтобы обеспечить поддержку всех устройств и размеров экранов). Flex-контейнер расширяет элементы, чтобы заполнить свободное пространство, или сжимает их чтобы предотвратить выход за пределы контейнера.
Важно, flexbox layout не обозначает направление (direction-agnostic) в противовес обычным layout (блоки вертикально ориентированы, встроенные элементы (inline) ориентированы горизонтально). Обычные практики хорошо работают для обычных страниц, но теряют в гибкости, когда требуется поддержка больших или сложных приложений (особенно когда идет речь об изменении ориентации, размеров, расширении, сжатии и т.д.).
Примечание: Flexbox layout наиболее подходит компонентам приложения, и небольшим по масштабированию макетам, в то время как Grid layout предназначен для больших по масштабированию макетов.
Основа и терминология
Так как flexbox целый модуль, а не одно свойство, закономерно, что данный модуль включает в себя много вещей, например, целый ряд свойств. Некоторые из них предназначены контейнеру (родительский элемент, известный как "flex container"), другие предназначены для потомков (обозначим их как flex-элементы, "flex items").
Если обычные макеты основываются на направлении блочных и встроенных (inline) элементов, то flex layout основывается на направлении flex-потока. Обратите внимание на фигуру из спецификации, которая объясняет основную идею flex layout.
Элементы могут быть расположены вдоль главной оси (main axis, от main-start до main-end) или вдоль поперечной оси (cross axis, от cross-start до cross-end).
- main axis - Главная ось flex-контейнера, вдоль которой лежат flex-элементы. Осторожно, это необязательно горизонтальная ось; это зависит от свойства
flex-direction
(см. ниже). - main-start | main-end – flex-элементы расположены внутри контейнера, начиная от main-start и заканчивая main-end.
- main size - ширина или высота flex-элемента, в зависимости от main axis.
- cross axis - поперечная ось, ось перпендикулярная к основной оси называется поперечной осью. Ее направление зависит от направления главной оси (main axis).
- cross-start | cross-end - flex строки заполняются элементами и расположены внутри контейнера, начиная со стороны cross-start flex-контейнера и идут к стороне cross-end.
- cross size - Ширина или высота flex-элемента, в зависимости от cross axis.
Свойства родителя (flex-контейнер)
display
Этим свойством определяется flex-контейнер; встроенный или блочный, зависит от переданного значения. Этим мы включаем flex контекст для всех непосредственных детей.
.container {
display: flex; /* or inline-flex */
}
Отметьте, что CSS columns не работает с flex-контейнером.
flex-direction
Устанавливает главную ось (main-axis), тем самым определяя направление у flex-элементов расположенных в flex-контейнере.
.container {
flex-direction: row | row-reverse | column | column-reverse;
}
row
(по умолчанию) - слева направо в ltr; справо налево в rtlrow-reverse
- справо налево в ltr; слева направо в rtlcolumn
- агалогичноrow
, но сверху внизcolumn-reverse
- аналогичноrow-reverse
, но снизу вверх
flex-wrap
По умолчанию, все flex-элементы будут пытаться поместиться на одной строке. Вы можете изменить это поведение и позволить элементам складываться (wrap
) по мере необходимости.
Направление здесь также играет роль, определяя направление новых строк.
.container{
flex-wrap: nowrap | wrap | wrap-reverse;
}
nowrap
(по умолчанию) - одна линия / слева направо в ltr; справо налево в rtlwrap
- несколько линий / слева направо в ltr; справо налево в rtlwrap-reverse
- несколько линий / справо налево в ltr; слева направо в rtl
flex-flow
Это сокращение для свойств flex-direction
и flex-wrap
, которые вместе определяют главную и поперечную ось flex-контейнера.
По умолчанию row
nowrap
.
flex-flow: <‘flex-direction’> || <‘flex-wrap’> /* default: row nowrap */
justify-content
Определяет выравнивание вдоль главной оси. Это помогает распределять оставшееся свободное пространство, когда каждый flex-элемент в строке не гибкий, или гибкие, но уже достигли своих максимальных размеров.
Также оно оказывает некоторое влияние на выравнивание элементов в случае переполнения (overflow) строки.
.container {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
flex-start
(по умолчанию) - элементы прижаты к началу строкиflex-end
- элементы прижаты к концу строкиcenter
- элементы центрируются вдоль строкиspace-between
- элементы равномерно распределяются в строке; первый элемент у начала строки, последний в конце строкиspace-around
- элементы равномерно распределяются в строке с равными промежутками между ними. Отметьте, что визуально промежутки не равны (для первого и споследнего элемента), так как все элементы имеют одинаковое пространство с обоих сторон.
align-items
Определяет поведение того, как flex-элементы располагаются вдоль поперечной оси на текущей строке. Представьте justify-content
, но для поперечной оси.
.container {
align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start
- верхний край элементов прижимается к cross-start линии (поперечному началу)flex-end
- нижний край элементов прижимается к cross-end линии (поперечному концу)center
- элементы центрируются в поперечной осиbaseline
- элементы выравниваются по своей базовой линииstretch
(по умолчанию) - растягиваются, чтобы заполнить контейнер (по-прежнему уважаютmin-width
/max-width
)
align-content
Выравнивает строки внутри flex-контейнера, когда есть дополнительное пространство в поперечной оси (cross-axis), подобно тому как justify-content
выравнивает отдельные элементы внутри
главной оси (main-axis).
Отметьте, что свойство не работает, когда есть только одна строка flex-элементов.
.container {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
flex-start
- строки прижимаются к началу контейнераflex-end
- строки прижимаются к концу контейнераcenter
- строки центрируются относительно контейнераspace-between
- строки равномерно распределяются; первая строка располагается у начала контейнера, последняя - в концеspace-around
- строки равномерно распределяются с одинаковым промежутком между каждой строкойstretch
(по умолчанию) - строки растягиваются, чтобы заполнить свободное пространство
Свойства потомков (flex-элементов)
order
По умолчанию flex-элементы раполагаются в исходном порядке. Однако, свойство order
контролирует порядок расположения flex-элементов в flex-контейнере.
По умолчанию 0
, поэтому все что больше 0
расположится справа, а все что меньше 0
- слева.
.item {
order: <integer>;
}
flex-grow
Свойство flex-grow
определяет способность для flex-элемента расти, если это необходимо. Оно принимает безразмерное значение, которое служит в качестве пропорции. Оно диктует сколько свободного пространства внутри flex-контейнера должен занимать элемент.
Все элементы имеют flex-grow
равный 1
, при этом свободное пространство в контейнере будет распределено равномерно между всеми детьми. Если один из потомков имеет значение 2
, то он попытается занять в 2 раза больше пространства по сравнению с другими элементами (по крайней мере попытается - "он по крайней мере попытался!").
.item {
flex-grow: <number>; /* default 0 */
}
Негативное значение невалидно.
flex-shrink
Определяет способность для flex-элемента сокращаться при необходимости.
.item {
flex-shrink: <number>; /* default 1 */
}
Негативное значение невалидно.
flex-basis
Свойство flex-basis
определяет размер элемента перед распределением оставшегося пространства в контейнере. Это может быть длина (например, 20%, 5rem, и т.д.) или ключевое слово. Ключевое слово
auto
означает "смотри на мои свойства height или width". Ключеволе слово content
означает "размер основан на контенте элемента" - это ключевое слово невполне поддерживается.
.item {
flex-basis: <length> | auto; /* default auto */
}
flex
Это сокращение для комбинации flex-grow
, flex-shrink
и flex-basis
. Второй и третий параметры (flex-shrink
и flex-basis
) необязательны.
По умолчанию 0 1 auto.
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
/* По умолчанию 0 1 auto */
Рекомендую вам использовать это свойство в противовес индивидуальным свойствам.
align-self
Это свойство позволяет переопределить выравнивание (заданное в align-items
) для отдельных flex-элементов.
Для лучшего понимая всех значений align-self
обратитесь к документации.
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
Отметьть что float
, clear
и vertical-align
не работают с flex-элементами.
Примеры
Давайте начнем с простого примера, разрешая почти ежедневную проблему: идеальное центрирование. Это должно быть очень простым, если вы используете flexbox.
.parent {
display: flex;
height: 300px; /* Or whatever */
}
.child {
width: 100px; /* Or whatever */
height: 100px; /* Or whatever */
margin: auto; /* Magic! */
}
See the Pen center on flex.
Этот пример основывается на том, что свойство margin, заданное потомку во flex-контейнере, поглощает свободное пространство. Таким образом, установив вертикальный margin в auto
, вы прекрасно центрируете элемент относительно обеих осей.
Давайте воспользуемся некоторыми дополнительными свойствами. Рассмотрим список из 6 элементов фиксированного размера, также они могут иметь auto
размер. Мы хотим, чтобы они были равномерно и красиво распределены по главной оси таким образом, чтобы, когда мы меняем размер браузера все выглядело бы прекрасно (без медиа-запросов).
.flex-container {
/* Сперва создадим flex контекст */
display: flex;
/* затем определим направление потока и сворачивание элементов
* Напомню, что это также:
* flex-direction: row;
* flex-wrap: wrap;
*/
flex-flow: row wrap;
/* Затем мы опредим то как распределять свободное пространство */
justify-content: space-around;
}
Готово. Ниже представлен пример на основе нашего кода. Откройте CodePen, измените размер вашего браузера и понаблюдайте за тем что получится.
See the Pen Flexbox demo.
Давайте попробуем что-нибудь еще. Представьте, что у нас есть в самом верху выравненная по правому краю навигация по сайту, но нам нужно, чтобы навигация центрировалась для средних экранов и складывалась в одну колонку на небольших устройствах.
/* Large */
.navigation {
display: flex;
flex-flow: row wrap;
/* Этим выравниваем элементы по концу строки на главной оси */
justify-content: flex-end;
}
/* Medium screens */
@media all and (max-width: 800px) {
.navigation {
/* На средних экранах центрируем равномерно распределяя пустое пространство вогруг элементов */
justify-content: space-around;
}
}
/* Small screens */
@media all and (max-width: 500px) {
.navigation {
/* На небольших экранах мы не используем значение row для flex-direction, поменяв его на column */
flex-direction: column;
}
}
Увеличим сложность. Давайте сделаем трехколончатый mobile-first макет с футером и шапкой во всю ширину.
.wrapper {
display: flex;
flex-flow: row wrap;
}
/* Этим мы говорим, что все элементы должны быть шириной 100% */
.header, .main, .nav, .aside, .footer {
flex: 1 100%;
}
/*
* flex:'flex-grow''flex-shrink''flex-basis'
* default: 0 1 auto
*/
/* Исходный порядок ириентирован на моб. устройства (mobile-first подход)
* В нашем случае это:
* 1. header
* 2. nav (?)
* 3. main
* 4. aside
* 5. footer
*/
/* Средние экраны */
@media all and (min-width: 600px) {
/* Мы располагаем сайдбары на одной строке */
.aside { flex: 1 auto; }
}
/* Большие экраны */
@media all and (min-width: 800px) {
/* Мы меняем местами элементы .aside-1 и .main, а говорим
* элементу .main забирать в два раза больше места, чем сайдбары.
*/
.main { flex: 2 0px; }
.aside-1 { order: 1; }
.main { order: 2; }
.aside-2 { order: 3; }
.footer { order: 4; }
}
See the Pen Demo Flexbox 3.
Источник
Подведем итоги
SCSS
.container {
background: gray;
display : flex; /* inline-flex */
/* расположение осей: */
flex-direction: row; /* column, row-reverse */
/* выравнивание по главной оси: */
justify-content: flex-start /*default*/; /* flex-start, flex-end, center, space-between, space-around */
/* выравнивание по поперечной оси */
align-items: stretch /*default*/; /* flex-start, flex-end, center, baseline */
}
/* Многострочный контейнер */
.container_multiple-row {
flex-wrap: nowrap /*default*/; /* wrap, wrap-reverse */
/* выравниваем строки */
align-content: flex-start /*default*/; /* flex-start, flex-end, center, space-between, space-around, stretch */
}
.container__item {
/* выравнивание (заданное в align-items) для конкретного flex-элемента */
align-self: stretch; /* auto (default) | flex-start | flex-end | center | baseline | stretch */
/* порядок расположения: */
order: 0 /*default*/;
/* by default: flex-grow: 0; flex-shrink: 1; flex-basis: auto*/
/* Одно значение, число без размерности: flex-grow */ /* https://developer.mozilla.org/ru/docsflex */
flex: 1;
/* расти эл-ту или нет; по умолчанию 0 - нет; значение служит в качестве пропорции.
оно говорит: 'Сколько съесть места в котейнере по отношению к другим'*/
flex-grow: 0 /*default 0*/;
// пример: если места в контейнере не хватает, то второй блок будет сжиматься в 3 раза больше, чем остальные
flex-shrink: 3 /*flex-shrink: 1*/;
// задает минимальный размер item
flex-basis: auto /*default 0*/;
}
/* Примеры */
.flex-container {
border: 1px dashed #999; max-width: 1000px; margin: 20px auto 0;
display: flex;
justify-content: center;
height: 300px;
align-items: center;
}
.flex-item {
color: #ecf0f1; padding: 20px; font-size: 18px; font-weight: bold;
&:nth-child(3) {
height: 100px;
}
&:nth-child(2) {
height: 150px;
font-size: 30px;
}
&:nth-child(4) {
align-self: flex-end;
}
}
// 2-й пример
.flex-container_1 {
border: 1px dashed #999; max-width: 1000px; margin: 20px auto 0;
display: flex;
flex-wrap: wrap;
}
.flex-item_1 {
color: #ecf0f1; padding: 20px; font-size: 18px; font-weight: bold;
//width: 300px;
&:nth-child(3) {
margin-left: auto;
}
}
// 3-й пример (order elements in container)
.flex-container_2 {
border: 1px dashed #999; max-width: 1000px; margin: 20px auto 0;
display: flex;
}
.flex-item_2 {
color: #ecf0f1; padding: 20px; font-size: 18px; font-weight: bold;
width: 300px;
&:nth-child(3) {
order: -20;
}
&:nth-child(4) {
order: -10;
}
}
// 4-й пример (property flex for item)
.flex-container_3 {
border: 1px dashed #999; max-width: 1000px; margin: 20px auto 0;
display: flex;
}
.flex-item_3 {
color: #ecf0f1; padding: 20px; font-size: 18px; font-weight: bold;
/* by default: flex-grow: 0; flex-shrink: 1; flex-basis: auto*/
//flex: 1; /* OR flex: 1 1 auto; */
flex-shrink:1;
// задает минимальный размер item
flex-basis: 100px;
&:nth-child(2) {
flex-grow: 2;
// если места в контейнере не хватает, то второй блок будет сжиматься в 3 раза больше, чем остальные
flex-shrink: 3;
}
}
Другие ресурсы
- flexbox на w3c
- flexbox на MDN
- Визуальное руководство по свойствам Flexbox из CSS3
- Смешанный синтаксис для лучшей поддержки браузерами (using-flexbox на CSS-TRICKS)
- flexplorer - онлайн инструмент для flexbox
Комментарии к статье