Открыть меню    

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; справо налево в rtl
  • row-reverse - справо налево в ltr; слева направо в rtl
  • column - агалогично row, но сверху вниз
  • column-reverse - аналогично row-reverse, но снизу вверх

    flex-wrap

По умолчанию, все flex-элементы будут пытаться поместиться на одной строке. Вы можете изменить это поведение и позволить элементам складываться (wrap) по мере необходимости.

Направление здесь также играет роль, определяя направление новых строк.

.container{
  flex-wrap: nowrap | wrap | wrap-reverse;
}
  • nowrap (по умолчанию) - одна линия / слева направо в ltr; справо налево в rtl
  • wrap - несколько линий / слева направо в ltr; справо налево в rtl
  • wrap-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

Комментарии к статье