Какой самый лучший способ понять Flexbox? Изучить основы и написать кучу разных штук. Именно этим мы и займемся.
Но сначала стоит кое-что уточнить:
- Эта статья написана для разработчиков среднего уровня и предполагает, что вы уже имеете представление о Флексбоксах. Но…
- Если вы в курсе, что такое CSS, но не имели дела с Флексбокс, то здесь находится исчерпывающий гид по технологии (статья в открытом доступе, необходимо, примерно, 45 минут на чтение).
- А если вы не особо хороши в CSS, то я рекомендую вам Полное (Практическое) введение в CSS (платный курс, 74 лекции, английский язык).
- Примеры из статьи можно реализовывать в произвольном порядке.
- Флексбокс – всего лишь технология разметки. Реальные проекты одной только разметкой не ограничиваются.
- Обозначения типа div.ohans означают что это элемент div с классом ohans.
Пример 1. Как сделать фотогалерею на Флексбокс
Разместить фотографии по строкам и столбцам на Флексбокс гораздо проще, чем многим кажется.
Рассмотрим простую сетку:
<main class="gallery"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> <img src="/sample.jpg"> </main>
У нас есть main.gallery и 10 изображений в нем.
Убедимся, что main.gallery растягивается на весь доступный экран:
.gallery { min-height: 100vh }
Кое-что об изображениях
По умолчанию все изображения inline-block элементы. У них есть ширина и высота. Они выстроятся в линию (только если они не слишком большие и могут все поместиться)
На старт
Сейчас наша галерея будет выглядеть следующим образом:

Размеры всех 10 изображений остались нетронутыми. При необходимости картинки переместятся на вторую строку. Послушные ребята =)
А теперь, на сцену выходит Флексбокс:
.gallery { display: flex }
С этого момента поведение изображений изменилось. Из inline-block элементов они стали flex-items.
В результате применения Флексбокс к .gallery все картинки уместились в одну линию. Да еще и растянулись по вертикали, вот так:

Картинки теперь уместились все в одну линию, да еще и растянулись по вертикали. Жалкое зрелище =(
Все это результат стандартного поведения Флексбокс:
- Сплющить все дочерние элементы в одну линию и никуда их не переносить. Не самое лучшее решение для галереи, так что изменим его:
.gallery { flex-wrap: wrap }
Это разрешит перенос элементов на другую строку как и полагается

Изображения перенесены
2. Теперь картинки располагаются в несколько линий. Но они все еще растянуты по вертикали и это определенно не характерно для изображений в галерее.
Свойство align-items флекс-контейнера по умолчанию равно значению stretch
.align-items: stretch
Изменим его:
.gallery { ... align-items: flex-start }
Это защитит картинки от растягивания.
Кроме того они выровнены относительно начала вертикальной оси:

Теперь в нашей галерее неискаженные изображения. Почти такие же как и были, пока мы не подключили флексбокс
Наша мощная флексбокс-галерея готова.
Преимущества использования Флексбокс
Сейчас преимущества использования Флексбокс не особо заметны, ведь тот же самый вид был и до его подключения.
Кроме легко получаемой адаптивности, преимущество флексбокс заключается в возможностях выравнивания.
Флекс-контейнер .gallery имеет несколько свойств для настройки выравнивания: flex-direction: row , justify-content: flex-start и align-items: flex-start.
Разметку галереи можно легко поменять поигравшись со следующим значением:
.gallery { ... justify-content:center; }

Теперь изображения идеально отцентрованы по горизонтали
Кроме того, картинки могут быть отцентрованы и по горизонтали и по вертикали .gallery.
.gallery { ... justify-content:center; align-items: center; }

А теперь изображения выровнены не только горизонтально, но и вертикально
Флексбокс предоставляет много вариантов выравнивания. Играйтесь со значениями, как сочтете нужным.
Можете посмотреть на действующую Флексбокс галерею здесь.
Пример 2: Как сделать карточки на Флексбокс
Карточки очень популярны в интернете. Гугл, Твиттер, Пинтерест и прочие им подобные – все используют карточки.
В UI-дизайне карточка – это шаблон, объединяющий схожую информацию в адаптивный контейнер. Внешне он напоминает игральную карту.
Существует много хороших способов применения Карточек. Например, сетка с ценами.

Простая сетка цен
Давайте сделаем такую.
Разметка
Каждая карточка построена следующим образом:
<section class="card"> <header> </header> <ul> <li></li> <li></li> <li></li> </ul> <button></button> </section>
У нас будет как минимум три карточки. Обернем их в div.cards
<div class="cards"></div>
Теперь у нас есть родственные элементы.
В этом примере родственные элементы будут заполнять вcе доступное окно просмотра
.cards { min-height: 100vh }
Установка Флексбокс
Следующий код инициализирует Флексбокс в контексте блока .card
.cards { display: flex; flex-wrap: wrap }
Если вы помните предыдущий пример, flex-wrap позволяет элементам flex-items располагаться в несколько линий, если они не помещаются в контейнер. Давайте зададим .card исходную ширину, используя Флексбокс
.card { flex: 0 0 250px }
Это свойство устанавливает значения flex-grow и flex-shrink равными 0. Значение flex-basis будет равным 250px.
В том виде, что у нас есть сейчас карточки будут выровнены относительно начала страницы и растянуты по вертикали

Изображения выровнены относительно начала страницы
В некоторых случаях это может быть идеальным решением. Но в большинстве случаев – нет.
Поведение флекс-контейнеров по умолчанию
Вид наших карточек является результатом стандартного поведения флекс-контейнеров.
Карточки располагаются в начале страницы (top left) потому что у justify-content установлено значение flex-start.
Кроме того, карточки растянуты на всю высоту родительского элемента, потому что у свойства align-items значение по умолчанию stretch.
Изменение стандартных значений
Мы можем получить впечатляющий результат, изменив стандартные значения флексбокс свойств.
Смотрите сами:

align-items: flex-start; justify-content: center

align-items: center; justify-content: center
Мы можете посмотреть код примера на Codepen.
Пример 3: Как сделать сетку на Флексбокс
На концепции, которая обсуждается в этом примере, строятся целые CSS-фреймфорки. Так что это очень важно.
Что такое сетка?
Сетка – это набор прямых пересекающихся вертикальных и горизонтальных линий, использующихся для структурирования контента

Набор пересекающихся прямых (вертикальных, горизонтальных) направляющих линий
Если вам знакомы CSS-фреймворки, такие как Bootstrap, то вы точно использовали сетки раньше.
Давайте начнем с базовой сетки
Базовая сетка

Базовая сетка с равномерно расположенными столбцами
Некоторые свойства этой сетки:
- Ячейки клетки располагаются равномерно и растянуты по всей ширине линии.
- Все ячейки одинаковой высоты.
Этого очень легко добиться, используя Флейксбокс
<div class="row"> <div class="row_cell">1</div> </div>
Каждая строка .row будет флекс-контейнером.
Каждый элемент внутри .row станет флекс-элементом. Все флех-элементы равномерно распределяются по линии.
С точки зрения дизайна не важно, будет ли у нас три вложенных элемента
<div class="row"> <div class="row_cell">1/3</div> <div class="row_cell">1/3</div> <div class="row_cell">1/3</div> </div>
Или 6:
<div class="row"> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> <div class="row_cell">1/6</div> </div>
Или 12:
<div class="row"> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> <div class="row_cell">1/12</div> </div>
Решение
Чтобы получить этот результат необходимы всего два шага.
- Инициализировать Флексбокс
.row { display: flex; }
- Каждому flex-item позволить заполнять строку в равных пропорциях
.row_cell { flex: 1 }
Вот и все.
Объяснение решения
flex: 1
flex – это сокращенное имя свойства, объединяющего в себе flex-grow, flex-shrink и flex-basis.
flex: 1 – установлено только одно значение для свойства и оно задается свойству flex-grow.
flex-shrink и flex-basis будут равны 1 и 0
flex: 1 === flex: 1 1 0
Ячейки определенного размера
Иногда нам не нужно, чтобы все элементы строки были одинакового размера.
Вам могут понадобиться ячейки вдвое (или в любое другое количество раз) большие чем прочие.

Сетка с ячейками в 2 и в 3 раза большими остальных
Решение довольно просто.
Для конкретно этой ячейки необходимо изменить класс следующим образом:
3 4 5 .row_cell--2 { flex: 2 }
Затем включите класс в разметку:
<div class="row"> <div class="row_cell row_cell--2">2x</div> <div class="row_cell">1/3</div> <div class="row_cell">1/3</div> </div>
Ячейка с классом .row__cell–2 будет в два раза больше ячейки по умолчанию.
Для ячейки, занимающей треть свободного пространства код будет следующий:
.row_cell--3 { flex: 3 }
Ячейки с определенным выравниванием
Благодаря Флекбоксу не нужно для каждой ячейки задавать определенное выравнивание, каждая может иметь свое собственное значение
Используйте следующее свойство:
.row_cell--top { align-self: flex-start }
Таким образом определенная ячейка будет выровнена по верху row.

После добавления класса .row_cell — top ячейка будет выровнена относительно верха строки
Разумеется, вы должны добавить класс этой особой ячейки в разметку. Взгляните на первый вложенный div разметки:
<div class="row"> <div class="row_cell row_cell--top"></div> <div class="row_cell"></div> <div class="row_cell"></div> </div>
Ниже приведены другие примеры выравнивания
.row_cell--bottom { align-self: flex-end }

После добавления класса .row_cell — bottom ячейка будет выровнена относительно низа строки
.row_cell--center { align-self: center }

После добавления класса .row_cell — center ячейка будет выровнена относительно центра строки
Общее выравнивание внутри строк
Выровнены могут быть не только ячейки, но и все дочерние элементы блока.
Измените класс следующим образом:
.row--top { align-items: flex-start }

Все ячейки сетки выровнены относительно верха строки
Очень важно, чтобы измененный класс .row–top был добавлен элементу row или родительскому флекс-контейнеру.
<div class="row row--top"> <div class="row_cell"></div> <div class="row_cell"></div> <div class="row_cell"></div> </div>
Ниже приведены другие варианты выравнивания:
.row--center { align-items: center }

Все ячейки сетки выровнены относительно центра строки
.row--bottom { align-items: flex-end }

Все ячейки сетки выровнены относительно низа строки
Вложенные сетки
Без лишних действий элементы row могут быть вложены друг в друга.

Строка с двумя ячейками, одна больше другой в два раза. В большой ячейке была вложена строка с тремя отцентрованными ячейками
Здесь расположены готовые сетки.
Пример 3: Как сделать макет сайта, используя Флексбокс
Строительство макетов полностью на Флексбокс не особо одобряется сообществом разработчиков.
И, разделяя данное мнение, я все же считаю, что бывают ситуации, когда это допустимо.
Самый главный совет, который я могу вам дать: Используйте флексбокс, когда это имеет смысл.
Я объясню это на следующем примере.
Макет сайта “святой Грааль”
Самый наистандартнейший макет страницы на свете

Макет “святой Грааль” – хэдер, футер и 3 контейнера для контента
Есть два способа попытаться построить этот макет с помощью Flexbox.
Начнем с первого. Для него нужно разместить во флекс-контейнере header, footer, nav, article и aside.
Разметка
Так выглядит наша разметка:
<body> <header>Header</header> <main> <article>Article</article> <nav>Nav</nav> <aside>Aside</aside> </main> <footer>Footer</footer> </body>
Среди прочих, в стандартнейшей разметке есть особое правило: центральная колонка, article в разметке должна идти перед обоими сайдбарами nav и aside.

Article должен идти в разметке первым, но располагаться по центру макета
Подключаем флексбокс
body { display: flex }
Поскольку дочерние элементы должны идти сверху вниз, изменим стандартное направление флексбокс
body { ... flex-direction: column }
- header и footer должны быть фиксированной ширины
header, footer { height: 20vh /*you can use pixels e.g. 200px*/ }
- main должен занимать все свободное пространство в контейнере
main { flex: 1 }
Надеюсь, вы помните, что запись flex: 1 означает тоже самое что и flex-grow: 1, flex-shrink: 1 и flex-basis: 0

Это приведет к тому, что main вырастет и займет все доступное ему место
На этом этапе необходимо позаботиться о содержимом main – блоках article, nav и aside.
Сделаем main флекс-контейнером
main { display: flex }
А для nav и aside установим значение width
nav, aside { width: 20vw }
Убедимся, что article занимает все доступное ему пространство
article { flex: 1 }

Теперь article занимает все свободное место
Осталось сделать всего одну вещь. Поменяем значения flex-order, чтобы nav отображался первым
nav { order: -1 }

Готовый вариант
Свойство order используется, чтобы переопределить порядок flex-items.
Все элементы flex-items внутри контейнера отображаются в порядке возрастания значения order. Элемент с наименьшим значением будет отображаться первым.
По умолчанию значение order для всех flex-items равно 0.
Второе решение для макета
Предыдущее решение использует flex-container для всего контейнера. Макет очень сильно зависит от flexbox.
Посмотрим на более разумный подход. Еще раз взглянем на результат, который должен у нас получиться.

Макет “святой Грааль”
header и footer могут быть блочными элементами. Без лишних вмешательств они и так заполнят все доступное им простанство контейнера и будут прижаты к верху и низу
<body> <header>Header</header> <main> <article>Article</article> <nav>Nav</nav> <aside>Aside</aside> </main> <footer>Footer</footer> </body>
Что означает, что флекс-контейнер необходим только для main.
Единственная сложность здесь заключается в том, что вам необходимо самим вычислить высоту блока main. Он должен занимать все свободное пространство между header и footer
main { height: calc(100vh - 40vh); }
Рассмотрим этот код. Он использует CSS функцию calc для того, чтобы вычислить высоту main.
Высота блока должна быть равна calc (100vh – высота хэдера – высота футера).
В предыдущем случае вы должны были задать фиксированную высоту футеру и хэдеру. Теперь вы поступаете таким же образом только с main.
Здесь лежит готовый результат.
Макет сайта в 2 колонки
Двухколоночный макет очень распространен. Их тоже очень легко строить на флексбокс.

Макет сайта в две колонки (сайдбар и основной контент)
Вот наша верстка:
<body> <aside>sidebar</aside> <main>main</main> </body>
Инициализируем флексбокс
body { display: flex; }
Задаем блоку aside фиксированную ширину
aside { width: 20vw }
И, наконец, убедимся, что main занимает все доступное пространство
main { flex: 1 }
Вот, в общем-то, и все, что нужно сделать.
Пример 5. Медиа-объекты на Флексбокс
Медиа-объекты повсюду: от твитов до постов в Фейсбуке.

Обычный пост в Твитере и Фейсбуке
Внимательно посмотрим на верстку
<div class="media"> <img class="media-object" src="/pic.jpg"> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> </div> </div>
Как вы догадались, .media станет нашим основным флекс-контейнером
.media { display: flex }
По умолчанию flex-items контейнера растягивается по вертикали, чтобы занять всю доступную высоту.
Убедимся, что .media-body заполняет все свободное пространство
.media-body { flex: 1 }

Раздел слева занимает все свободное пространство экрана. Тело медиа-объекта занимает оставшееся горизонтальное пространство внутри медиа-объекта (белого цвета)
Давайте зафиксируем тянущийся бокс
.media { ... align-items: flex-start }

Флекс-элементы теперь выровнены по началу медиа-объекта. Размер изображения по умолчанию и никаких странных растяжений =)
Вот и все.
Перевернутый медиа-объект

У перевернутого медиа-объекта изображение располагается с другой стороны (справа), относительно тела объекта
Нет никакой необходимости вносить изменения в html-код, чтобы повернуть медиа-объект.
Просто поменяем местами элементы flex-items вот так:
.media-object { order: 1 }
Теперь картинки будут располагаться после .media-body и media-heading
Вложенные медиа-объекты
Вы можете сделать вложенные медиа-объекты без изменения CSS-стилей, написанных ранее!
<div class="media"> <img class="media-object" src="/pic.jpg"> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> <!--nested--> <div class="media"> <img class="media-object" src="/pic.jpg"> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> </div> </div><!--end nested--> </div> </div>
Все работает!

Медиа-объект, вложенный в медиа-объект
Unicode медиа-объекты
Мы не обязаны ограничиваться только картинками.
Без каких-либо изменений в ранее написанных CSS-стилях, вы можете вместо изображения вставить юникод.
<div class="media"> <div class="media-object">😎</div> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> </div> </div>
Я поместил сюда смайлик

Медиа-объект с эмодзи-смайлом
Чтобы получить этот результат мы просто заменили img на div. А вот здесь вы можете подсмотреть юникоды некоторых смайликов-эмодзи.
Медиа-объект с HTML
А еще вы можете использовать html-объекты как в примере ниже
<div class="media"> <div class="media-object">☎</div> <div class="media-body"> <h3 class="media-heading"> Header </h3> <p></p> </div> </div>
В качестве html-объекта в примере используется ☎ и на картинке вы можете видеть результат

&phone
Поэкспериментируйте с этими примерами на CodePen.
Пример 6. Как сделать компоненты форм на Флексбокс
Очень сложно найти сайты, которые не используют формы в том или ином виде

Поля формы могут иметь не только место для ввода, но и другие элементы
Посмотрим на код
В этом примере представлена комбинация выровненных полей ввода с кнопкой или с текстовым блоком. И вновь, это очень легко сделать при помощи флексбокса.
Инициализируем флексбокс-контекст
.form { display: flex }
Убедимся, что поле занимает все доступное ему пространство
.form__field { flex: 1 }
Наконец, по своему желанию, вы можете добавить стили для кнопок и блоков с текстом
.form__item { ... }
Код из этих примеров есть на Codepen.
Пример 7. Как сделать макет мобильного приложения на Флексбокс
В этом примере рассмотрим построение вот такого макета мобильного приложения.

Макет мобильного приложения, который мы соберем на Флексбокс
Но этот пример будет немного отличаться от предыдущих. Я объясню процесс построения макета при помощи псевдокода, а вы его сделаете.
Считайте это практикой, чтобы вы не расслаблялись.
Шаг 1.
Отделите макет от картинки iPhone и получите следующее:

Скелет макета
Шаг 2.
Определите body как флекс-контейнер.

Инициируйте Флексбокс
Шаг 3.
По умолчанию flex-direction контейнера установлен как row. Но в нашем случае, нужен column.

Измените порядок дочерних флекс-элементов
Шаг 4.
Задайте элементам 1 и 3 фиксированные значения высоты height: 50px.
Шаг 5.
Элемент 2 должен занимать все доступное пространство. Используйте свойство flex-grow или короткую запись flex; 1.
Шаг 6.
Наконец, определите каждый блок контента медиа-объектом, как в предыдущем примере.

Сделайте блоки контента медиа-объектами
В результат этих шести шагов у вас получится макет мобильного приложения.
Заключение
По моему опыту работы в UI рано или поздно вы столкнетесь с одним из вышеперечисленных примеров.
А теперь идите и напишите что-нибудь шикарное!
14 комментариев
Malikero · 02.10.2020 в 20:52
Всем привет! С новым годом, желаю всем счастья, здоровья и удачи в этом году!
Отличный у вас сайт, многие посты очень познавательные.
Joni · 02.10.2020 в 20:53
Здравствуйте. Помогите, пожалуйста, выровнять зеленые блоки по красной линии.http://joxi.ru/gmvzWdDtxWRwdm
summary · 02.10.2020 в 20:53
Добрый день. К сожалению, не видя кода я не могу вам помочь. Если вы заведете песочницу на codepen, к примеру, и дадите ссылку, я с удовольствием взгляну и попробую что-нибудь сделать.
Dmitry · 02.10.2020 в 20:53
Невероятная полезная статья. Спасибо, за предостережение о верстке основных компонентов сайта.
summary · 02.10.2020 в 20:53
Рада была помочь. Оставайтесь с нами
Stepan · 02.10.2020 в 20:54
В начале статьи идет речь о галерее (в качестве примера). А вот как сделать чтоб выравнивание элементов было по обоим краям , как это происходит при justify-content: space-between;, но при этом последняя (незаполненная) строчка не растягивалась на весь контейнер, а элементы в ней располагались с такимже интервалом как и в заполненной строке, начиная с левого края?
summary · 02.10.2020 в 20:54
Здравствуйте. Верно ли я понимаю, что вы хотите, грубо говоря, чтобы первая строка вела себя как при justify-content: space-between, а вторая незаполненная, как при justify-content: flex-start?
К сожалению, возможностями flex так сделать не получится. Тут нет как таковых “строк”, и поведение определяется для всего набора элементов, независимо, в одной они строке, в двух или пятнадцати.
Для того, что вы хотите сделать, думаю, вам больше подойдут CSS Grid.
Анатолий · 02.10.2020 в 20:55
Подскажите, по-вашему мнению правильно ли использовать flexbox-разметку, как вот тут paratapok.ru/frontend/5148_css3-flexbox/ (в самом низу страницы), для верстки макетов из psd? Правильно ли так делать?
summary · 02.10.2020 в 20:55
Добрый день.
Вообще, я считаю, что для раскладок лейаутов уже можно и нужно использовать гриды. Это их основное предназначение, у них есть отличные фишки, упрощающие жизнь. Флексы же лучше использовать для стилизации каких-то внутренних блоков.
С другой стороны, все, что напрямую не запрещено спецификацией – разрешено, поэтому, если вы не знаете гриды, то используйте флексы
Michaeldox · 02.10.2020 в 20:55
Актуально. Подскажите, где я могу найти больше информации по этому вопросу?
summary · 02.10.2020 в 20:56
Добрый день. Могу посоветовать курсы htmlacademy (из платных) или посмотреть примеры кода на Scrimba
Материалов же просто “на почитать” в сети предостаточно.
Удачи!
Иггорь · 02.10.2020 в 20:56
Хорошо продемонстрировано назначения флексов, а самое главное описано откуда у них ноги растут, а именно из сеток, просто долго разбирался с флэксами без сетки – это вызывало затруднения , а теперь все очень понятно.Спасибо!
Песчаный Воин · 02.10.2020 в 20:56
Добрый день!
Пытаюсь разобраться с тестовым сайтом на поддомене следуя вашей статье и ничего не получается. Какой-то момент упускаю.
https://test.voin-zen.ru/
На основном сайте я все сделал быстро и просто, хочу добиться такого же результат с помощью flexbox.
https://voin-zen.ru/
Мне надо чтобы на мобильном тестовый сайт выглядел как и основной.
Не в 3 элемента в строку, а один элемент на весь экран.
Вот стили, назвал почти как у вас. Не улавливаю момент перехода на мобильник
.news-list-flex-cards {
display: flex;
flex-wrap: wrap;
flex-direction:row;
align-items: flex-start;
justify-content: space-between;
min-height: 100vh;
}
.news-item-flex-card {
flex: 0 0 250px;
}
Подскажите что не так делаю. На ПК все нормально, на мобильнике просто уменьшенная версия сайта, не адаптивная.
Фиксированные только размеры блока где картинка
a.news-a {
display:block;
width:299px;
height:189px;
overflow:hidden;
}
a.news-a img {
object-fit: cover;
width: 100%;
height: 189px;
}
summary · 02.10.2020 в 20:57
Добрый день!
У вас в шаблоне есть div c id = “container”, который определяет ширину контентной части страницы. Некий шаблон задает ему width, равный 980px, который все и портит.
Поведение флексовых потомков напрямую зависит от поведения родителя, но, если родитель не меняется, то и потомкам делать нечего. Замените стиль на max-width, если вам нужно, чтобы область начала уменьшаться.
Комментирование закрыто.