10 особенностей CSS Flexible Box Layout, о которых полезно знать веб-разработчику

Пост опубликован в блогах iXBT.com, его автор не имеет отношения к редакции iXBT.com
| Статья | ИИ, сервисы и приложения

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

Тайный способ выравнивания элементов: используем margin со значением auto

Как быть, если первые два элемента внутри flex-контейнера нужно выровнять по левому краю, а последний — сместить к правому? Веб-разработчики, которые не знают, как решить эту задачу за счет установки значения для всего одного свойства, начинают создавать лишние теги HTML. Но решение было заложено в спецификации: нужно добавить для последнего элемента свойство margin-left со значением auto.

HTML:

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

CSS:

html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: border-box;
}

.flex-container {
  display: flex;
  gap: 20px;
  padding: 20px;
  background-color: #ccc;
}

.element {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 120px;
  height: 120px;
  background-color: #555555;
  border: 2px solid #fff;
  font-size: 60px;
  line-height: 1.0;
  font-weight: bold;
  color: #fff;
  text-align: center; 
}

.element:last-child {
  margin-left: auto;
}
Автор: 1024x768

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

Когда контент ломает сетку: секрет min-width

Допустим, у нас есть flex-контейнер с двумя колонками: одна фиксированной ширины, а вторая — «резиновая», в которой находится заголовок с длинным словом и настроенными переносами.

HTML:

<div class="page">
  <div class="sidebar"></div>
  <div class="content">
    <h1>Самосовершенствование</h1>
  </div>
</div>

CSS:

.page {
  display: flex;
  padding: 20px;
  background-color: #ccc;
}

.sidebar {
  flex-shrink: 0;
  width: 160px;
  background-color: #9bce90;
}

.content {
  flex: 1;
  padding: 20px;
  background-color: #eee;
}

.content h1 {
  font-size: 46px;
  line-height: 1.2;
  overflow-wrap: break-word;
}

Автор: 1024x768

Видим, что область с контентом «уехала» за пределы flex-контейнера, а переносы не сработали. Почему так произошло? Дело в том, что согласно спецификации, flex-элементы получили по умолчанию значение auto для свойства min-width. И, в отличие от обычных блоков, они ведут себя иначе: минимальный размер элемента по главной оси определяется размером его содержимого. Обнулим значение свойства min-width и элемент перестанет выходить за пределы flex-контейнера.

.content {
  flex: 1;
  min-width: 0;
  padding: 20px;
  background-color: #eee;
}
Автор: 1024x768

Кто главнее: flex-basis или width?

В предыдущем примере мы определили ширину левой колонки с помощью свойства width. А что будет, если задать также значение для свойства flex-basis?

.sidebar {
  flex-shrink: 0;
  flex-basis: 360px;
  width: 160px;
  background-color: #9bce90;
}
Автор: 1024x768

Как видим, значение flex-basis перебило значение with и ширина колонки стала равной 360 пикселям. А что будет, если определить еще и свойство max-width?

.sidebar {
  flex-shrink: 0;
  flex-basis: 360px;
  width: 160px;
  max-width: 100px;
  background-color: #9bce90;
}
Автор: 1024x768

Max-width победил всех и ширина колонки стала равной 100 пикселям. И, конечно же, стоит сказать о том, что flex-basis всегда работает вдоль главной оси flex-контейнера. Чтобы в этом убедиться, изменим у flex-контейнера значение свойства flex-direction:

.page {
  display: flex;
  flex-direction: column;
  padding: 20px;
  background-color: #ccc;
}
Автор: 1024x768

Особенности работы со слоями

Свойство z-index способно поднять flex-элемент над соседями даже при position со значением static.

HTML:

<div class="gallery">
  <img src="1.jpg" class="item">
  <img src="2.jpg" class="item">
  <img src="3.jpg" class="item">
</div>

CSS:

.gallery {
  display: flex;
  padding: 20px;
  background-color: #ccc;
}

.item {
  width: 260px;
  height: 260px;
  margin-right: -50px;
  border: 2px solid #fff;
}

.item:hover {
  z-index: 10;
  box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.5);
}
Курсор мыши был наведен на второй flex-элемент, который «всплыл» несмотря на то, что у свойства position было значение static
Курсор мыши был наведен на второй flex-элемент, который «всплыл» несмотря на то, что у свойства position было значение static
Автор: 1024x768

Стоит отметить, что эта особенность существует только у прямых потомков flex-контейнера и если вам нужно выстроить слои у вложенных в него элементов, то придется задать значение relative свойству position, иначе значение свойства z-index будет проигнорировано.

Особенности абсолютного позиционирования

Рассмотрим особенности поведения элемента с абсолютным позиционированием, расположенного внутри flex-контейнера. Создадим контейнер, зададим ему фиксированную высоту и установим значением relative для свойства position. Внутри контейнера расположим три элемента и выровняем их по центру как по горизонтали, так и по вертикали.

HTML:

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

CSS:

.flex-container {
  position: relative;
  height: 260px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 20px;
  padding: 20px;
  background-color: #ccc;
}
Автор: 1024x768

Теперь добавим для последнего элемента свойство position со значением absolute и, для наглядности, изменим у него цвет фона:

.element:last-child {
  position: absolute;
  background-color: #843b3e;
}
Автор: 1024x768

Видим, что элемент выпал из общего потока, но, вместо того чтобы переместиться в левый верхний угол flex-контейнера, для которого задано свойство position со значением relative, он расположился по центру. Это произошло из-за того, что на элемент по-прежнему влияют значения свойств justify-content и align-items, определяя его начальное положение. Однако, если ему задать координаты с помощью любого из свойств left, right, top или bottom, но он переместится так, как это сделал бы обычный элемент с абсолютным позиционированием.

.element:last-child {
  position: absolute;
  right: 20px;
  top: 20px;
  background-color: #843b3d;
}
Автор: 1024x768

Схлопывание внешних отступов отменяется

Внутри flex-контейнера создадим два элемента. Первому зададим нижний внешний отступ, а второму — верхний.

HTML:

<div class="flex-container">
  <div class="text">Первый элемент</div>
  <div class="text">Второй элемент</div>
</div>

CSS:

.flex-container {
  display: flex;
  flex-wrap: wrap;
  padding: 20px;
  background-color: #ccc;
}

.text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  background-color: #555555;
  width: 100%;
  height: 120px;
  border: 2px solid #fff;
  font-size: 60px;
  line-height: 1.0;
  font-weight: bold;
  color: #fff;
  text-align: center;
}

.text:first-child {
  margin-bottom: 60px;
}

.text:last-child {
  margin-top: 60px;
}
Автор: 1024x768

Отступы не схлопнулись, как это бывает у обычных блочных элементов, а наоборот сложились и суммарное расстояние между блоками составило 120 пикселей.

Чем отличаются align-content, align-items и align-self

Новички часто путают эти свойства. Разберемся, чем они отличаются на примерах. Создадим flex-контейнер с элементами, включим перенос элементов на другую строку, зададим контейнеру фиксированную высоту и пропишем значение center для свойства align-content. Первому и последнему элементу увеличим высоту.

HTML:

<div class="flex-container">
  <div class="element">1</div>
  <div class="element">2</div>
  <div class="element">3</div>
  <div class="element">4</div>
  <div class="element">5</div>
  <div class="element">6</div>
  <div class="element">7</div>
  <div class="element">8</div>
</div>

CSS:

.flex-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  padding: 20px;
  background-color: #ccc;
  height: 500px;
  align-content: center;
}

.element:first-child {
  height: 140px;
  background-color: #843b3d;
}

.element:last-child {
  height: 140px;
  background-color: #34622a;
}
Автор: 1024x768

Оба ряда были отцентрированы по вертикали как единое целое. Теперь заменим свойство align-content на align-items:

.flex-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  padding: 20px;
  background-color: #ccc;
  height: 500px;
  align-items: center;
}
Автор: 1024x768

Flex-контейнер как бы разделился на две половины и элементы каждой выстроились своими центрами вдоль осей. И теперь пропишем одному из элементов значение flex-start для свойства align-self:

.element:nth-child(3) {
  align-self: flex-start;
  background-color: #33548c;
}
Автор: 1024x768

Элемент получил собственное выравнивание и сместился к верхнему краю flex-контейнера.

Структурные псевдоклассы против свойства order

Создадим flex-контейнер с пятью элементами. У первого, третьего и пятого элементов изменим цвет фона.

HTML:

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

CSS:

.flex-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  padding: 20px;
  background-color: #ccc;
}

.element:first-child {
  background-color: #843b3d;
}

.element:nth-child(3) {
  background-color: #34622a;
}

.element:last-child {
  background-color: #33548c;
}
Автор: 1024x768

Теперь определим значения свойства order для второго и четвертого элементов:

.element:nth-child(2) {
  order: 1;
}

.element:nth-child(4) {
  order: 2;
}
Автор: 1024x768

Цвета элементов остались привязаны к своей структуре в HTML: структурные псевдоклассы ориентируются на порядок тегов в разметке, а не на свойство order. Что делать, если нужно менять порядок элементов на экранах разных устройств, но при этом всегда применять стили к тому, который отображается на экране последним? Для решения этой задачи придется задействовать JavaScript.

Разница между flex и inline-flex

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

HTML:

<div class="example">
  <div class="flex-container flex-container_color_1">
    <div class="element">1</div>
    <div class="element">2</div>
    <div class="element">3</div>
  </div>
  <div class="flex-container flex-container_color_2">
    <div class="element">4</div>
  </div>
</div>

CSS:

.flex-container {
  display: flex;
  gap: 20px;
  padding: 20px;
  background-color: #ccc;
}

.flex-container_color_1 {
  background-color: #f8a4a3;
}

.flex-container_color_2 {
  background-color: #9bce90;
}
Автор: 1024x768

Оба контейнера ведут себя как обычные блочные элементы: растягиваются во всю ширину вышестоящего блока и располагаются друг под другом. Изменим значение свойства display на inline-flex:

.flex-container {
  display: inline-flex;
  gap: 20px;
  padding: 20px;
  background-color: #ccc;
}
Автор: 1024x768

Теперь контейнеры выстроились в одну линию как и положено блочно-строчным элементам, а также начали обладать их типичной особенностью: если в коде HTML между элементами есть пробел или перенос строки (как раз наш случай), то тогда и пробельный символ отобразится на экране. Исправить это можно задав у вышестоящего блока значение 0 для свойства font-size. Поскольку это свойство унаследуют вложенные элементы, у них значение шрифта обязательно должно быть переопределено.

.example {
  font-size: 0;
}
Автор: 1024x768

Flex-контейнеры игнорируют псевдоэлементы first-letter и first-line

Создадим flex-контейнер с текстом. Попробуем увеличить первую букву, а первую строку сделать жирной.

HTML:

<div class="flex-container">
  Первая буква должна быть большой, а текст в первой строке должен быть жирным.
</div>

CSS:

.flex-container {
  display: flex;
  padding: 22px;
  background-color: #ccc;
  font-size: 30px;
  line-height: 1.5;
}

.flex-container::first-letter {
  font-size: 60px;
}

.flex-container::first-line {
  font-weight: bold;
}
Автор: 1024x768

Видим, что внутри flex-контейнера псевдоэлементы first-letter и first-line не работают. Чтобы это исправить, поместим текст внутри какого-нибудь тега.

HTML:

<div class="flex-container>
  <p>Первая буква должна быть большой, а текст в первой строке должен быть жирным.</p>
</div>

CSS:

.flex-container > p:last-child {
  margin-bottom: 0;
}

.flex-container > p::first-letter {
  font-size: 60px;
}

.flex-container > p::first-line {
  font-weight: bold;
}
Автор: 1024x768
Автор не входит в состав редакции iXBT.com (подробнее »)

3 комментария

Добавить комментарий

Mindkiller
А не проще дать техническое задание какому-нибудь дипсику или квену, вместо того чтобы изучать хитросплетения тысяч свойств ради одного-двух простых сайтов? Или вообще начертить на бумаге макет — а ИИ пусть думает, как его в андроедоустойчивый CSS преобразовать :).
1
А код, который сгенерировала нейросеть, проверять не нужно? А нейросети, которые могут качественно сверстать сложный макет, уже появились?
Mindkiller
Если я, например, вижу, что нейросеть где-то накосячила (не учла узкие андроеды или ещё что) — я ей описываю проблему и она переделывает style.css. Т.е. нейросети в этом плане ничем не отличаются от людей. Надо проверять и при необходимости заставлять дорабатывать. А сложные макеты у тех, кто выкатывает в прод пару простых сайтов за год, случаются нечасто. В любом случае результат будет зависеть от того, насколько качественно было написано техническое задание (или насколько подробно был расчерчен макет). Так-то ещё до бума ИИ существовал в природе софт, который умел с рисунка CSS выдавать, а уж для современных LLM такая задача проста до безобразия.

Добавить комментарий

Сейчас на главной

Новости

Публикации

Новый термальный отель Çelik Thermal & Spa рядом с Памуккале: что входит в 9700 рублей за сутки

Памуккале обычно представляют как белые травертины, голубую воду и толпы туристов. Но всего в нескольких километрах находится Карахайыт, где термальная вода совсем другая: красновато-коричневая...

Сколько нужно будет заплатить за полный комплект гаджетов от Apple в россии

Осень и конец года традиционно становятся временем громких премьер от Apple, но российские ценники на очередные новинки способны перевернуть представления о премиальном сегменте. Крупные ритейлеры,...

FiiO SnowSky FH3 LUMI — драйвовая V-шка — обзор гибридных внутриканальных наушников 1DD+2BA

Компания FiiO в лице своего бренда SnowSky выпустила продолжение своих гибридных наушников FH3, добавив к названию приставку LUMI. Я не знаком с первой версией наушников, но в FH3 LUMI используется...

Фундаментальные константы Вселенной непостоянны: расчеты на суперкомпьютерах оспорили данные коллайдеров

В представлении большинства людей физические константы — это неизменные числа. Считается, что заряд электрона или скорость света зафиксированы самой природой раз и навсегда. Однако...

Что, если у времени два измерения: как новая гипотеза объясняет черные дыры и квантовую механику

В современной теоретической физике существует заметная асимметрия в том, как ученые обращаются с пространством и временем. Когда исследователям не хватает существующих законов для объяснения...

Запечатанные 4000 лет назад письма Месопотамии прочитали без вскрытия: как мобильный томограф заглянул сквозь глину прямо в музее

Четыре тысячи лет назад в торговых городах Ближнего Востока возникла развитая почтовая и юридическая система. Жители Месопотамии и Анатолии писали клинописью на влажных плитках из глины. Когда...