10 особенностей CSS Flexible Box Layout, о которых полезно знать веб-разработчику
CSS Flexible Box Layout — это модуль для выравнивания элементов и распределения пространства между ними. В сети полно кратких шпаргалок, помогающих понять, как управлять элементами внутри flex-контейнера. Однако технология полна нюансов, знание которых сэкономит вам время при работе с реальными проектами.
Содержание
- Тайный способ выравнивания элементов: используем margin со значением auto
- Когда контент ломает сетку: секрет min-width
- Кто главнее: flex-basis или width?
- Особенности работы со слоями
- Особенности абсолютного позиционирования
- Схлопывание внешних отступов отменяется
- Чем отличаются align-content, align-items и align-self
- Структурные псевдоклассы против свойства order
- Разница между flex и inline-flex
- Flex-контейнеры игнорируют псевдоэлементы first-letter и first-line
Тайный способ выравнивания элементов: используем 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;
}
У 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;
}
Видим, что область с контентом «уехала» за пределы flex-контейнера, а переносы не сработали. Почему так произошло? Дело в том, что согласно спецификации, flex-элементы получили по умолчанию значение auto для свойства min-width. И, в отличие от обычных блоков, они ведут себя иначе: минимальный размер элемента по главной оси определяется размером его содержимого. Обнулим значение свойства min-width и элемент перестанет выходить за пределы flex-контейнера.
.content {
flex: 1;
min-width: 0;
padding: 20px;
background-color: #eee;
}
Кто главнее: flex-basis или width?
В предыдущем примере мы определили ширину левой колонки с помощью свойства width. А что будет, если задать также значение для свойства flex-basis?
.sidebar {
flex-shrink: 0;
flex-basis: 360px;
width: 160px;
background-color: #9bce90;
}
Как видим, значение flex-basis перебило значение with и ширина колонки стала равной 360 пикселям. А что будет, если определить еще и свойство max-width?
.sidebar {
flex-shrink: 0;
flex-basis: 360px;
width: 160px;
max-width: 100px;
background-color: #9bce90;
}
Max-width победил всех и ширина колонки стала равной 100 пикселям. И, конечно же, стоит сказать о том, что flex-basis всегда работает вдоль главной оси flex-контейнера. Чтобы в этом убедиться, изменим у flex-контейнера значение свойства flex-direction:
.page {
display: flex;
flex-direction: column;
padding: 20px;
background-color: #ccc;
}
Особенности работы со слоями
Свойство 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-контейнера и если вам нужно выстроить слои у вложенных в него элементов, то придется задать значение 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;
}
Теперь добавим для последнего элемента свойство position со значением absolute и, для наглядности, изменим у него цвет фона:
.element:last-child {
position: absolute;
background-color: #843b3e;
}
Видим, что элемент выпал из общего потока, но, вместо того чтобы переместиться в левый верхний угол flex-контейнера, для которого задано свойство position со значением relative, он расположился по центру. Это произошло из-за того, что на элемент по-прежнему влияют значения свойств justify-content и align-items, определяя его начальное положение. Однако, если ему задать координаты с помощью любого из свойств left, right, top или bottom, но он переместится так, как это сделал бы обычный элемент с абсолютным позиционированием.
.element:last-child {
position: absolute;
right: 20px;
top: 20px;
background-color: #843b3d;
}
Схлопывание внешних отступов отменяется
Внутри 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;
}
Отступы не схлопнулись, как это бывает у обычных блочных элементов, а наоборот сложились и суммарное расстояние между блоками составило 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;
}
Оба ряда были отцентрированы по вертикали как единое целое. Теперь заменим свойство align-content на align-items:
.flex-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
padding: 20px;
background-color: #ccc;
height: 500px;
align-items: center;
}
Flex-контейнер как бы разделился на две половины и элементы каждой выстроились своими центрами вдоль осей. И теперь пропишем одному из элементов значение flex-start для свойства align-self:
.element:nth-child(3) {
align-self: flex-start;
background-color: #33548c;
}
Элемент получил собственное выравнивание и сместился к верхнему краю 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;
}
Теперь определим значения свойства order для второго и четвертого элементов:
.element:nth-child(2) {
order: 1;
}
.element:nth-child(4) {
order: 2;
}
Цвета элементов остались привязаны к своей структуре в 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;
}
Оба контейнера ведут себя как обычные блочные элементы: растягиваются во всю ширину вышестоящего блока и располагаются друг под другом. Изменим значение свойства display на inline-flex:
.flex-container {
display: inline-flex;
gap: 20px;
padding: 20px;
background-color: #ccc;
}
Теперь контейнеры выстроились в одну линию как и положено блочно-строчным элементам, а также начали обладать их типичной особенностью: если в коде HTML между элементами есть пробел или перенос строки (как раз наш случай), то тогда и пробельный символ отобразится на экране. Исправить это можно задав у вышестоящего блока значение 0 для свойства font-size. Поскольку это свойство унаследуют вложенные элементы, у них значение шрифта обязательно должно быть переопределено.
.example {
font-size: 0;
}
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;
}
Видим, что внутри 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;
}





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