Рассмотрим основы нового механизма «гибкой» раскладки — флексбокс. Сначала потренируемся «на котиках» направлять оси флекс-контейнера, выравнивать и переносить флекс-элементы, а затем научимся простому применению флексбокса в реальных интерфейсах.
Флексбокс — это первый CSS-механизм, предназначенный для построения сеток и создания сложных раскладок блоков.
Другие механизмы, с помощью которых мы раньше строили сетки, задумывались совсем не для этого: плавающие блоки нужны для создания блоков, которые обтекает текст, а таблицы используются для разметки табличных данных.
Флексбокс задумывался для создания «гибких» раскладок и хранит много тонкостей и чудес, о которых мы поговорим в этой серии курсов. А пока начнём с простого. Как включить флексбокс?
Очень просто: нужно задать элементу свойство display: flex;
. После этого происходит два события:
display: flex;
превращается во «флекс-контейнер» и внутри него начинает происходить вся магия гибкой раскладки.Первое, что вы заметите после выполнения этого задания, это то, что блоки растянутся на всю высоту контейнера. Да, внутри флексбокса можно делать элементы одинаковой высоты!
Поэкспериментируем!
.room
задайте свойство display
со значением flex
.Вспомните, как ведёт себя обычный поток документа. Блоки и текст располагаются слева направо и сверху вниз.
В привычной блочной модели направления «лево», «право», «верх» и «низ» неизменны. Но внутри флекс-контейнера эти понятия могут изменяться, потому что там можно изменять обычное направление потока.
Вместо направлений «лево» и «право» во флексбоксе используется понятие «главная ось». Поток флекс-элементов «течёт» вдоль главной оси от её начала к её концу.
По умолчанию главная ось направлена слева направо, но её можно разворачивать во всех направлениях с помощью свойства flex-direction
, которое задаётся для флекс-контейнера. Значения свойства:
row
— значение по умолчанию, главная ось направлена слево направо.
column
— главная ось направлена сверху вниз.
row-reverse
— главная ось направлена справа налево.
column-reverse
— главная ось направлена снизу вверх.
Флекс-элементы всегда располагаются вдоль главной оси, независимо от её направления.
Для блока .room
задайте направление главной оси:
Вместо направлений «верх» и «низ» во флексбоксе используется понятие «поперечная ось». Вдоль этой оси рассчитывается высота элементов и работают «вертикальные» выравнивания.
Поперечная ось всегда перпендикулярна главной оси и поворачивается вместе с ней:
Это не совсем логичное поведение, к которому надо привыкнуть. Получается, что поперечная ось никогда не смотрит вверх или влево. А свойства для поворота поперечной оси нет.
Давайте посмотрим на поведение поперечной оси вживую.
Для блока .room
задайте ещё раз направление главной оси:
Обращайте внимание на направление поперечной оси.
Вместо «горизонтального» выравнивания во флексбоксе используется свойство для распределения элементов вдоль главной оси — justify-content
. Это свойство задаётся для флекс-контейнера.
Его значением по умолчанию является flex-start
. При этом значении элементы располагаются у начала главной оси.
Чтобы элементы располагались по центру главной оси, нужно задать для justify-content
значение center
.
Давайте разместим коврики по центру комнаты.
.room
.
Чтобы флекс-элементы располагались в начале главной оси, свойству justify-content
нужно задать значение flex-start
. Оно же является и значением по умолчанию.
А значение flex-end
расположит элементы в конце главной оси.
Обратите внимание, что justify-content: flex-end
не меняет порядок элементов, как это происходит при изменении направления оси flex-direction: row-reverse
. Элементы просто прижимаются к концу главной оси.
Давайте опробуем эти значения justify-content
и разместим коврики в начале и в конце комнаты.
.room-2
разверните главную ось справа налево.Помните ли вы режим горизонтального выравнивания «по ширине», когда текст распределялся в блоке равномерно, а края текста прижимались к краям блока? Совсем как в этом абзаце.
У флексбокса есть чем-то похожие значения justify-content
, которые равномерно распределяют флекс-элементы вдоль главной оси:
space-between
— расстояния между соседними элементами одинаковые, между элементами и краями флекс-контейнера отступов нет.
space-around
— расстояния между соседними элементами одинаковые, между элементами и краями флекс-контейнера есть отступ, равный половине расстояния между соседними элементами.
Сейчас мы добавим третьего кота и поэкспериментируем с этими значениями justify-content
.
А пока небольшой итог. Свойство justify-content
управляет распределением элементов вдоль главной оси и имеет пять значений:
значение по умолчанию flex-start
,
flex-end
,
center
,
space-between
,
space-around
.
.room
добавьте кота Семёна: блок с классами rug
и simeon
..room-1
задайте равномерное распределение вдоль главной оси без отступов по краям,.room-2
— равномерное распределение с половинными отступами по краям.Вместо «вертикального» выравнивания во флексбоксе используется свойство для выравнивания элементов вдоль поперечной оси — align-items
. Это свойство задаётся для флекс-контейнера.
Его значением по умолчанию является stretch
. Именно благодаря этому значению флекс-элементы и растягиваются на всю «высоту» флекс-контейнера. Если флекс-элементам задана высота, то растягиваться они не будут.
Чтобы элементы выровнялись по центру поперечной оси, нужно задать для align-items
значение center
.
Давайте выровняем коврики по центру комнаты вдоль поперечной оси и убедимся, что элементы действительно центруются, даже если у них разная высота.
.rug
задайте высоту 150px
,.room
задайте выравнивание флекс-элементов по центру поперечной оси,.keks
задайте высоту 250px
.Чтобы расположить флекс-элементы в начале или в конце поперечной оси, нужно использовать значения flex-start
и flex-end
для свойства align-items
.
Эти значения аналогичны значениям свойства justify-content
, отличается только ось.
Проверим эти значения и разместим коврики сверху и снизу комнаты.
Для блока .room
задайте выравнивание флекс-элементов:
Ещё одно значение свойства align-items
— это baseline
. Если задать его контейнеру, то флекс-элементы будут выравниваться по базовой линии текста в них. Эта воображаемая линия проходит по нижней части букв.
Если выровнять флекс-элементы по базовой линии, то они выстроятся так, чтобы текст в них был как бы на «одной строке».
Чтобы лучше понять поведение baseline
, сравним его с другим значением — flex-start
.
Мини-итог. Свойство align-items
управляет выравниванием элементов вдоль поперечной оси и имеет пять значений:
значение по умолчанию stretch
,
flex-start
,
flex-end
,
center
,
baseline
.
.room-1
задайте выравнивание флекс-элементов в начале поперечной оси,.room-2
выравнивание по базовой линии текста.Распределение элементов по главной оси задаётся для всего флекс-контейнера и на все флекс-элементы действует одинаково. Задать какому-то элементу отличное от других распределение по главной оси нельзя. И это вполне логично, ведь тогда элементы будут «сталкиваться» друг с другом.
C поперечной осью всё проще. Можно сказать, что у каждого элемента она своя, и можно задавать им разное поперечное выравнивание. Для этого используется свойство align-self
, которое задаётся для самих флекс-элементов, а не для флекс-контейнера.
У свойства align-self
те же самые значения, что и у align-items
.
.rudolf
задайте выравнивание в начале поперечной оси,.keks
— в конце поперечной оси,.simeon
— по центру оси center
.Аналогично align-items
для отдельного флекс-элемента можно задать и выравнивание по базовой линии с помощью align-self
со значением baseline
.
Давайте зададим выравнивание по базовой линии двум отдельным блокам.
Задайте выравнивание флекс-элементов по базовой линии текста:
.text-simeon
,.text-keks
.Что будет, если флекс-элементов в контейнере станет больше, чем может уместиться в один ряд?
Это чем-то похоже на поведение ячеек в таблице.
Такое поведение можно изменить свойством флекс-контейнера flex-wrap
. По умолчанию оно имеет значение nowrap
, то есть перенос флекс-элементов на новую строку запрещён.
Значение wrap
разрешает перенос флекс-элементов на новую строку, если они не помещаются в контейнер.
Давайте посмотрим на практике, как оно работает.
.rug
задайте ширину 120px
,.room
последним добавьте кота Массимо: блок с классами rug
и massimo
,.room
задайте перенос флекс-элементов на новую строку.Если перенос флекс-элементов разрешён, то ряды элементов располагаются вдоль поперечной оси. Первый ряд располагается в начале поперечной оси, а последний в конце. Но так работает только значение wrap
.
Если для flex-wrap
задать значение wrap-reverse
, то элементы будут переноситься, а ряды будут располагаться в обратном порядке: первый в конце поперечной оси, а последний в начале.
Давайте добавим в комнату ещё котиков и попробуем переносить их на новую строку в обратном поперечной оси направлению.
rug
и marty
и Черныша — блок с классами rug
и blacky
,.room
задайте перенос флекс-элементов на новую строку в обратном направлении wrap-reverse
,180px
.Вспомним свойство justify-content
, которое управляет распределением флекс-элементов вдоль главной оси.
Есть очень похожее свойство align-content
, которое управляет выравниванием рядов флекс-элементов вдоль поперечной оси. У этих свойств почти одинаковые значения:
flex-start
,
flex-end
,
center
,
space-between
,
space-around
,
и stretch
, которое есть только у align-content
и является значением по умолчанию.
Свойство align-content
связано и со свойством align-items
, которое управляет выравниванием флекс-элементов вдоль поперечной оси.
В чём разница между align-content
и align-items
, когда работает одно, а когда работает другое? Вот ответы:
Если есть только один ряд флекс-элементов, то работает align-items
.
Если есть несколько рядов, то работает align-content
.
Подчеркнём, что align-content
влияет на ряды, а не на отдельные элементы.
В последней версии спецификации это поведение изменилось: теперь правильно, когда align-content
выравнивает элементы в многострочном флекс-контейнере, даже если строка в контейнере единственная. Это изменение на момент окончания 2015 года применено только в браузерах Safari и Edge.
.room-1
задайте align-items
в начале поперечной оси,.room-2
— align-items
в конце поперечной оси..rug
до 120px
, чтобы в блоках стало два ряда элементов.Смотрите, как выравнивание рядов переопределило выравнивание элементов.
Ранее мы говорили, что как только во флекс-контейнере появляется несколько рядов элементов, вместо align-items
начинает действовать свойство align-content
.
В этом случае align-items
не отключается полностью, а может влиять на отображение флекс-элементов в рядах.
Это происходит, когда мы используем для align-content
значение по умолчанию — stretch
. Оно растягивает ряды флекс-элементов, при этом оставшееся свободное место между ними делится поровну.
Отображение строк при align-content: stretch
зависит от значения align-items
:
align-items
задано значение stretch
, то элементы в строках растягиваются на всю высоту своей строки.stretch
, то элементы в строках ужимаются под своё содержимое и выравниваются в строках в зависимости от значения align-items
.Давайте посмотрим на этот эффект вживую.
.rug
внутри .room-2
ширину 120px
, чтобы там появилось два ряда.align-items
в начале оси,Значение align-items
влияет на отображение рядов во флекс-контейнере, если у align-content
задано значение stretch
. В этом мы убедились в прошлом задании.
Есть ли похожее влияние на остальные значения align-content
? Нет.
Убедимся в этом на примере значения center
, которое располагает ряды в середине поперечной оси так, что:
Давайте поэкспериментируем.
.room-2
задайте выравнивание рядов по центру оси.align-items
в начале оси,Остальные четыре значения свойства align-content
аналогичны значениям свойства justify-content
, отличается только ось:
flex-start
располагает ряды в начале поперечной оси.
flex-end
располагает ряды в конце поперечной оси.
space-between
равномерно распределяет ряды вдоль поперечной оси, расстояния между соседними рядами одинаковые, отступов у краёв нет.
space-around
равномерно распределяет ряды вдоль поперечной оси, расстояния между соседними рядами одинаковые, отступы у краёв равны половине расстояния между соседними рядами.
Напоследок небольшое резюме.
Свойство align-content
— «гибридное». Мы переводим его как «выравнивание», но оно больше похоже на «распределение», justify-content
, от которого оно позаимствовало два значения space-between
и space-around
.
Близость с «распределением» подчёркивает и отсутствие значения baseline
— всё-таки свойство работает с рядами, а не с отдельными элементами.
От «выравниваний» же, align-items
и align-self
, это свойство получило значение по умолчанию stretch
и возможность «растягивать» ряды по высоте.
.room
задайте выравнивание строк в начале оси,И ещё одно свойство, которое мы рассмотрим в этом курсе, — это order
, порядковый номер флекс-элемента.
Это очень полезное свойство, так как с его помощью можно менять порядок следования флекс-элементов в потоке, не меняя HTML-код.
По умолчанию порядковый номер флекс-элементов равен 0
, а сортировка элементов производится по возрастанию номера.
Порядковый номер задаётся целым числом, положительным или отрицательным. Например:
.flex-element { order: -1; /* этот элемент станет отображаться первым в контейнере */ }
Давайте попробуем перетасовать коврики с котиками с помощью свойства order
.
.keks
задайте порядковый номер -1
,.simeon
— порядковый номер -2
,.rudolf
— номер 1
.В следующих заданиях мы разберём примеры из жизни, в которых можно применять флексбокс.
Самый насущный вопрос, который можно легко и изящно решить с помощью флексбокса, — как отцентровать элемент по вертикали и горизонтали так, чтобы центровка сохранялась при изменении размеров элемента или контейнера.
Ответ прост: задать контейнеру раскладку флексбокса, а дочернему флекс-элементу margin: auto
.
В этом случае флекс-элемент уменьшит свой размер под содержимое и отцентруется по вертикали и горизонтали.
Стоит обратить внимание на интересный момент. Если центруемых флекс-элементов в контейнере будет несколько, то отступы между ними будут равномерными. То есть будет происходить распределение элементов внутри флекс-контейнера чем-то похожее на justify-content: space-around
.
Давайте проверим этот момент на примере карточки товара, в которой картинка центруется внутри блока.
.pictures
задайте раскладку флексбокса,.picture
задайте margin: auto
..picture img
на 40px
,.picture
с такой же картинкой.А теперь давайте отцентруем элементы с помощью свойств флекс-контейнера без margin: auto
на дочерних элементах.
Заметьте разницу между тем, как распределяются элементы при разных значениях свойства justify-content
.
.picture
уберите margin: auto
,.pictures
задайте распределение флекс-элементов по центру главной осиspace-around
.Флексбокс полезен при создании блоков с дочерними элементами динамической длины. Хороший пример — меню.
Часто встречаются дизайны, в которых пункты равномерно распределены по блоку меню. Первый пункт примыкает к левой части блока меню, а последний — к правой, причём с небольшими внутренними отступами.
Эту задачу можно попытаться решить, задав фиксированные отступы и ширину пунктам меню. Но такой способ не подойдёт, если количество пунктов меню или подписи внутри них будут изменяться.
И тут на помощь приходит флексбокс. Зададим меню раскладку флексбокса, пункты станут флекс-элементами. С помощью свойства распределения элементов justify-content
добьёмся нужного результата.
.menu
задайте раскладку флексбокса,Теперь можно запросто добавить в меню ещё один пункт или изменить ширину самого контейнера.
Отступы между пунктами меню будут «гибко» меняться, подстраиваясь под новые условия.
.menu
между двумя div
с текстом Рыба
и Молоко
добавьте ещё один div
со ссылкой с текстом Сметана
.80%
.С помощью раскладки флексбокса можно также легко управлять порядком следования элементов, не изменяя при этом HTML-код.
Давайте заменим один из пунктов меню блоком с логотипом, а затем легко попереставляем его на разные места с помощью свойства order
.
.logo
и вставьте его внутрь меню вместо div
с текстом Сметана
..menu
задайте центральное выравнивание элементов по поперечной оси..logo
задайте порядковый номер флекс-элемента -1
,1
.Давайте используем раскладку флексбокса ещё в одном примере.
Для начала выстроим два блока, идущих друг за другом, в ряд. Затем изменим порядок их отображения.
Заметьте, что флекс-элементами внутри флекс-контейнера становятся только прямые потомки, элементы первого уровня вложенности.
В нашем примере флекс-контейнер .post
включает два флекс-элемента section
и aside
. Блоки внутри флекс-элементов ведут себя как обычно, флекс-поток их не затрагивает.
.post
задайте раскладку флексбокса,aside
внутри .post
задайте порядковый номер флекс-элемента -1
.Флекс-элемент внутри флекс-контейнера можно также сделать флекс-контейнером.
Он будет одновременно вести себя и как флекс-элемент, то есть подчиняться правилам распределения и выравнивания своего родителя, и как самостоятельный флекс-контейнер. При этом его вложенные элементы первого уровня будут следовать только его флекс-правилам.
В нашем примере давайте сделаем блок с иконками социальных сетей вложенным флекс-контейнером, а его дочерние флекс-элементы распределим по всей высоте блока.
.post aside
задайте раскладку флексбокса,20px
.Теперь, если изменить высоту флекс-элемента section
, то изменится и высота элемента aside
. А так как aside
сам является флекс-контейнером, то изменение его высоты перераспределит его дочерние флекс-элементы — ссылки с иконками.
Получается, что иконки всегда будут распределяться по высоте содержимого блока section
.
Давайте проверим это, добавив ещё немного текста в блок.
.post
.Интересного эффекта можно достичь, если скомбинировать флексбокс и трюк с селектором :checked ~
. Подробно :checked ~
разбирается в задании курса «Селекторы. Часть 3».
Приём заключается в следующем: с помощью селектора по выделению чекбокса можно управлять порядком флекс-элементов, изменяя направление главной оси с помощью flex-direction
. Лучше всего эффект работает, когда направление главной оси меняется с «сверху вниз» на «снизу вверх».
При этом флекс-контейнер должен находиться в разметке на одном уровне с чекбоксом.
Таким образом реализуется сортировка на CSS, без использования JavaScript.
.sort-list
задайте раскладку флексбокса.input-sort
для блока .sort-list
задайте направление главной оси снизу вверх.Переключайте чекбокс, чтобы сортировать элементы списка.
Ещё одна часто встречающаяся задача — реализовать раскладку с блоками одинаковой высоты.
Надо учитывать, что содержимое блоков может быть разным и их высота может меняться.
В обычной блочной модели есть фундаментальный недостаток — соседние блоки ничего не знают друг о друге, поэтому их высоты нельзя «связать». Получается, что все «стандартные» варианты для решения этой задачи не работают:
float
или inline-block
не могут «связывать» высоты соседних блоков;
таблицы и CSS-таблицы позволяют делать ячейки одинаковой высоты, но появляются ограничения, связанные с расположением элементов в строках;
минимальная высота не подходит, так как какой-то из блоков всегда может стать выше остальных;
конечно, можно задать всем блокам фиксированную высоту, но это решение совсем не универсальное.
А с помощью флексбоксов эта проблема решается легко и изящно, ведь флекс-элементы по умолчанию растягиваются на всю высоту контейнера.
Попробуем починить раскладку на float
с помощью флексбокса.
.columns
задайте раскладку флексбоксаИтак, вы подошли к финальному испытанию.
Вам предстоит снова собирать палитру. Да не одну!
На этот раз придётся воспользоваться всем изученным арсеналом свойств флексбокса. Также для прохождения может понадобиться повторение CSS-селекторов.
Этот курс — первая часть серии о флексбоксе. До встречи на следующих курсах. Продолжение следует!