Полный гайд по CSS Flexbox с примерами из практики
Привет! Это первая статья по HTML&CSS из серии. И начать я решил именно с Flexbox. В интернете уже довольно много гайдов по Flexbox в CSS. Но чаще всего это шпаргалки, которые не сильно помогают разобраться как на самом деле все работает. Я постараюсь раскрыть тему на реальных примерах. А в конце статьи поделюсь лайфхаками, которыми сам постоянно пользуюсь в работе.
Если вам больше нравится воспринимать информацию в видео-формате, то можете посмотреть ролик на YouTube:
Что такое Flexbox и зачем он
Flexbox в CSS — это специальный инструмент, который помогает управлять расположением элементов на веб-странице.
Flexbox особенно полезен для создания гибких и адаптивных макетов, так как конфигурацию flex-сетки легко менять относительно разных размеров устройств.
Песочница
Дальше в статье я буду рассказывать про все свойства на примере блока с несколькими элементами.
Div с классом container
– это элемент с белой обводкой из примера. Он будет выступать в роли flex-контейнера. А внутри этого блока будут лежать сами элементы с классом item
. Изначально наш пример без специальных flex-стилей выглядит следующим образом.
<div class="container">
<div class="item item-1">item 1</div>
<div class="item item-2">item 2</div>
<div class="item item-3">item 3</div>
</div>
Пример будет доступен в песочнице на Codepen. Вы можете параллельно сами повторять все действия из статьи, так информация будет усваиваться еще лучше.
display: flex
Значение flex
для контейнера задается через свойство display
. По-умолчанию это свойство имеет значение display: block
.
Мы прописываем значение display: flex
. И тогда наш блок превращается во flex-контейнер.
.container {
display: flex;
}
Мы сразу же замечаем как значения выстроились в ряд.
flex-direction
Вообще flex-контейнер может выстраивать значения как по горизонтали, так и по вертикали. По-умолчанию, как видите из предыдущего примера, главной осью является горизонтальная ось. Но мы можем поменять направление с помощью свойства flex-direction
.
Если написать значение column
у flex-direction
, то направление элементов поменяется.
.container {
display: flex;
flex-direction: column;
}
У flex-direction
также доступны и реверсивные свойства. Например, row-reverse
отображает значения по горизонтали в обратном порядке.
.container {
display: flex;
flex-direction: row-reverse;
}
А column-reverse
выставляет значения в обратном порядке по вертикали.
.container {
display: flex;
flex-direction: column-reverse;
}
flex-wrap
Если добавить больше элементов в пример, то мы увидим что они ужимаются в 1 ряд и не переходят на новую строку.
<div class="container">
<div class="item item-1">item 1</div>
<div class="item item-2">item 2</div>
<div class="item item-3">item 3</div>
<div class="item item-4">item 4</div>
<div class="item item-5">item 5</div>
<div class="item item-6">item 6</div>
<div class="item item-7">item 7</div>
<div class="item item-8">item 8</div>
<div class="item item-9">item 9</div>
</div>
За перенос элементов на новую строку отвечает свойство flex-wrap
. Если мы укажем flex-wrap: wrap
, то элементы перенесутся на новую строку.
.container {
display: flex;
flex-wrap: wrap; /* default - flex-wrap: no-wrap */
}
Если указать значение wrap-reverse
, то элементы начнут выстраиваться начиная с нижней линии и дальше перейдут уже сверху на новую строку.
.container {
display: flex;
flex-wrap: wrap-reverse;
}
justify-content
Свойство justify-content
позволяет управлять расстоянием между элементами по главной оси.
Если задать свойству значение flex-end
, то все элементы прижмутся к правому краю.
.container {
display: flex;
justify-content: flex-end;
}
Если поменяем на flex-start
, то увидим как элементы прижмутся к левому краю. И это, кстати, значение по-умолчанию.
.container {
display: flex;
justify-content: flex-start; /* default */
}
Рассмотрим остальные возможные значения ниже.
Значение center
сжимает все элементы в центр.
.container {
display: flex;
justify-content: center;
}
Значение space-beetwen
выставляет одинаковое расстояние между элементами, но прижимает их по краям.
.container {
display: flex;
justify-content: space-between;
}
Значение space-around
выставляет одинаковое расстояния вокруг каждого элемента. Создается эффект двойного отступа между элементами, потому что плюсуются отступы от каждого элемента.
.container {
display: flex;
justify-content: space-around;
}
Значение space-evenly
создает расстояние одинаково по краям и между элементами.
.container {
display: flex;
justify-content: space-evenly;
}
align-items
Следующее важное свойство для flex-контейнера – это свойство align-items
. Оно задает правила как выравнивать элементы по вертикали, то есть по дополнительной оси.
Но чтобы посмотреть как оно работает, нам нужно сделать элементы разной высоты. Для этого добавим разное количество строк в каждом item.
<div class="item item-1">
item 1
<div>text</div>
<div>text</div>
</div>
<div class="item item-2">
item 2
<div>text</div>
</div>
<div class="item item-3">
item 3
</div>
Изначально мы видим, что все значения растянулись на одинаковую высоту. Это происходит потому что align-items
имеет значение stretch
по-умолчанию.
Дальше рассмотрим другие доступные свойства.
Значение flex-start
прижимает все элементы кверху.
.container {
display: flex;
align-items: flex-start;
}
Если написать значение flex-end
, то все элементы прижмутся книзу.
.container {
display: flex;
align-items: flex-end;
}
Значение center
выровняет все элементы по центру.
.container {
display: flex;
align-items: center;
}
Значение baseline
на первый взгляд похож на flex-start
.
.container {
display: flex;
align-items: baseline;
}
Но, если мы поставим разный размер шрифта во всех элементах, то увидим, что элементы немного съезжают.
.item-1 {
font-size: 32px;
}
.item-2 {
font-size: 64px;
}
.item-3 {
font-size: 16px;
}
Значение baseline
выравнивает элементы по нижней границе первой линии шрифта, так называемой baseline. Обратите внимание на желтую линию на скриншоте.
gap
Последнее свойство для flex-контейнера – это свойство gap
. Оно выставляет расстояние между элементами. Добавим больше элементов в пример и передадим в свойство gap
значение 16px
.
.container {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
Мы видим, что между элементами добавились отступы в 16 пикселей.
Но мы можем выставлять разные отступы по горизонтали и по вертикали – для этого нужно передать 2 значения подряд. Попробуем передать 16px
и 32px
. И увидим, что первое свойство установит отступы по вертикали, а второе свойство выставит отступы по горизонтали.
.container {
display: flex;
flex-wrap: wrap;
gap: 16px 32px;
}
Пока это все что нужно знать про flex-контейнер, мы изучили все его свойства. Дальше рассмотрим свойства для самих элементов, которые лежат внутри flex-контейнера.
order
И можем начать со свойства order
. Это свойство задает порядок отображения конкретного элемента. По умолчанию у всех элементов стоит order: 0
и тогда элементы просто отображаются в таком порядке, в котором они объявлены в HTML.
Попробуем поменять значение order
на 1 у второго элемента .
.item-2 {
order: 1;
}
Видим сразу же что второй элемент отправился в самый конец. Потому что у первого элемента значение order: 0
, у третьего элемента значение order: 0
, а у второго элемента значение order: 1
и он соответственно уходит в самый конец.
Теперь попробуем поменять order
у всех элементов.
.item-1 {
order: 5;
}
.item-2 {
order: 3;
}
.item-3 {
order: 1;
}
Кстати, order
не обязательно должен идти подряд 1 к одному. Мы можем указывать любые значения, а CSS просто сравнивает какое больше, а какое меньше.
align-self
Свойство align-self
похоже на align-items
у контейнера, но только оно теперь задается дочернему элементу и отвечает только за его выравнивание.
Для наглядности сделаем разную высоту для элементов и выставим align-items: center
у контейнера. После этого первому элементу в свойстве align-self
укажем значение flex-start
.
.container {
display: flex;
align-items: center;
}
.item-2 {
align-self: flex-start;
}
Второй элемент стал выравниваться по верхней границе, хотя остальные значения выравниваются по-центру.
Если поменяем значение на flex-end
, то элемент перескочит вниз.
.item-2 {
align-self: flex-end;
}
И так можно менять каждый элемент по-отдельности. Для свойства align-self
доступны такие же значения, как и для свойства align-items
у flex-контейнера – flex-start
, flex-end
, center
, baseline
, stretch
.
Дальше мы переходим к серии самых сложных свойств. Именно с ними чаще всего возникают проблемы у новичков.
flex-grow
И начнем мы со свойства flex-grow
. Это свойство позволяет указать коэффициент увеличения элемента относительно свободного пространства внутри flex-контейнера. Свободное пространство – это оставшееся незаполненное место внутри flex-контейнера, которое подсвечено желтым цветом ниже.
Обратите внимание, что значение flex-grow
– это не соотношение элементов друг к другу.
По-умолчанию flex-grow
имеет значение 0. Именно поэтому изначально элементы никак не делят пространство между собой. Если укажем 1, то все элементы становятся одинаковыми, потому что они равномерно разделили между собой это свободное место.
.item {
flex-grow: 1;
}
Теперь попробуем перезаписать значение flex-grow
самого первого элемента на 0, и увидим, что он снова уменьшился.
.item {
flex-grow: 1;
}
.item-1 {
flex-grow: 0;
}
Здесь желтым подсвечена зона потенциального свободного пространства, если бы у всех элементов стоял flex-grow: 0
. Значение 0 означает, что первый элемент никак не участвует в дележке свободного пространства. А остальные 2 элемента делят пространство между собой, как видно по нижней шкале на скриншоте выше.
Теперь попробуем прописать разное значение flex-grow
для всех элементов.
.item-1 {
flex-grow: 1;
}
.item-2 {
flex-grow: 2;
}
.item-3 {
flex-grow: 3;
}
Хочу еще раз обратить внимание, что эти свойства не означают, что второй элемент будет в 2 раза больше первого, а третий элемент в 3 раза больше первого. Все элементы именно разделят свободное пространство между собой в равных пропорциях.
Условно говоря, первому элементу достанется 1 доля от желтого блока, второму элементу достанется 2 доли, а третьему элементу достанется 3 доли.
Кстати, это свойство перестанет работать, если контент и так не будет помещаться на экран. Например, добавим еще элементов и попробуем указать для .item-1
значение flex-grow
больше 0.
.item-1 {
flex-grow: 2;
}
Ничего не меняется. Это происходит потому что нет свободного места и делить соответственно нечего.
Значения отличные от 0 и 1 редко используются на практике. Поэтому важнее всего отработать как между собой взаимодействуют именно 0 и 1.
flex-basis
Следующее свойство – это свойство flex-basis
. Это прям супер важное свойство и очень часто используется на практике.
Свойство flex-basis
указывает, какую ширину займет элемент по-умолчанию. Может показаться, что flex-basis
является заменой width
, но на самом деле это не так. Свойство flex-basis
устанавливает лишь оптимальную ширину, то есть если мы передадим flex-basis: 200px
, то вообще не факт что элемент будет шириной в 200px
– он может быть как больше, так и меньше. Давайте разбираться почему так происходит.
Для начала укажем для всех элементов flex-basis 200px
:
.item {
flex-basis: 200px;
Можем убедиться, что она действительно стала 200px. Давайте попробуем подставить другие значения. Например, укажем 50px.
.item {
flex-basis: 50px;
}
Теперь видим, что элементы на самом деле занимают бОльшую ширину, а точнее 86px. Так происходит, потому что они сжались до максимально маленькой ширины, дальше слово item
просто не помещается в контейнер.
Похожая история будет происходить если указать слишком большое значение. Например, попробуем во flex-basis
передать 300px
.
.item {
flex-basis: 300px;
}
И теперь видим, что элементы наоборот занимают меньшую ширину – 262px вместо 300px. Иначе они бы просто не поместились в контейнер.
Очень часто на практике для flex-basis
используют проценты. Например напишем 25%:
.item {
flex-basis: 25%;
}
Видим, что все элементы заняли 1/4 часть. Таким образом создается сетка на сайтах. Пример такой сетки будет показан в конце статьи.
flex-shrink
flex-shrink
помогает распределить пространство, если места в контейнере недостаточно. Создадим ситуацию, когда места недостаточно. Попробуем указать большой flex-basis
для элементов, так чтобы они не помещались. Также мы добавим фиксированную ширину в 600px
для flex-контейнера.
.container {
display: flex;
width: 600px;
}
.item {
flex-basis: 300px;
}
По факту элементы приняли ширину 200px
, а не 300px
, как видно на скриншоте. Хотя в идеале все три элемента должны занимать ширину 900px
, если бы контейнер был побольше.
Если мы укажем flex-shrink: 0, то как раз и увидим ширину содержимого 900px
. Элементы просто вылезут за пределы контейнера.
.item {
flex-basis: 300px;
flex-shrink: 0;
}
Это происходит, потому что flex-shink: 0
запрещает элементам сжиматься. И они строго занимают оптимальную ширину, которую мы указали во flex-basis
. Если мы поменяем значение на 1
, то вернемся в исходное состояние. 1
- это значение по-умолчанию свойства flex-shrink
.
Теперь попробуем дать разный flex-shrink
для всех элементов и посмотрим что из этого получтися.
.item {
flex-basis: 300px;
}
.item-1 {
flex-shrink: 1;
}
.item-2 {
flex-shrink: 2;
}
.item-3 {
flex-shrink: 3;
}
Обратите внимание на реальную ширину элементов. У первого элемента ширина 150px
, у второго 200px
, а у третьего 250px
. Почему так получилось?
Наш контейнер условно переполнялся на 300px
, если бы везде была оптимальная ширина из flex-basis
. В результате эти 300px
отбавились у всех элементов пропорционально коэффициенту flex-shrink
. Первый стал меньше на 150px
, второй элемент стал меньше на 100px
, а третий элемент стал меньше на 50px
.
Сокращенная запись
Для этих трех свойств (flex-grow,
flex-shrink
и flex-basis
) существует более короткая запись. Мы можем написать следующим образом:
.item {
flex: 1 1 200px;
}
Первое значение отвечает за flex-grow
, второе за flex-shrink
, а третье за flex-basis
. Вы можете писать как удобнее, оба варианта поравильные – и полный и сокращенный.
Лайфхаки
Мы разобрали все flex свойства, как у контейнера так и дочерних элементов. А теперь я вам покажу несколько примеров из реальной практики. Это мои лайфхаки, которыми я сам постоянно пользуюсь на работе.
На моем видео в YouTube эти примеры разбираются подробнее. А здесь вы можете посмотреть на код и попробовать поэкспериментировать.
Центрирование элемента
Первый лайфхак – это центрирование единственного элемента во flex-контейнере. Очень простой хак, который также пригодится вам на собеседованиях, когда будут спрашивать про способы центрирования.
Сетка
Следующий пример чуть посложнее. Но у меня нет ни одного проекта, где бы я не написал такую сетку для себя.
Растягивание на доступное пространство
И последний пример, который я очень часто использую в работе – это компонент с фиксированной частью. Эта фиксированная часть должна занимать столько места, сколько контента в ней содержится. В данном случае это кнопка “Отправить”. Как видим она всегда одной ширины. А вторая часть компонента должна растягиваться во все доступное пространство.
Итог
Мы с вами научились пользоваться флексами на полную катушку. Также я показал вам несколько полезных примеров, которые можно смело использовать в работе. Все примеры из статьи доступны по ссылке в github.
Подписывайтесь на телеграм‑канал Вайтишная — выкладываю там полезные материалы и пишу честно про IT