Flexbox

Flexbox (flexible box, гнучкий блок) - новий підхід до розмітки блоків, який вдало поєднує табличне і блочне форматування.

Підтримка флексбоксів браузерами вже є достатньою, щоб застосовувати їх у комерційній верстці.

Бутстрап 4 для формування колонок використовує флексбокси замість флоатів.

Youtube: HTML Шорти - Кому потрібні флекси (5:13).

Напрямки потоків

Flexbox - набір стилів, які необхідно задавати як батьківським елементам, так і дочірнім.

Основа флексів - напрямок потоку. Блочні елементи розташовуються вертикально, строчні елементи - горизонтально, а флекс-елементам можна задавати напрямок розташування, в тому числі і зворотній: справа наліво, знизу вгору.

Flex streams
Напрямки потоків флекс-бокса

Батьківський елемент.

Поексперементуємо у jsFiddle:

ul>li{item $}*20

ul { margin:0; padding: 10px; list-style: none; border: 1px solid green; }
li { float: left; padding: 10px; background: #acf; border: 1px solid #aaa; }

В першу чергу створимо батьківський елемент, обгортку.

Можна використовувати будь-які теги (не порушуючи правила вкладень блочних та строчних елементів). В подальшому в прикладах коду вказані блоки div, але ми будемо працювати зі списком.

<div class="flex">
  ...
</div>

.flex { display: flex; }
// або
.flex { display: inline-flex; } // флекс-аналог inline-block

Ні для обгортки, ні для його дітей першого порядку не можна використовувати флоати та абсолютне чи фіксоване позиціонування (елементи автоматично отримують стиль display: block).

Далі задаємо напрямок розміщення дочірніх блоків. Є 4 варіанти напрямку:

.flex-row { flex-direction: row; }
.flex-wor { flex-direction: row-reverse; }
.flex-col { flex-direction: column; }
.flex-loc { flex-direction: column-reverse; }

<div class="flex flex-row">...</div>
<div class="flex flex-wor">...</div>
<div class="flex flex-col">...</div>
<div class="flex flex-loc">...</div>

row - горизонтальний напрямок потоку;
column - вертикальний напрямок потоку;
reverse - змінити напрямок розташування на протилежний.

При застосуванні вертикального напрямку решта стилів застосовується так, ніби блок повернений на 90 градусів проти часової стрілки, поверніть голову на бік :)

Можна вказати чи флекс-обгортка буде багатострочною, чи однострочною:

.flex { flex-wrap: nowrap; }
.flex { flex-wrap: wrap; }
.flex { flex-wrap: wrap-reverse; }

Значення стиля nowrap - всі блоки намагатимуться поміститися в одному рядку.

Значення стиля wrap - по досягненні кінця рядка блоки будуть переноситися на новий рядок.

Значення стиля wrap-reverse дозволяє змінити порядок рядків, перші елементи будуть знизу.

Попередні два стиля можна об'єднати одним:

.flex { flex-flow: row nowrap; }
.flex { flex-flow: column-reverse wrap; }

Розтягування контенту:

.flex { justify-content: flex-start; }
.flex { justify-content: flex-end; }
.flex { justify-content: center; }
.flex { justify-content: space-between; }
.flex { justify-content: space-around; }
Flex justify
Розтягування контенту

Вирівнювання контенту по вертикалі:

.flex { align-items: flex-start; }
.flex { align-items: flex-end; }
.flex { align-items: center; }
.flex { align-items: stretch; }
.flex { align-items: baseline; }
Flex align-items
Вирівнювання контенту по вертикалі

Для багатострочного флекса є ще властивість, яка керує строками:

.flex { align-content: flex-start; }
.flex { align-content: flex-end; }
.flex { align-content: center; }
.flex { align-content: space-between; }
.flex { align-content: space-around; }
.flex { align-content: stretch; }
Flex
Вирівнювання строк у флексбоксі

Дочірні елементи

Стиль, яким можна керувати порядком елементів:

.flex > div:nth-child(1) { order: 2; }
.flex > div:nth-child(2) { order: 3; }
.flex > div:nth-child(3) { order: 1; }
.flex > div:nth-child(4) { order: 4; }

Стиль, яким можна створити "сітку" з дочірніх елементів. Значення стилю - ціле чи дробне число більше нуля. Якщо задано нуль - блоки розтягуються відповідно іншим стилям.

Число - це пропорційне значення ширини блока.

.flex > div { flex-grow: 2; }
.flex > div:nth-child(2) { flex-grow: 2.5; }
.flex > div.long { flex-grow: 4; }

flex-shrink - стиль, що дає можливість стискатися елементу, числове значення, по замовчуванню - 1.

flex-basis - розмір елемента "по замовчуванню" до його розтягування відповідно стилів flex.

flex - стиль, що об'єднує в собі flex-grow, flex-shrink та flex-basis:

.flex > div { flex: 2 1 auto; }

align-self - дозволяє змінити стиль align-items батьківського елемента для конкретного дочірнього елемента:

.flex > div.end { align-self: flex-end; }

Шпаргалка по ширині дочірніх блоків

Властивість flex керує шириною дочірніх блоків (якщо задано колоночне розташування елементів - то висотою).

Ця властивість комбінована, складається з трьох параметрів:

flex: flex-grow flex-shrink flex-basis;

flex: 0 1 auto;    // значення по-замовчуванню

Можна задавати одне або два значення. Будьте уважні, підставлятися можуть різні параметри, вдумливо ознайомтеся з наступним кодом:

flex: initial;    // flex: 0 1 auto;
flex: none;       // flex: 0 0 auto;
flex: auto;       // flex: 1 1 auto;
flex: content;    // flex: 1 1 content;
flex: 10px;       // flex: 1 1 10px;
flex: 4;          // flex: 4 1 0;

flex: 2 10px;     // flex: 2 1 10px;
flex: 3 2;        // flex: 3 2 0;

Швидка шпаргалка для основних випадків:

ширина = 150px div {
  flex: none;
  width: 150px;
}

ширина <= 150px div {
  width: 150px;
}

ширина = 1/3 від залишку div {
  flex: 1;
}

ширина = 2/3 від залишку div {
  flex: 2;
}

Щоб зрозуміти різницю між першими двома блоками - спробуйте задати їм по-черзі ширину 100%. Перший буде займати рівно всю ширину блока і виштовхне сусідів вправо, другий - займе менше 100%, але доступний йому максимум.

У третьому та четвертому блоці цифри flex сумуються, сума приймається за 100%, і кожен блок буде займати вказану долю.

Наприклад, є 3 блока: два по боках фіксованого розміру, третій має займати всю ширину, що залишилася. Бокові будуть мати стиль { flex: none; width: ...px; } або ж взагалі ширина автоматично буде задаватися, а центральний - { width: 100%; }

Flex-basis

Параметр flex-basis визначає початкову, базову ширину елемента. Може приймати наступні значення:

flex-basis: auto;     // ширина визначається автоматично
flex-basis: 100px;    // ширина в px, %, em і т.д.

flex-basis: fill;           // повна ширина флекс-батька
flex-basis: max-content;    // по максимальній ширині контента
flex-basis: min-content;    // по мінімальній ширині контента
flex-basis: fit-content;    // підлаштовується під розмір контента

flex-basis: inherit;    // наслідування від батьківського елемента
flex-basis: initial;    // auto
flex-basis: unset;      // auto

Частіше за все використовується значення auto, іноді - 0, решта значень досить рідкісні.

Якщо блоку задана властивість flex-basis не-auto, то значення стиля width (або height) для такого блока буде ігноруватися.

Якщо flex-basis: 0 - ширина блока вважається нульовою, далі реальна ширина розраховується через властивості flex-grow та flex-shrink.

Приклади мінімальної і максимальної ширини контента:

lorem
ipsum
dolorize
sit am
lorem ipsum dolorize sit amen

Flex-grow

Принцип дії flex-grow та flex-shrink:

Сума ширин блоків < ширина флекс-обгортки — працює flex-grow.

Сума ширин блоків > ширина флекс-обгортки — працює flex-shrink.

Властивість flex-grow - доля від незайнятого простору флекс-обгортки. Може приймати такі значення:

flex-grow: 0;    // ціле чи дробне число
flex-grow: 1.8;

flex-grow: initial;    // значення по-замовчуванню flex-grow: 0;
flex-grow: inherit;
flex-grow: unset;      // flex-grow: 0;

Розглянемо приклад. У нас є 2 блока шириною 100px і обгортка шириною 500px:

div { display: flex; }

<div>
  <span class="box1"></span>
  <span class="box2"></span>
</div>

У нас ширина всіх блоків = 200px, а ширина обгортки = 500px. Маємо вільні 300px.

Якщо задати обом блокам flex-grow: 1, то вони поділять вільний простір навпіл і кожен блок стане шириною 250px.

span { flex: 1 1 auto; }
span { flex: 5 1 auto; }
span { flex-grow: 1; }    // скорочений варіант

Якщо ж задати їм різні значення, то вільний простір буде поділено між ними пропорційно:

.box1 { flex: 1 1 auto; }    // 100 + 100 * 1 = 200px
.box2 { flex: 2 1 auto; }    // 100 + 100 * 2 = 300px
// сума flex-grow = 3; 300px / 3 = 100px це ширина однієї долі

.box1 { flex-grow: 4; }      // 100 + 54.5 * 4 = 318px
.box2 { flex-grow: 1.5; }    // 100 + 54.5 * 1.5 = 182px
// сума flex-grow = 5.5; 300px / 5.5 = 54.5px це ширина однієї долі

.box1 { flex-grow: 0; }    // 100 + 300 * 0 = 100px
.box2 { flex-grow: 1; }    // 100 + 300 * 1 = 400px
// сума flex-grow = 1; 300px це ширина однієї долі

span { flex-grow: 0; }    // ширина обох блоків залишиться 100px

Flex-shrink

Властивість flex-shrink діє подібно властивості flex-grow, але для надлишкової ширини (висоти) блоків і заставляє їх звузитися. Може приймати ті ж значення, що і flex-grow.

Нехай у нас в обгортці шириною 500px знаходяться три блока, ширина кожного з яких 220px. Маємо 220 * 3 - 500 = 160px надлишкових, тобто, останній блок в рядку буде виступати за межі обгортки на таку ширину.

div { display: flex; }

<div>
  <span class="box1"></span>
  <span class="box2"></span>
  <span class="box3"></span>
</div>

При однакових значеннях flex-shrink у всіх блоків вони звузяться на 160 / 3 = 53px. При різних - буде вираховано пропорцією:

span { flex-shrink: 1; }      // 220 - 53 * 1 = 167px
span { flex: 0 2.5 auto; }    // 220 - 21 * 2.5 = 167px
// сума частин буде 3 і 7.5; 160 / 3 = 53px і 160 / 7.5 = 21px

.box1 { flex-shrink: 1; }    // 220 - 40 * 1 = 180px
.box1 { flex-shrink: 0; }    // 220 - 40 * 0 = 220px
.box1 { flex-shrink: 3; }    // 220 - 40 * 3 = 100px
// сума частин буде 4; 160 / 4 = 40px

Домашнє завдання.

  1. Спробуйте зверстати проект Minecraft флексами.

Шпаргалка по ширині блоків.

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

CSS display: flow-row.

Flexbox adventures (песочница флексбоксов).

Flex-grow.

Flexbox Froggy (игра про флексбоксы).

CSS display: grid.