В этой статье познакомимся с технологией CSS Flexbox, предназначенной для создания гибких макетов веб-страниц.

CSS - Flexbox верстка

Поддержка браузерами технологии CSS Flexbox

Технология Flexbox поддерживается уже почти всеми используемые на сегодняшний момент браузерами (с использованием префиксов: IE10+, Edge12+, Firefox 2+, Chrome 4+, Safari 3.1+, Opera 12.1+, iOS Safari 3.2, Opera mini, Android 2.1+, Blackberry 7+).

Основы Flexbox (сетка)

В основу Flexbox положена сетка. Она состоит всего из 2 элементов. Первый элемент – это flex-контейнер. Создание flex-контейнера осуществляется посредством добавления к необходимому HTML элементу CSS-свойства display со значением flex или flex-inline.

После этого все непосредственные дочерние элементы flex-контейнера (дети) автоматически становятся flex-элементами (2 элемент flexbox сетки).

HTML разметка:

<div class="flex-container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

CSS-стили:

.flex-container {
  display: flex; /* flex || inline-flex */
}
Структура flexbox сетки
Структура flexbox сетки

Flex-элементы по умолчанию занимают всю высоту flex-контейнера.

Значение flex или flex-inline определяет то, как flex-контейнер будет представлен на странице. Если его необходимо представить как блок, то используйте значение flex. Если элемент необходимо представить как строчный, то используйте значение flex-inline. В этом случае он будет занимать столько места странице, сколько необходимо для отображения его элементов.

Направление выстраивания flex-элементов

Указание направления выстраивания flex-элементов внутри flex-контейнера осуществляется посредством осей.

CSS Flexbox - Направление осей по умолчанию
CSS Flexbox - Направление осей по умолчанию

Во flexbox выделяют 2 оси. Первая ось называется основной или главной (по умолчанию направлена вправо). Вторая - поперечная (по умолчанию направлена вниз).

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

Расположение элементов в контейнере по умолчанию (flex-элементы, которым не хватает места во flex-контейнере, вылезают за его пределы)
CSS Flexbox - Расположение элементов в контейнере по умолчанию

В CSS Flexbox разрешить перенос flex-элементов на новые линии (если им не хватает места в текущей линии) осуществляется с помощью установки flex-контейнеру CSS свойства flex-wrap со значением wrap или wrap-reverse.

flex-wrap: wrap; 
/* 
  nowrap (в одну линию - по умолчанию) 
  wrap (разрешить перенос flex-элементов на новые линии) 
  wrap-reverse (осуществлять перенос flex-элементов в обратном порядке) 
*/

Значения wrap и wrap-reverse CSS-свойства flex-wrap определяют направление поперечной оси.

Установка направления главной оси flexbox осуществляется с помощью CSS-свойства flex-direction.

flex-direction: row; 
/* 
  row (вправо) - по умолчанию
  row-reverse (налево)
  column (вниз)
  column-reverse (вверх)
*/

С помощью этого свойства можно сделать так, чтобы flex-элементы располагались не горизонтально (строками), а вертикально (колонками).

CSS Flexbox - Расположение элементов при установке свойству flex-direction значения column, а flex-wrap - wrap
CSS Flexbox - Расположение элементов при установке свойству flex-direction значения column, а flex-wrap - wrap

Свойства flex-direction и flex-wrap можно указать с помощью универсального CSS свойства flex-flow:

flex-flow: row nowrap; /* 1 значение - flex-direction, 2 значение - flex-wrap */

Выравнивание flex-элементов

Во Flexbox выравнивание элементов внутри контейнера осуществляется по двум направлениям (осям).

Выравнивание flex-элементов по направлению главной оси

Выравнивание элементов вдоль основной оси осуществляется с помощью CSS свойства justify-content:

justify-content: flex-start; 
/* 
  flex-start (flex-элементы выравниваются относительно начала оси) – по умолчанию
  flex-end (flex-элементы выравниваются относительно конца оси)
  center (по центру flex-контейнера)
  space-between (равномерно, т.е. с одинаковым расстоянием между flex-элементами)
  space-around (равномерно, но с добавлением половины пространства перед первым flex-элементом и после последнего)
*/
Варианты выравнивания flex-элементов вдоль главной оси
CSS Flexbox - Варианты выравнивания flex-элементов вдоль главной оси

Выравнивание flex-элементов вдоль поперечной оси

Выравнивание flex-элементов во flex-контейнере по направлению поперечной оси осуществляется с помощью CSS-свойства align-items:

align-items: stretch;
/* 
  stretch (растягиваются по всей длине поперечной оси) – по умолчанию
  flex-start (относительно начала поперечной оси)
  flex-end (относительно конца поперечной оси)
  baseline (относительно базовой линии)
  center (по центру)
*/
Варианты выравнивания flex-элементов вдоль поперечной оси
CSS Flexbox - Варианты выравнивания flex-элементов вдоль поперечной оси<

Выравнивание линий flex-контейнера

CSS Flexbox позволяет выравнивать не только сами flex-элементы, но и линии на которых они расположены.

align-content: stretch
/* 
  stretch (растягиваются по всей длине поперечной оси) – по умолчанию
  flex-start (относительно начала поперечной оси)
  flex-end (относительно конца поперечной оси)
  center (по центру)
  space-between (равномерно, т.е. с одинаковым расстоянием между линиями)
  space-around (равномерно, но с добавлением половины  пространства перед первой линией и после последней)
*/
Варианты выравнивания линий flex-контейнера
CSS Flexbox - Варианты выравнивания линий flex-контейнера<

Свойство align-content имеет смысл использовать только тогда, когда flex-элементы во flex-контейнере располагаются на нескольких линиях. Чтобы это произошло, необходимо, во-первых, чтобы ширина всех flex-элементов была больше ширины flex-контейнера, а во-вторых flex-контейнер должен иметь в качестве CSS-свойства flex-wrap значение wrap или wrap-reverse.

CSS-свойство align-self

Свойство align-self в отличие от предыдущих (justify-content, align-items и align-content) предназначено для flex-элементов. Оно позволяет изменить выравнивание flex-элемента вдоль направления поперечной оси. Свойство align-self может принимать такие же значения как align-items.

align-items: stretch; /* auto (по умолчанию) || stretch || flex-start || flex-end || baseline || center */

Пример:

<div class="flex-container">
  <div class="flex-container_element-1">
    1
  </div>
  <div class="flex-container_element-2">
    2
  </div>
  <div class="flex-container_element-3">
    3
  </div>
  <div class="flex-container_element-4">
    4
  </div>  
</div>

CSS:

.flex-container {
  display: flex;
  width: 300px;
  height: 150px;
  align-items: center;
  padding: 10px;
  background-color: #efefef;
}
.flex-container_element-1,
.flex-container_element-2,
.flex-container_element-3,
.flex-container_element-4 {
  flex-basis: 70px;
  text-align: center;
  padding: 15px;
  font-size: 30px;
} 
.flex-container_element-1 {
  align-self: flex-start;
  background: #fe4;
} 
.flex-container_element-2 {
  align-self: flex-end;
  background: pink;
} 
.flex-container_element-3 {
  align-self: stretch;
  background: lime;
}
.flex-container_element-4 {
  align-self: auto;
  background: cyan;
}  
Как работает CSS свойство align-self
Как работает CSS свойство align-self

Изменение порядка следования flex-элементов

По умолчанию flex-элементы отображаются во flex-контейнере в том порядке, в котором они расположены в HTML коде. Для изменения порядка следования одних flex-элементов относительно других в CSS Flexbox можно использовать свойство order. Данное CSS свойство выстраивает flex-элементы во flex-контейнере в порядке возрастания их номеров.

order: 0; 
/* 
  0 (по умолчанию)
  целое положительное или отрицательное число
*/

Например:

<div class="flex-container">
  <div class="flex-container_element-1">...</div>
  <div class="flex-container_element-2">...</div>
  <div class="flex-container_element-3">...</div>
  <div class="flex-container_element-4">...</div>
</div>
CSS:
.flex-container {
  display: flex;
}
/* переместим 2 flex-элемент в конец */
.flex-container_element-2 {
  order: 2;
} 
/* передвинем 3 элемент до 2 */
.flex-container_element-3 {
  order: 1;
}
/* расположим 4 flex-элемент до 1 */
.flex-container_element-4 {
  order: -1;
}
Как работает CSS свойство order
Flexbox - Как работает CSS свойство order

Управление шириной flex-элемента

Во Flexbox есть несколько CSS свойств, определяющих то, какая ширина может быть у flex-элемента.

CSS-свойство flex-basis

Данное свойство предназначено для установления начальной ширины flex-элементу. Задавать значение ширины можно посредством различных единиц измерения, таких как px, %, em и др. По умолчанию данное свойство имеет значение auto (в этом случае ширина элемента будет рассчитываться автоматически на основании его содержимого).

Конечная ширина flex-элемента будет определяться в зависимости от значений CSS-свойств flex-grow и flex-shrink, которые установлены не только для этого элемента, но и для других flex-элементов этого flex-контейнера.

CSS-свойство flex-grow

Это свойство определяет, может ли начальная ширина flex-элемента увеличиваться (расти). Увеличение ширины flex-элемента осуществляется за счёт свободного пространства линии. В качестве значения CSS-свойства flex-grow указывается целое число. Именно это значение и определяет (если оно больше или равно 1) какую часть свободного пространства flex-элемент заберёт себе.

Например:

<div class="flex-container">
  <div class="flex-container_element-1">...</div>
  <div class="flex-container_element-2">...</div>   
</div>
CSS:
.flex-container {
  display: flex;
  width: 600px;
}
.flex-container_element-1 {
  flex-basis: 40%;
  flex-grow: 1;
} 
.flex-container_element-2 {
  flex-basis: 40%;
  flex-grow: 4;
}
Как работает CSS свойство flex-grow
Как работает CSS свойство flex-grow

В этом примере, если flex-элементы расположены на одной линии и в ней есть свободное пространство (600×(1-0,8)=120px):

  • к ширине элемента .flex-container_element-1 добавится 1/5 часть этого пространства (120×1/5=24px);
  • к ширине элемента .flex-container_element-2 добавится 4/5 части этого пространства (120×4/5=96px).

Другими словами, CSS свойство flex-grow позволяет не просто указать, что ширина flex-элемента может вырасти, но и задать, насколько эта величина может вырасти по отношению к другим элементам.

По умолчанию CSS свойство flex-grow имеет значение 0. Это означает, что flex-элемент не может расти (увеличивать свою ширину).

CSS-свойство flex-shrink

Данное свойство определяет, может ли ширина flex-элемента уменьшиться. Уменьшение ширины flex-элемента будет осуществляться только в том случае, если ширины линии будет не достаточно для отображения всех flex-элементов, расположенных в ней. Необходимая ширина рассчитывается на основании начальной ширины, который имеет каждый flex-элемент в ней.

Например:

<div class="flex-container">
  <div class="flex-container_element-1">...</div>
  <div class="flex-container_element-2">...</div>   
</div>
CSS:
.flex-container {
  display: flex;
  width: 500px;
}
.flex-container_element-1 {
  flex-basis: 300px;
  flex-grow: 1;
} 
.flex-container_element-2 {
  flex-basis: 300px;
  flex-grow: 3;
}
Как работает CSS свойство flex-shrink
Как работает CSS свойство flex-shrink

Ширина flex-контейнера 500px. Для отображения flex-элементов необходимо 600px. В итоге не хватает 100px. В этом примере уменьшаться могут 2 flex-элемента (.flex-container_element-1 и .flex-container_element-2). Ширина первого flex-элемента .flex-container_element-1 в данном случае составит 300 – 1/4*100= 275px. Ширина второго flex-элемента .flex-container_element-2 в данном случае составит 300 – 3/4*100= 225px.

Значение по умолчанию:

flex-shrink: 1;

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

CSS-свойство flex

Для удобной установки flex-grow, flex-shrink и flex-basis можно использовать CSS свойство flex.

Значение по умолчанию:

flex: 0 1 auto;
/*
  0 - flex-grow (1 значение)
  1 - flex-shrink (2 значение)
  auto - flex-basis (3 значение)
*/

Верстка макета страницы на CSS Flexbox

В этом разделе создадим простой адаптивный макет на Flexbox.

Структура макета будет состоять из 3 секций:

  • header (для вывода заголовка и основного меню);
  • main (для отображения основной части);
  • footer (для футера).

Основную часть (main) в свою очередь разделим ещё на 2 раздела (их позиционирование будем осуществлять с помощью CSS Flexbox). На больших экранах (>=992px) эти разделы выстроим горизонтально, а на остальных - вертикально (<992px).

<header class="container">
  [Шапка страницы...]
</header>
<main class="container">
  <div class="row-flex">
    <article class="main_article col-flex">
      [Основная часть...]
    </article>
    <aside class="main_aside col-flex">
      [Дополнительная часть...]
    </aside>
  </div>
</main>
<footer class="container">
  [Футер...]
</footer>
CSS:
/* контейнер (устанавливает  ширину блока в зависимости от ширины viewport) */
.container {
  position: relative;
  margin-left: auto;
  margin-right: auto;
  padding-right: 15px;
  padding-left: 15px;
}
@media (min-width: 576px) {
  .container {
    width: 540px;
    max-width: 100%;
  }
}
@media (min-width: 768px) {
  .container {
    width: 720px;
    max-width: 100%;
  }
}
@media (min-width: 992px) {
  .container {
    width: 960px;
    max-width: 100%;
  }
}
@media (min-width: 1200px) {
  .container {
    width: 1140px;
    max-width: 100%;
  }
}
/* flex-контейнер */
.row-flex {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-flex-wrap: wrap;
      -ms-flex-wrap: wrap;
          flex-wrap: wrap;
  margin-right: -15px;
  margin-left: -15px;
}
/* CSS настройки flex-элементов */
.col-flex {
  position: relative;
  width: 100%;
  min-height: 1px;
  padding-right: 15px;
  padding-left: 15px;
}
/* ширина блоков article и aside по умолчанию */
.main_article, .main_aside {
  -webkit-box-flex: 0;
  -webkit-flex: 0 0 100%;
      -ms-flex: 0 0 100%;
          flex: 0 0 100%;
  max-width: 100%;
}
/* ширина блоков article и aside для больших экранов */
@media (min-width: 992px) {
  /* 2/3 от ширины контейнера */
  .main_article {
    -webkit-box-flex: 0;
    -webkit-flex: 0 0 66.666667%;
        -ms-flex: 0 0 66.666667%;
            flex: 0 0 66.666667%;
    max-width: 66.666667%;
  }
  /* 1/3 от ширины контейнера */
  .main_aside {
    -webkit-box-flex: 0;
    -webkit-flex: 0 0 33.333333%;
        -ms-flex: 0 0 33.333333%;
            flex: 0 0 33.333333%;
    max-width: 33.333333%;
  }
}

Для поддержки макета большинством браузеров добавим в CSS необходимые префиксы и max-width.

Для «превращения» блока во flex-контейнер будем использовать класс row-flex. Установку ширины каждому flex-элементу (main_article и main_aside) внутри flex-контейнера будем осуществлять с помощью CSS-свойства flex.

Макет веб-страницы на Flexbox
Макет веб-страницы на Flexbox

В качестве примера разметим посредством Flexbox ещё блок «Футер» и секцию раздела main-article «Интересненькое на сайте».

Секцию «Футер» разделим на 4 равные части (минимальная ширина одной части - 200px), а «Интересненькое на сайте» на 3 части (минимальная ширина одной части - 300px).

<header class="container">
  [Шапка страницы...]
</header>
<main class="container">
  <div class="row-flex">
    <article class="main_article col-flex">
      [Основная часть...]
      <!-- Секция "Интересненькое на сайте -->
      <div class="row-flex">
        <div class="main_other_article col-flex" style="min-width:300px">
          [Ещё 1...]
        </div>
        <div class="main_other_article col-flex" style="min-width:300px">
          [Ещё 2...]
        </div>
        <div class="main_other_article col-flex" style="min-width:300px">
          [Ещё 3...]
        </div>
      </div>
    </article>
    <aside class="main_aside col-flex">
      [Дополнительная часть...]
    </aside>
  </div>
</main>
<footer class="container">
  <div class="row-flex">
    <div class="footer_block col-flex" style="min-width:200px">
      [Секция футера 1...]
    </div>
    <div class="footer_block col-flex" style="min-width:200px">
      [Секция футера 2...]
    </div>
    <div class="footer_block col-flex" style="min-width:200px">
      [Секция футера 3...]
    </div>
    <div class="footer_block col-flex" style="min-width:200px">
      [Секция футера 4...]
    </div>
  </div>
</footer>

Дополнительный CSS:

.footer_block, .main_other_article {
  -webkit-flex-basis: 0;
      -ms-flex-preferred-size: 0;
          flex-basis: 0;
  -webkit-box-flex: 1;
  -webkit-flex-grow: 1;
      -ms-flex-positive: 1;
          flex-grow: 1;
  max-width: 100%;
}

Демо макета страницы на Flexbox