Повний посібник з Flexbox

Повний посібник з Flexbox

  • 22 березня, 2023
  • читати 15 хв

Модуль Flexbox-лейауту (flexible box — «гнучкий блок», на даний момент W3C Candidate Recommendation) ставить завдання запропонувати ефективніший спосіб верстки, вирівнювання та розподілу вільного місця між елементами в контейнері, навіть коли їх розмір невідомий та/або динамічний (звідси слово «Гнучкий»).

Головна задумка flex-верстки у наділенні контейнера здатністю змінювати ширину/висоти (і порядок) своїх елементів для найкращого заповнення простору (у більшості випадків — для підтримки всіх видів дисплеїв та розмірів екранів). Flex-контейнер розтягує елементи для заповнення вільного місця або стискає їх, щоб запобігти виходу за кордон.

Найважливіше, flexbox-лейаут не залежить від напрямку на відміну від звичайних лейаутів (блоки, що розташовуються вертикально, та інлайн-елементи, що розташовуються горизонтально). У той час, як звичайний лейаут відмінно підходить для веб-сторінок, йому не вистачає гнучкості (ніякого каламбуру) для підтримки великих або складних програм (особливо коли справа доходить до зміни орієнтації екрану, зміни розміру, розтягування, стиснення тощо) .

Примітка: Flexbox-лейаут найкраще підходить для складових частин програми та дрібномасштабних лейаутів, у той час як Grid-лейаут більше використовується для лейаутів великого масштабу.

Основи

Так як flexbox — це цілий модуль, а не просто одинична властивість, він поєднує в собі безліч властивостей. Деякі з них повинні застосовуватися до контейнера (батьківського елемента, так званого flex-контейнера), тоді як інші властивості застосовуються до дочірніх елементів або flex-елементів.

Якщо звичайний лейаут ґрунтується на напрямках потоків блокових та інлайн-елементів, то flex-лейаут ґрунтується на «напрямках flex-потоку». Ознайомтеся з цією схемою зі специфікації, яка пояснює основну ідею flex-лейаутів.

В основному елементи розподілятимуться або вздовж головної осі (від main-start до main-end), або вздовж поперечної осі (від cross-start до cross-end).

  • main-axis — головна вісь, вздовж якої розташовуються flex-елементи. Зверніть увагу, вона необов'язково має бути горизонтальною, все залежить від якості flex-direction (див. нижче).
  • main-start | main-end — flex-елементи розміщуються в контейнері від позиції main-start до позиції main-end.
  • main size — ширина або висота flex-елемента в залежності від обраної основної величини. Основна величина може бути або завширшки, або заввишки елемента.
  • cross axis — поперечна вісь, перпендикулярна до головної. Її напрямок залежить від напрямку головної осі.
  • cross-start | cross-end — flex-рядки заповнюються елементами і розміщуються в контейнері від позиції cross-start і до позиції cross-end.
  • cross size — ширина або висота flex-елемента в залежності від обраної розмірності дорівнює цій величині. Ця властивість збігається з width або height елемента, залежно від обраної розмірності.

Властивості

display: flex | inline-flex;

Застосовується до: батьківського елементу flex-контейнера.

Визначає flex-контейнер (інлайновий чи блоковий залежно від обраного значення), підключає flex-контекст всім його безпосередніх нащадків.

display: other values | flex | inline-flex;

Майте на увазі:

  • CSS-стовпці columns не працюють з flex-контейнером
  • float, clear та vertical-align не працюють з flex-елементами

flex-direction

Застосовується до: батьківського елементу flex-контейнера.

Встановлює головну вісь main-axis, визначаючи цим напрямок для flex-елементів, які у контейнері.

flex-direction: row | row-reverse | column | column-reverse

  • row (за замовчуванням): зліва направо для ltr, праворуч наліво для rtl;
  • row-reverse: праворуч наліво для ltr, зліва направо для rtl;
  • column: аналогічно row, зверху донизу;
  • column-reverse: аналогічно row-reverse, знизу нагору.

flex-wrap

Застосовується до: батьківського елементу flex-контейнера.

Визначає, чи контейнер однорядковим або багаторядковим, а також напрямок поперечної осі, що визначає напрямок, в якому будуть розташовуватися нові рядки.

flex-wrap: nowrap | wrap | wrap-reverse

  • nowrap (за замовчуванням): однорядковий / зліва направо для ltr, праворуч наліво для rtl;
  • wrap: багаторядковий / зліва направо для ltr, праворуч наліво для rtl;
  • wrap-reverse: багаторядковий / праворуч наліво для ltr, зліва направо для rtl.

flex-flow

Застосовується до: батьківського елементу flex-контейнера.

Це скорочення для властивостей flex-direction і flex-wrap, що разом визначають головну і поперечну осі. За замовчуванням набуває значення row nowrap.

flex-flow: <'flex-direction'> || <'flex-wrap'>

justify-content

Застосовується до: батьківського елементу flex-контейнера.

Визначає вирівнювання щодо головної осі. Допомагає розподілити вільне місце, що залишилося у випадку, коли елементи рядка не «тягнуться», або тягнуться, але вже досягли свого максимального розміру. Також дозволяє до певної міри керувати вирівнюванням елементів при виході за межі рядка.

justify-content: flex-start | flex-end | center | space-between | space-around

  • flex-start (за замовчуванням): елементи зсуваються на початок рядка;
  • flex-end: елементи зсуваються до кінця рядка;
  • center: елементи вирівнюються по центру рядка;
  • space-between: елементи розподіляються рівномірно (перший елемент на початку рядка, останній - наприкінці);
  • space-around: елементи розподіляються рівномірно з рівною відстанню між собою та межами рядка.

align-items

Застосовується до: батьківського елементу flex-контейнера.

Визначає стандартну поведінку для того, як flex-елементи розташовуються щодо поперечної осі на поточному рядку. Вважайте це версією justify-content для поперечної осі (перпендикулярної до основної).

align-items: flex-start | flex-end | center | baseline | stretch

  • flex-start: межа cross-start для елементів знаходиться на позиції cross-start;
  • flex-end: межа cross-end для елементів знаходиться на позиції cross-end;
  • center: елементи вирівнюються у центрі поперечної осі;
  • baseline: елементи вирівнюються за своєю базовою лінією;
  • stretch (за замовчуванням): елементи розтягуються, заповнюючи контейнер (з урахуванням min-width/max-width).

align-content

Застосовується до: батьківського елементу flex-контейнера.

Вирівнює рядки flex-контейнера за наявності вільного місця на поперечній осі аналогічно тому, як це робить justify-content на головній осі.

Примітка: ця властивість не працює з однорядковим flexbox.

align-content: flex-start | flex-end | center | space-between | space-around | stretch

  • flex-start: рядки вирівнюються щодо початку контейнера;
  • flex-end: рядки вирівнюються щодо кінця контейнера;
  • center: рядки вирівнюються центром контейнера;
  • space-between: рядки розподіляються рівномірно (перший рядок на початку рядка, останній - наприкінці);
  • space-around: рядки розподіляються рівномірно з рівною відстанню між собою;
  • stretch (за замовчуванням): рядки розтягуються, заповнюючи вільний простір.

order

Застосовується до: дочірнього елемента/flex-елементу.

За замовчуванням flex-елементи розміщуються у початковому порядку. Тим не менш, властивість ордер може керувати порядком їхнього розташування в контейнері.

order: <integer>

flex-grow

Застосовується до: дочірнього елемента/flex-елементу.

Визначає для flex-елемента можливість «виростати» за потреби. Приймає безрозмірне значення, що є пропорцією. Воно визначає, яку частку вільного місця всередині контейнера може зайняти елемент.

Якщо у всіх елементів властивість flex-grow встановлено як 1, то кожен нащадок отримає всередині контейнера однаковий розмір. Якщо ви задали одному з нащадків значення 2, він забере вдвічі більше місця, ніж інші.

flex-grow: <number> (за замовчуванням 0)

Негативні числа не приймаються.

flex-shrink

Застосовується до: дочірнього елемента/flex-елементу.

Визначає для flex-елемента можливість при необхідності стискатися.

flex-shrink: <number> (<b>default</b> 1)

Негативні числа не приймаються.

flex-basis

Застосовується до: дочірнього елемента/flex-елементу.

Визначає розмір за замовчуванням елемента перед розподілом простору в контейнері.

flex-basis: <length> | auto (default auto)

flex

Застосовується до: дочірнього елемента/flex-елементу.

Це скорочення для flex-grow, flex-shrink та flex-basis. Другий та третій параметри (flex-shrink, flex-basis) необов'язкові. Значення за замовчуванням – 0 1 auto.

flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

align-self

Застосовується до: дочірнього елемента/flex-елементу.

Дозволяє перевизначити вирівнювання, задане за умовчанням або в align-items для окремих flex-елементів.

Зверніться до опису якості align-items для кращого розуміння доступних значень.

align-self: auto | flex-start | flex-end | center | baseline | stretch

Приклади

Почнемо з дуже простого прикладу, що зустрічається практично кожен день: вирівнювання точно по центру. Немає нічого простішого, якщо використовувати flexbox.

.parent {
  display: flex;
  height: 300px; /* Або що завгодно */
}

.child {
  width: 100px;  /* Або що завгодно */
  height: 100px; /* Або що завгодно */
  margin: auto;  /* Магія! */
}

Цей приклад ґрунтується на тому, що margin у flex-контейнері, заданий як auto, поглинає зайве простір, тому завдання відступу таким чином вирівняє елемент по центру по обох осях.

Тепер давайте використовуємо якісь властивості. Уявіть набір із 6 елементів фіксованого розміру (для краси), але з можливістю зміни розміру контейнера. Ми хочемо рівномірно розподілити їх по горизонталі, щоб при зміні розміру вікна браузера виглядало добре (без @media-запитів!).

.flex-container {
  /* Спочатку створимо flex-контекст */
  display: flex;
  
  /* Тепер визначимо напрямок потоку і чи хочемо ми, щоб елементи
   переносилися на новий рядок
   * Пам'ятайте, що це так само, як і:
   * flex-direction: row;
   * flex-wrap: wrap;
   */
  flex-flow: row wrap;
  
  /* Тепер визначимо, як розподілятиметься простір */
  justify-content: space-around;
}

Готово. Решта — вже справа оформлення.

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

/* Великі екрани */
.navigation {
  display: flex;
  flex-flow: row wrap;
  /* Зсуває елементи до кінця рядка по головній осі */
  justify-content: flex-end;
}

/* Экрани середнього розміру */
@media all and (max-width: 800px) {
  .navigation {
    /* Для екранів середнього розміру ми вирівнюємо навігацію центром,
     рівномірно розподіляючи вільне місце між елементами */
    justify-content: space-around;
  }
}

/* Маленькі екрани */
@media all and (max-width: 500px) {
  .navigation {
    /* На маленьких екранах замість рядка ми маємо елементи в стовпці */
    flex-direction: column;
  }
}

Давайте спробуємо щось краще і пограємо з гнучкістю flex-елементів! Як щодо орієнтованого на мобільні пристрої триколонкового макета з повноширинною шапкою та підвалом? І іншим порядком розташування.

.wrapper {
  display: flex;
  flex-flow: row wrap;
}

/* Задаємо всім елементам ширину 100% */
.header, .main, .nav, .aside, .footer {
  flex: 1 100%;
}

/* У цьому випадку ми покладаємось на вихідний порядок для орієнтації на
 * мобільні пристрої:
 * 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; }
}

Підтримка браузерами

  • (modern) означає підтримку нового синтаксису зі специфікації (display: flex;)
  • (hybrid) означає підтримку старого неофіційного синтаксису з 2011 року (display: flexbox;)
  • (old) означає підтримку старого синтаксису з 2009 року (display: box;)
ChromeSafariFirefoxOperaIEAndroidiOS
21+ (modern)
20- (old)
3.1+ (old)2-21 (old)
22+ (new)
12.1+ (modern)10+ (hybrid)2.1+ (old)3.2+ (old)

Браузер Blackberry версії 10+ підтримує новий синтаксис.

Для отримання детальнішої інформації про те, як і коли використовувати різні синтаксиси для забезпечення кращої підтримки браузерами, зверніться до цієї статті (CSS-Tricks) або цієї статті (DevOpera).

SASS-@mixin для полегшення болю:

@mixin flexbox() {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
}

@mixin flex($values) {
  -webkit-box-flex: $values;
  -moz-box-flex:  $values;
  -webkit-flex:  $values;
  -ms-flex:  $values;
  flex:  $values;
}

@mixin order($val) {
  -webkit-box-ordinal-group: $val;  
  -moz-box-ordinal-group: $val;     
  -ms-flex-order: $val;     
  -webkit-order: $val;  
  order: $val;
}

.wrapper {
  @include flexbox();
}

.item {
  @include flex(1 200px);
  @include order(2);
}