Углубляемся в свойство flex
Перевод статьи: Ahmad Shadeed — Digging Into the Flex Property
Вы когда-нибудь задумывались о том, как работает свойство CSS flex? Это сокращение от flex-grow, flex-shrink и flex-base. Самый распространенный вариант использования, который я замечаю в Интернете, — это flex: 1, который позволяет элементу flex расширяться и заполнять доступное пространство.
В этой статье я подробно рассмотрю это свойство и объясню, когда и почему его можно использовать, с практическими и наглядными примерами.
Свойство Flex-Grow
flex-grow устанавливает коэффициент роста, который позволяет flex элементу увеличиваться и заполнять доступное пространство. Значение flex-grow принимает только целое число. Обратите внимание на следующее.
<div class="wrapper"> <div class="item item-1"></div> <div class="item item-2"></div> <div class="item item-3"></div> </div>
.wrapper { display: flex; flex-wrap: wrap; } .item { flex-grow: 1; }
Примечание: flex-grow может влиять на ширину или высоту, в зависимости от свойства flex-direction. Для следующих примеров предположим, что для параметра flex-direction установлено значение row (значение по умолчанию), если я не уточню что-то еще.
Обратите внимание, что без использования flex-grow ширина элементов flex по умолчанию будет равна их начальной ширине. Однако при использовании flex-grow: 1 доступное пространство распределялось между ними.
Вам может быть интересно, как пространство распределяется между flex элементами? Что ж, это хороший вопрос, и я скоро на него отвечу.
На приведенном ниже рисунке показано, как элементы выглядят без flex-grow. Другими словами, это их естественный размер.
Чтобы понять, как рассчитывается ширина flex элемента, см. уравнение ниже. Я узнал об уравнении из этого поста Саманты Минг (Спасибо!).
Давайте посчитаем размер элемента, содержащего текст «CSS».
Ширина элемента (width) = ( (flex-grow / общее кол-во flex-grow) * доступное пространство) + начальная ширина элементов
Flex-grow: коэффициент увеличения flex для элемента
Total flex-grow: суммирование значения flex-grow для всех flex элементов
Available space: перед применением flex-grow
Item width: начальная ширина элемента
—> Item width = ( (1 / 3) * 498) + 77 = 241
Множественные flex-grow
В предыдущем примере значение flex-grow одинаково для всех flex элементов. Давайте попробуем добавить flex-grow: 2 для первого элемента. Как это будет рассчитываться? Имейте в виду, что доступное пространство для нашего примера составляет 498 пикселей.
Надеюсь, теперь стало понятнее.
Можем ли мы использовать 0 как значение flex-grow
?
Конечно! Поскольку свойство flex-grow принимает целочисленные значения, можно использовать 0 как способ предотвратить использование flex элемента для расширения на доступное пространство.
Это может быть полезно в особых случаях, когда мы хотим, чтобы flex элемент оставался с его начальной шириной.
Flex Grow не делает Flex элементы одинаковыми
Существует распространенное заблуждение, что использование flex-grow сделает элементы равными по ширине. Это неверно. Идея использования flex-grow заключается в распределении доступного пространства. Как вы видели в уравнении, ширина каждого гибкого элемента рассчитывается на основе его начальной ширины (ширина до применения flex-grow).
Если вы хотите, чтобы flex элементы были одинаковой ширины, это можно сделать с помощью flex-basis. Я объясню это в следующих разделах.
Свойство Flex-Shrink
flex-shrink устанавливает коэффициент уменьшения flex элемента. Если размер всех flex элементов больше, чем размер оболочки, элементы будут сжиматься в соответствии с коэффициентом flex-shrink.
Рассмотрим следующий пример. Средний элемент имеет ширину 300 пикселей, а для параметра flex-shrink установлено значение 1. Это позволит элементу уменьшиться по ширине, если нет места для размещения всех flex элементов.
.item-2 { width: 300px; flex-shrink: 1; }
Браузер сохранит ширину элемента равной 300 пикселей при следующих условиях:
- Сумма ширины всех элементов меньше ширины обертки
- Ширина области просмотра равна или меньше ширины элемента
Вот как элемент ведет себя с разными размерами области просмотра.
Как вы видите на рисунке, ширина составляет 300 пикселей, пока ширина области просмотра не станет меньше 300 пикселей.
Свойство Flex-Basis
Это свойство устанавливает начальный размер flex элемента перед распределением свободного пространства в соответствии с flex коэффициентами. Размер может относиться к ширине по умолчанию и высоте (в случае flex-direction: column).
Свойство flex-basis может принимать те же значения, что и свойства width или height. Значение по умолчанию — auto, которое разрешается в content. Значение content — это автоматический размер, основанный на размере содержимого flex элемента.
.item-1 { flex-grow: 0; flex-shrink: 0; flex-basis: 50%; }
В приведенном выше примере ширина первого элемента составляет 50%. Важно установить для параметра flex-grow значение 0, чтобы размер элемента не превышал 50%.
Что будет, если вместо этого использовать 100%? Элемент займет 100% ширины своего родителя, а остальные элементы будут перенесены на новую строку.
.item-1 { flex-grow: 0; flex-shrink: 0; flex-basis: 100%; }
Свойство Flex
Свойство flex это сокращение от flex-grow, flex-shrink и flex-base. Значение по умолчанию для flex — auto, которое разрешается как flex: 0 1 auto. Это означает, что оно позволяет flex элементам увеличиваться в зависимости от размера их содержимого.
В этом контексте есть кое-что важное, что я хотел бы выделить, а именно абсолютные и относительные flex элементы. Нет, речь идет не о позиционировании CSS, а о том, что связано с flexbox.
Относительный размер flex элементов
.item { /* Значение по умолчанию равно: 1 1 auto */ flex: auto; }
В этом случае размер flex элементов будет зависить от содержимого. В результате flex элементы с большим количеством содержимого будут больше.
Абсолютный размер flex элементов
Напротив, когда для свойства flex-based установлено значение 0, все flex элементы будут увеличиваться до одинакового размера.
.item { /* Эквивалентно flex: 1 1 0% */ flex: 1; }
Что мне нравится в свойстве Flex
Судя по названию, это свойство очень гибкое в принимаемых значениях. Рассмотрим следующие примеры.
Одно значение без указания единиц измерения
.item { flex: 1; }
Если у него есть только одно значение, то это значение будет считаться как flex-grow.
Два значения без указания единиц измерения
.item { flex: 1 1; }
Эти значения будут соответствовать flex-grow и flex-shrink соответственно. По умолчанию для flex-basis будет установлено значение 0.
Одно значение с указанием длины
Это будет использоваться для flex-basis. Для параметров flex-grow и flex-shrink по умолчанию будет установлено значение 1.
.item { flex: 100px; /* flex: 1 1 100px */ }
Использование 0 без указания единиц измерения
В случаях, когда вам нужно установить flex-basis в ноль, используя сокращение flex.
.item { flex: 0; }
Такое использование не рекомендуется, так как это запутает и разработчика, и браузер. Как вы можете решить, соответствует ли этот 0 коэффициентам flex (grow или shrink) или flex-basis? Это сбивает с толку. Согласно спецификации CSS:
Ноль без указания единиц измерения, которому не предшествуют два коэффициента flex, следует интерпретировать как коэффициент flex. Чтобы избежать неправильного толкования или недопустимых объявлений, авторы должны указать нулевой компонент <’flex-basis’> с единицей измерения или поставить перед ним два фактора flex.
Рекомендуется добавить единицу измерения, например px или %.
.item { flex: 0%; /* flex: 1 1 0% */ }
Рекомендуется использовать сокращение flex
Когда вам нужно установить grow, shrink и basis, лучше использовать для этой цели свойство flex.
Согласно спецификации CSS:
Авторам рекомендуется контролировать flexibility, используя сокращение flex, а не напрямую его свойства, так как сокращение правильно сбрасывает любые неуказанные компоненты для соответствия общему использованию.
Случаи использования
Аватар пользователя
Типичный вариант использования flexbox — пользовательский компонент. Аватар и текстовое содержимое должны находиться в одной строке.
<div class="user"> <img class="user__avatar" src="shadeed.jpg" alt="" /> <div> <h3>Ahmad Shadeed</h3> <p>Author of Debugging CSS</p> </div> </div>
.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 будет проигнорирована браузером.
.user__avatar { /* width будет 100px, а не 70px */ flex: 0 0 100px; width: 70px; height: 70px; }
Заголовок раздела
У вас есть title для заголовка раздела, и он должен занимать все доступное пространство. В этом случае идеально подходит flex: 1.
.page-header { display: flex; flex-wrap: wrap; } .page-header__title { flex: 1; }
Элемент Input для отправки сообщений
Это очень распространено в приложениях для обмена сообщениями, таких как Facebook Messenger или Twitter. Входные данные должны заполнять доступное пространство с фиксированной шириной для кнопки отправки.
form { display: flex; flex-wrap: wrap; } input { flex: 1; /* Другие стили */ }
Приведенные выше примеры являются полезными примерами использования flex-grow. Однако некоторые случаи игнорируются или вообще не упоминаются в некоторых статьях по flex. Давайте рассмотрим их!
Выравнивание элементов на двух картах
Предположим, что CSS-сетка имеет макет из двух столбцов. Проблема в том, что положение дат не совпадают. Они должны быть на одной линии (красной).
Мы можем сделать это с помощью flexbox.
<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 для заголовка, чтобы он заполнял доступное пространство и, таким образом, размещал дату в конце, даже если заголовок короткий.
.card { display: flex; flex-direction: column; } /* Первое решение */ .card__title { flex-grow: 1; }
Кроме того, это возможно без использования flex-grow. Благодаря auto margins и flexbox! Я написал подробную статью об auto в CSS, если вы хотите вникнуть в подробности.
/* Второе решение */ .card__date { margin-top: auto; }
Сценарии использования — более одного фактора гибкости
Здесь я имею в виду использование flex-grow или flex-shrink, но со значением, отличным от 1. В этом разделе я рассмотрю некоторые идеи использования.
Действия в футоре
Вдохновленный Facebook (я тоже украл значки), этот нижний колонтитул (footer) действий состоит из четырех элементов, а последний имеет меньшую ширину. Мы можем сделать это следующим образом:
.actions { display: flex; flex-wrap: wrap; } .actions__item { flex: 2; } .actions__item.user { flex: 1; }
Расширяющая анимацию
Мы можем сделать интересную вещь — анимировать flex элемент при наведении курсора. Это может быть чрезвычайно полезно. Вот простой пример этого:
.palette { display: flex; flex-wrap: wrap; } .palette__item { flex: 1; transition: flex 0.3s ease-out; } .palette__item:hover { flex: 4; }
Расширение тарифного плана
Мне нравится демонстрация на Codepen. Как только card активирована, она расширяется, изменяя flex-grow на 4.
https://codepen.io/shshaw/pen/EbjvbQ
Когда контент больше, чем его оболочка
Некоторое время назад я получил письмо от читателя с вопросом о проблеме, с которой он столкнулся. Как и на рисунке, у нас есть два изображения, которые должны оставаться в границах своей оболочки.
.wrapper { display: flex; } .wrapper img { flex: 1; }
Однако даже с flex: 1 изображения все равно выходят за пределы оболочки. Согласно спецификации CSS:
По умолчанию flex элементы не сжимаются меньше своего минимального размера содержимого (длины самого длинного слова или элемента фиксированного размера). Чтобы изменить это, установите свойство min-width или min-height.
В нашем случае изображения слишком большие, и flexbox не сжимает их, чтобы поместиться в оболочку. Чтобы изменить это поведение, нам нужно установить следующее:
.wrapper img { flex: 1; min-width: 0; }
Я объяснил эту проблему в своей статье о минимальной и максимальной width / height в CSS.
Заключение
Вот и все. Я объяснил основы свойств flex и объяснил, как их использовать. Надеюсь, вы узнали что-то новое из этой статьи. У вас есть комментарий или предложение? Пожалуйста, напишите мне на @shadeed9.
Спасибо за чтение.
Я пишу электронную книгу
Рад сообщить вам, что я пишу электронную книгу об Debugging CSS.
Если вам интересно, перейдите на debuggingcss.com и подпишитесь на обновления о книге.
Ресурсы и дополнительная информация
- Grid for layout, Flexbox for components
- Learn Box Alignment
- A closer look at Absolute and Relative flex-items.
flex-grow
is weird. Or is it?- CSS Flexbox: 5 Real World Use Cases
- Solved by Flexbox
очень разжовано и понятно
супер