От автора: вы когда-нибудь задумывались о том, как работает свойство CSS flex? Это сокращение от flex-grow, flex-shrink и flex-basis. Наиболее распространенный вариант использования, который я вижу в Интернете — flex: 1. Это возможность flex-элемента расширяться и заполнять все доступное пространство.
В этой статье я подробно рассмотрю сокращенные и полные свойства и объясню, когда и для чего их использовать, с практическими и наглядными примерами.
Свойство flex-grow
flex-grow устанавливает коэффициент растяжения, который позволяет flex-элементам растягиваться и заполнять все доступное пространство. Значение flex-grow принимает только целое число. Обратите внимание на следующее.
1 2 3 4 5 |
<div class="wrapper"> <div class="item item-1"></div> <div class="item item-2"></div> <div class="item item-3"></div> </div> |
1 2 3 4 5 6 7 8 |
.wrapper { display: flex; flex-wrap: wrap; } .item { flex-grow: 1; } |
Примечание: в зависимости от свойства flex-direction flex-grow может влиять на ширину или высоту. В следующих примерах предположим, что для параметра flex-direction установлено значение row (значение по умолчанию), если я не укажу что-то другое.
Обратите внимание, что без использования flex-grow ширина элементов по умолчанию будет равна их начальной ширине. Однако при использовании flex-grow: 1 доступное пространство распределяется между ними.
Вам может быть интересно, как пространство распределяется между flex-элементами? Что ж, это хороший вопрос, и я на него скоро отвечу. На рисунке ниже показано, как элементы выглядят без flex-grow. Другими словами, это их естественный размер.
Чтобы понять, как рассчитывается ширина flex-элемента, см. уравнение ниже. Я узнал об уравнении из этого поста Саманты Минг (Спасибо!). Рассчитаем размер элемента, содержащего текст «CSS».
Ширина элемента = ((flex-grow / total flex-grow) * доступное пространство) + начальная ширина элемента
Flex-grow: коэффициент растяжения для элемента
Total flex-grow: сумма значений flex-grow для всех элементов
Доступное пространство: перед применением flex-grow
Ширина элемента: начальная ширина элемента.
-> Ширина элемента = ((1/3) * 498) + 77 = 241
Несколько факторов flex-grow
В предыдущем примере значение flex-grow одинаково для всех элементов. Попробуем добавить flex-grow: 2 для первого элемента. Как это будет рассчитываться? Имейте в виду, что для нашего примера доступно пространство 498px.
Надеюсь, теперь вам стало понятнее.
Можем ли мы использовать ноль в качестве значения flex-grow?
Конечно! Поскольку свойство flex-grow принимает целочисленные значения, можно использовать 0, как способ предотвратить расширения элемента в доступном пространстве.
Это может быть полезно в крайних случаях, когда мы хотим, чтобы элемент сохранял начальную ширину.
Flex-grow не делает flex-элементы одинаковыми
Существует распространенное заблуждение, что использование flex-grow сделает элементы равными по ширине. Это неверно. Идея использования flex-grow — распределить доступное пространство. Как вы видели в уравнении, ширина каждого гибкого элемента рассчитывается на основе его начальной ширины (ширины до применения flex-grow).
Если вы хотите, чтобы элементы были одинаковыми по ширине, это можно сделать, используя flex-basis. Я объясню это в следующих разделах.
Свойство flex-shrink
flex-shrink устанавливает коэффициент сжатия flex-элемента. Если размер всех flex-элементов больше, чем размер оболочки, элементы будут сжиматься в соответствии с коэффициентом flex-shrink.
Рассмотрим следующий пример. Средний элемент имеет ширину 300px, и установлено flex-shrink: 1. Это позволит элементу уменьшиться в ширину, если нет места для размещения всех flex-элементов.
1 2 3 4 |
.item-2 { width: 300px; flex-shrink: 1; } |
Браузер сохранит ширину элемента равной 300px при следующих условиях:
Сумма ширины всех элементов меньше ширины оболочки
Ширина области просмотра равна или меньше ширины элемента
Вот как элемент ведет себя с разными размерами области просмотра.
Как вы видите на рисунке, ширина будет 300px до тех пор, пока ширина области просмотра не станет меньше 300px.
Свойство flex-basis
Оно устанавливает начальный размер flex-элемента перед распределением свободного пространства в соответствии с коэффициентами. Размер может относиться к ширине по умолчанию и высоте (в случае flex-direction: column).
Свойство flex-basis может принимать то же значение, что и свойства width или height. Значение по умолчанию — auto, которое разрешается в content. Значение content представляет автоматический размер, основанный на размере содержимого элемента.
1 2 3 4 5 |
.item-1 { flex-grow: 0; flex-shrink: 0; flex-basis: 50%; } |
В приведенном выше примере ширина первого элемента составляет 50%. Важно сбросить значение flex-grow на 0, чтобы элемент не стал больше, чем 50%.
Что будет, если использовать вместо этого 100%? Элемент займет 100% ширины своего родителя, а остальные элементы будут перенесены в новую строку.
1 2 3 4 5 |
.item-1 { flex-grow: 0; flex-shrink: 0; flex-basis: 100%; } |
Сокращенное свойство Flex
Это сокращение для flex-grow, flex-shrink и flex-basis. Значение по умолчанию для flex — auto, которое преобразуется во flex: 0 1 auto. Это означает, что оно позволяет гибким элементам увеличиваться в зависимости от размера их содержимого.
В этом контексте есть кое-что важное, что я хотел бы выделить, а именно абсолютные и относительные flex-элементы. Нет, речь идет не о позиционировании CSS, а о том, что связано с flexbox.
Относительный размер flex-элементов
1 2 3 4 |
.item { /* The default value, equivalent to flex: 1 1 auto */ flex: auto; } |
Размер flex-элементов зависит от содержимого. В результате flex-элементы с большим количеством содержимого будут больше.
Абсолютный размер flex-элементов
Напротив, если для свойства flex-basis установлено значение 0, все flex-элементы будут увеличиваться до одинакового размера.
1 2 3 4 |
.item { /* Equivalent to flex: 1 1 0% */ flex: 1; } |
Что мне нравится в свойстве Flex
Судя по названию, это свойство может принимать значения. Возьмем следующие примеры.
Одно значение без единиц измерения
1 2 3 |
.item { flex: 1; } |
Если он имеет только одно значение без единиц измерения, оно будет рассматриваться как flex-grow, а полные значения будут 1 1 0.
Два значения без единиц измерения
1 2 3 |
.item { flex: 1 1; } |
Значения — flex-grow и flex-shrink соответственно. По умолчанию flex-basis будет 0.
Одно значение длины
Оно будет использоваться для flex-basis. По умолчанию flex-grow и flex-shrink будут 1.
1 2 3 4 |
.item { flex: 100px; /* flex: 1 1 100px */ } |
Использование 0 без единиц измерения
В тех случаях, когда вам нужно установить для flex-basis 0, используя сокращение flex.
1 2 3 |
.item { flex: 0; } |
Это не рекомендуется делать, так как это запутает и разработчика, и браузер. Как вы можете понять, относится 0 к факторам растяжения или сжатия, или к flex-basis? Это сбивает с толку. Согласно спецификации CSS:
Ноль без единиц измерения, которому не предшествуют два коэффициента сжатия/растяжения, следует интерпретировать как коэффициент сжатия/растяжения. Чтобы избежать неправильного толкования или недопустимых объявлений, авторы должны указать нулевой компонент <‘flex-base’> с единицей измерения или поставить перед ним два фактора сжатия/растяжения.
Вместо этого вы должны добавить такие единицы, как px или %.
1 2 3 4 |
.item { flex: 0%; /* flex: 1 1 0% */ } |
Рекомендуется использовать сокращение Flex
Когда вам нужно настроить растяжение, сжатие и базу, лучше использовать для этой цели свойство flex. Согласно спецификации CSS:
Авторам рекомендуется контролировать гибкость, используя сокращение flex, а не напрямую через отдельные свойства, так как сокращение правильно сбрасывает любые неуказанные компоненты для соответствия общему использованию.
Случаи использования
Аватар пользователя
Типичный вариант использования flexbox — пользовательский компонент. Аватар и текстовое содержимое должны находиться в одной строке.
1 2 3 4 5 6 7 |
<div class="user"> <img class="user__avatar" src="shadeed.jpg" alt="" /> <div> <h3>Ahmad Shadeed</h3> <p>Author of Debugging CSS</p> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 |
.user { display: flex; flex-wrap: wrap; align-items: center; } .user__avatar { flex: 0 0 70px; width: 70px; height: 70px; } |
Обратите внимание, что я добавил для аватара flex: 0 0 70px. Это важно, так как в некоторых старых браузерах изображение может выглядеть сжатым, если flex не установлено. Добавление этого придает flex более высокий приоритет, чем у свойства width (в случае flex-direction: row) или height (в случае flex-direction: column).
Если мы изменим размер аватара, просто настроив свойство flex, width браузер будет игнорировать.
1 2 3 4 5 6 |
.user__avatar { /* The width is 100px, not 70px */ flex: 0 0 100px; width: 70px; height: 70px; } |
Заголовок раздела
У вас есть заголовок раздела, и он должен занимать все доступное пространство. Использование flex: 1идеально подходит для этого случая.
1 2 3 4 5 6 7 8 |
.page-header { display: flex; flex-wrap: wrap; } .page-header__title { flex: 1; } |
Поле для ввода сообщения
Это очень распространено в приложениях для обмена сообщениями, таких как Facebook* Messenger или Twitter. Входные данные должны заполнять доступное пространство с фиксированной шириной до кнопки отправки.
1 2 3 4 5 6 7 8 9 |
form { display: flex; flex-wrap: wrap; } input { flex: 1; /* Other styles */ } |
Приведенные выше сценарии являются полезными примерами использования flex-grow. Однако некоторые случаи игнорируются или вообще не упоминаются в статьях по flex. Давайте рассмотрим их!
Выравнивание последнего элемента на двух карточках
Предположим, что CSS-сетка имеет макет из двух столбцов. Проблема в том, что здесь даты не совпадают. Они должны быть на одной линии (красной). Мы можем сделать это с помощью flexbox.
1 2 3 4 5 |
<div class="card"> <img src="thumb.jpg" alt=""> <h3 class="card__title">Title short</h3> <time class="card__date"></time> </div> |
Установив flex-direction: column, мы можем использовать flex-grow для заголовка, чтобы он заполнял доступное пространство, и, таким образом, дата оставалась в конце, даже если заголовок короткий.
1 2 3 4 5 6 7 8 9 |
.card { display: flex; flex-direction: column; } /* First solution */ .card__title { flex-grow: 1; } |
Кроме того, это возможно без использования flex-grow. Благодаря авто полям и flexbox!
1 2 3 4 |
/* Second solution */ .card__date { margin-top: auto; } |
Сценарии использования — более одного фактора Flex
Я имею в виду, что здесь используется flex-grow или flex-shrink, но со значением, отличным от 1. В этом разделе я рассмотрю некоторые идеи, где это можно включить.
Действия в футере
Вдохновленный Facebook* (я украл также значки), этот футер состоит из четырех элементов, и последний имеет меньшую ширину. Мы можем сделать следующее:
1 2 3 4 5 6 7 8 9 10 11 12 |
.actions { display: flex; flex-wrap: wrap; } .actions__item { flex: 2; } .actions__item.user { flex: 1; } |
Анимация раскрытия
Мы можем сделать интересную вещь — анимировать элемент при наведении курсора. Это может быть чрезвычайно полезно. Вот простой пример того, что возможно:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.palette { display: flex; flex-wrap: wrap; } .palette__item { flex: 1; transition: flex 0.3s ease-out; } .palette__item:hover { flex: 4; } |
Расширение тарифного плана
Мне нравится эта демонстрация на Codepen. После активации карта расширяется с flex-grow 4.
Когда содержимое больше, чем его оболочка
Некоторое время назад я получил письмо от читателя с вопросом о проблеме, с которой он столкнулся. Как и на рисунке, у нас есть два изображения, которые должны оставаться в границах оболочки.
1 2 3 4 5 6 7 |
.wrapper { display: flex; } .wrapper img { flex: 1; } |
Однако даже при flex: 1 изображения все равно выходят за пределы оболочки. Согласно спецификации CSS:
По умолчанию flex-элементы не сжимаются меньше минимального размера своего содержимого (длины самого длинного слова или элемента фиксированного размера). Чтобы изменить это, установите свойство min-width или min-height.
В нашем случае изображения слишком большие, и flexbox не сжимает их, чтобы поместиться в оболочку. Чтобы изменить это поведение, нам нужно установить следующее:
1 2 3 4 |
.wrapper img { flex: 1; min-width: 0; } |
Заключение
Вот и все. Я объяснил основы свойств flex и, как их использовать. Надеюсь, вы узнали что-то новое из этой статьи. Спасибо за прочтение.
Автор: Ahmad Shadeed
Источник: //ishadeed.com
Редакция: Команда webformyself.
* Признана экстремистской организацией и запрещена в Российской Федерации.