Флексбокс, часть 1

Флексбокс, часть 1

Рассмотрим основы нового механизма «гибкой» раскладки — флексбокс. Сначала потренируемся «на котиках» направлять оси флекс-контейнера, выравнивать и переносить флекс-элементы, а затем научимся простому применению флексбокса в реальных интерфейсах.

×

Флексбокс, display: flex [1/31]

Флексбокс — это первый CSS-механизм, предназначенный для построения сеток и создания сложных раскладок блоков.

Другие механизмы, с помощью которых мы раньше строили сетки, задумывались совсем не для этого: плавающие блоки нужны для создания блоков, которые обтекает текст, а таблицы используются для разметки табличных данных.

Флексбокс задумывался для создания «гибких» раскладок и хранит много тонкостей и чудес, о которых мы поговорим в этой серии курсов. А пока начнём с простого. Как включить флексбокс?

Очень просто: нужно задать элементу свойство display: flex;. После этого происходит два события:

  1. Элемент с display: flex; превращается во «флекс-контейнер» и внутри него начинает происходить вся магия гибкой раскладки.
  2. Непосредственные потомки этого элемента превращаются во «флекс-элементы» и начинают играть по новым правилам.

Первое, что вы заметите после выполнения этого задания, это то, что блоки растянутся на всю высоту контейнера. Да, внутри флексбокса можно делать элементы одинаковой высоты!

Поэкспериментируем!

На момент написания курса поддержка флексбокса в современных браузерах довольно хорошая, что позволяет сейчас с уверенностью его использовать.

  • Цель 1 Блоку .room задайте свойство display со значением flex.
  • ×

    Главная ось, flex-direction [2/31]

    Вспомните, как ведёт себя обычный поток документа. Блоки и текст располагаются слева направо и сверху вниз.

    В привычной блочной модели направления «лево», «право», «верх» и «низ» неизменны. Но внутри флекс-контейнера эти понятия могут изменяться, потому что там можно изменять обычное направление потока.

    Вместо направлений «лево» и «право» во флексбоксе используется понятие «главная ось». Поток флекс-элементов «течёт» вдоль главной оси от её начала к её концу.

    Поток флекс-элементов «течёт» вдоль главной оси

    По умолчанию главная ось направлена слева направо, но её можно разворачивать во всех направлениях с помощью свойства flex-direction, которое задаётся для флекс-контейнера. Значения свойства:

    Флекс-элементы всегда располагаются вдоль главной оси, независимо от её направления.

    Мы добавили в мини-браузер индикатор главной оси. Теперь вы всегда будете знать, куда она направлена.

    Для блока .room задайте направление главной оси:

    1. Цель 1 справа налево,
    2. Цель 2 сверху вниз,
    3. Цель 3 а затем снизу вверх.
    ×

    Поперечная ось [3/31]

    Вместо направлений «верх» и «низ» во флексбоксе используется понятие «поперечная ось». Вдоль этой оси рассчитывается высота элементов и работают «вертикальные» выравнивания.

    Поперечная ось во флексбоксе

    Поперечная ось всегда перпендикулярна главной оси и поворачивается вместе с ней:

    Это не совсем логичное поведение, к которому надо привыкнуть. Получается, что поперечная ось никогда не смотрит вверх или влево. А свойства для поворота поперечной оси нет.

    Давайте посмотрим на поведение поперечной оси вживую.

    Мы добавили в мини-браузер индикатор поперечной оси. Теперь вы всегда будете знать, куда она направлена.

    Для блока .room задайте ещё раз направление главной оси:

    1. Цель 1 сверху вниз,
    2. Цель 2 справа налево,
    3. Цель 3 а затем слева направо.

    Обращайте внимание на направление поперечной оси.

    ×

    Распределение флекс-элементов, justify-content [4/31]

    Вместо «горизонтального» выравнивания во флексбоксе используется свойство для распределения элементов вдоль главной оси — justify-content. Это свойство задаётся для флекс-контейнера.

    Его значением по умолчанию является flex-start. При этом значении элементы располагаются у начала главной оси.

    Чтобы элементы располагались по центру главной оси, нужно задать для justify-content значение center.

    Давайте разместим коврики по центру комнаты.


    1. Цель 1 Задайте распределение флекс-элементов по центру главной оси в блоке .room.
    ×

    В начале и в конце главной оси [5/31]

    Чтобы флекс-элементы располагались в начале главной оси, свойству justify-content нужно задать значение flex-start. Оно же является и значением по умолчанию.

    А значение flex-end расположит элементы в конце главной оси.

    Обратите внимание, что justify-content: flex-end не меняет порядок элементов, как это происходит при изменении направления оси flex-direction: row-reverse. Элементы просто прижимаются к концу главной оси.

    Давайте опробуем эти значения justify-content и разместим коврики в начале и в конце комнаты.


    1. Цель 1 В блоке .room-2 разверните главную ось справа налево.
    2. Цель 2 Обоим блокам задайте распределение элементов в начале главной оси,
    3. Цель 3 затем только первому блоку — в конце главной оси,
    4. Цель 4 и снова обоим блокам — в конце главной оси.
    ×

    Равномерное распределение [6/31]

    Помните ли вы режим горизонтального выравнивания «по ширине», когда текст распределялся в блоке равномерно, а края текста прижимались к краям блока? Совсем как в этом абзаце.

    У флексбокса есть чем-то похожие значения justify-content, которые равномерно распределяют флекс-элементы вдоль главной оси:

    Сейчас мы добавим третьего кота и поэкспериментируем с этими значениями justify-content.

    А пока небольшой итог. Свойство justify-content управляет распределением элементов вдоль главной оси и имеет пять значений:


    1. Цель 1 В каждый из блоков .room добавьте кота Семёна: блок с классами rug и simeon.
    2. Цель 2 Затем блоку .room-1 задайте равномерное распределение вдоль главной оси без отступов по краям,
    3. Цель 3 а блоку .room-2 — равномерное распределение с половинными отступами по краям.
    ×

    Выравнивание флекс-элементов, align-items [7/31]

    Вместо «вертикального» выравнивания во флексбоксе используется свойство для выравнивания элементов вдоль поперечной оси — align-items. Это свойство задаётся для флекс-контейнера.

    Его значением по умолчанию является stretch. Именно благодаря этому значению флекс-элементы и растягиваются на всю «высоту» флекс-контейнера. Если флекс-элементам задана высота, то растягиваться они не будут.

    Чтобы элементы выровнялись по центру поперечной оси, нужно задать для align-items значение center.

    Давайте выровняем коврики по центру комнаты вдоль поперечной оси и убедимся, что элементы действительно центруются, даже если у них разная высота.


    1. Цель 1 Коврикам .rug задайте высоту 150px,
    2. Цель 2 затем для блока .room задайте выравнивание флекс-элементов по центру поперечной оси,
    3. Цель 3 а после этого коврику Кекса .keks задайте высоту 250px.
    ×

    В начале и в конце поперечной оси [8/31]

    Чтобы расположить флекс-элементы в начале или в конце поперечной оси, нужно использовать значения flex-start и flex-end для свойства align-items.

    Эти значения аналогичны значениям свойства justify-content, отличается только ось.

    Проверим эти значения и разместим коврики сверху и снизу комнаты.


    Для блока .room задайте выравнивание флекс-элементов:

    1. Цель 1 в начале поперечной оси,
    2. Цель 2 а затем в конце поперечной оси.
    ×

    Выравнивание элементов по базовой линии [9/31]

    Ещё одно значение свойства align-items — это baseline. Если задать его контейнеру, то флекс-элементы будут выравниваться по базовой линии текста в них. Эта воображаемая линия проходит по нижней части букв.

    Если выровнять флекс-элементы по базовой линии, то они выстроятся так, чтобы текст в них был как бы на «одной строке».

    Чтобы лучше понять поведение baseline, сравним его с другим значением — flex-start.

    Мини-итог. Свойство align-items управляет выравниванием элементов вдоль поперечной оси и имеет пять значений:


    1. Цель 1 Для блока .room-1 задайте выравнивание флекс-элементов в начале поперечной оси,
    2. Цель 2 а для блока .room-2 выравнивание по базовой линии текста.
    ×

    Эгоистичное выравнивание, align-self [10/31]

    Распределение элементов по главной оси задаётся для всего флекс-контейнера и на все флекс-элементы действует одинаково. Задать какому-то элементу отличное от других распределение по главной оси нельзя. И это вполне логично, ведь тогда элементы будут «сталкиваться» друг с другом.

    C поперечной осью всё проще. Можно сказать, что у каждого элемента она своя, и можно задавать им разное поперечное выравнивание. Для этого используется свойство align-self, которое задаётся для самих флекс-элементов, а не для флекс-контейнера.

    У свойства align-self те же самые значения, что и у align-items.


    1. Цель 1 Для коврика Рудольфа .rudolf задайте выравнивание в начале поперечной оси,
    2. Цель 2 для Кекса .keks — в конце поперечной оси,
    3. Цель 3 а для Семёна .simeon — по центру оси center.
    ×

    Выравнивание одного элемента по базовой линии [11/31]

    Аналогично align-items для отдельного флекс-элемента можно задать и выравнивание по базовой линии с помощью align-self со значением baseline.

    Давайте зададим выравнивание по базовой линии двум отдельным блокам.


    Задайте выравнивание флекс-элементов по базовой линии текста:

    1. Цель 1 для коврика Семёна .text-simeon,
    2. Цель 2 для коврика Кекса .text-keks.
    ×

    Перенос флекс-элементов, flex-wrap [13/31]

    Что будет, если флекс-элементов в контейнере станет больше, чем может уместиться в один ряд?

    Это чем-то похоже на поведение ячеек в таблице.

    Такое поведение можно изменить свойством флекс-контейнера flex-wrap. По умолчанию оно имеет значение nowrap, то есть перенос флекс-элементов на новую строку запрещён.

    Значение wrap разрешает перенос флекс-элементов на новую строку, если они не помещаются в контейнер.

    Давайте посмотрим на практике, как оно работает.


    1. Цель 1 Коврикам .rug задайте ширину 120px,
    2. Цель 2 затем в блок .room последним добавьте кота Массимо: блок с классами rug и massimo,
    3. Цель 3 а после этого для .room задайте перенос флекс-элементов на новую строку.
    ×

    Перенос в обратном порядке [14/31]

    Если перенос флекс-элементов разрешён, то ряды элементов располагаются вдоль поперечной оси. Первый ряд располагается в начале поперечной оси, а последний в конце. Но так работает только значение wrap.

    Если для flex-wrap задать значение wrap-reverse, то элементы будут переноситься, а ряды будут располагаться в обратном порядке: первый в конце поперечной оси, а последний в начале.

    Давайте добавим в комнату ещё котиков и попробуем переносить их на новую строку в обратном поперечной оси направлению.


    1. Цель 1 Добавьте ещё двух котов: Марти — блок с классами rug и marty и Черныша — блок с классами rug и blacky,
    2. Цель 2 затем для .room задайте перенос флекс-элементов на новую строку в обратном направлении wrap-reverse,
    3. Цель 3 а потом задайте всем коврикам ширину 180px.
    ×

    Выравнивание строк флекс-контейнера, align-content [15/31]

    Вспомним свойство justify-content, которое управляет распределением флекс-элементов вдоль главной оси.

    Есть очень похожее свойство align-content, которое управляет выравниванием рядов флекс-элементов вдоль поперечной оси. У этих свойств почти одинаковые значения:

    Свойство align-content связано и со свойством align-items, которое управляет выравниванием флекс-элементов вдоль поперечной оси.

    В чём разница между align-content и align-items, когда работает одно, а когда работает другое? Вот ответы:

    В последней версии спецификации это поведение изменилось: теперь правильно, когда align-content выравнивает элементы в многострочном флекс-контейнере, даже если строка в контейнере единственная. Это изменение на момент окончания 2015 года применено только в браузерах Safari и Edge.


    1. Цель 1 Для .room-1 задайте align-items в начале поперечной оси,
    2. Цель 2 а для .room-2align-items в конце поперечной оси.
    3. Цель 3 Затем увеличьте ширину коврика .rug до 120px, чтобы в блоках стало два ряда элементов.

    Смотрите, как выравнивание рядов переопределило выравнивание элементов.

    ×

    align-content: stretch и align-items [16/31]

    Ранее мы говорили, что как только во флекс-контейнере появляется несколько рядов элементов, вместо align-items начинает действовать свойство align-content.

    В этом случае align-items не отключается полностью, а может влиять на отображение флекс-элементов в рядах.

    Это происходит, когда мы используем для align-content значение по умолчанию — stretch. Оно растягивает ряды флекс-элементов, при этом оставшееся свободное место между ними делится поровну.

    Отображение строк при align-content: stretch зависит от значения align-items:

    Давайте посмотрим на этот эффект вживую.


    1. Цель 1 Задайте .rug внутри .room-2 ширину 120px, чтобы там появилось два ряда.
    2. Цель 2 Для обеих комнат задайте align-items в начале оси,
    3. Цель 3 посередине оси,
    4. Цель 4 в конце оси.
    ×

    align-content: не-stretch и align-items [17/31]

    Значение align-items влияет на отображение рядов во флекс-контейнере, если у align-content задано значение stretch. В этом мы убедились в прошлом задании.

    Есть ли похожее влияние на остальные значения align-content? Нет.

    Убедимся в этом на примере значения center, которое располагает ряды в середине поперечной оси так, что:

    Давайте поэкспериментируем.


    1. Цель 1 Для .room-2 задайте выравнивание рядов по центру оси.
    2. Цель 2 Затем для обеих комнат задайте align-items в начале оси,
    3. Цель 3 и в конце оси.
    ×

    Остальные значения align-content [18/31]

    Остальные четыре значения свойства align-content аналогичны значениям свойства justify-content, отличается только ось:

    Напоследок небольшое резюме.

    Свойство align-content — «гибридное». Мы переводим его как «выравнивание», но оно больше похоже на «распределение», justify-content, от которого оно позаимствовало два значения space-between и space-around.

    Близость с «распределением» подчёркивает и отсутствие значения baseline — всё-таки свойство работает с рядами, а не с отдельными элементами.

    От «выравниваний» же, align-items и align-self, это свойство получило значение по умолчанию stretch и возможность «растягивать» ряды по высоте.


    1. Цель 1 Для .room задайте выравнивание строк в начале оси,
    2. Цель 2 в конце оси,
    3. Цель 3 равномерное выравнивание без отступов по краям,
    4. Цель 4 равномерное выравнивание с половинными отступами по краям.
    ×

    Порядковый номер флекс-элемента, order [19/31]

    И ещё одно свойство, которое мы рассмотрим в этом курсе, — это order, порядковый номер флекс-элемента.

    Это очень полезное свойство, так как с его помощью можно менять порядок следования флекс-элементов в потоке, не меняя HTML-код.

    По умолчанию порядковый номер флекс-элементов равен 0, а сортировка элементов производится по возрастанию номера.

    Порядковый номер задаётся целым числом, положительным или отрицательным. Например:

    .flex-element {
        order: -1; /* этот элемент станет отображаться первым в контейнере */
    }

    Давайте попробуем перетасовать коврики с котиками с помощью свойства order.


    1. Цель 1 Для коврика Кекса .keks задайте порядковый номер -1,
    2. Цель 2 затем для коврика Семёна .simeon — порядковый номер -2,
    3. Цель 3 а для коврика Рудольфа .rudolf — номер 1.
    ×

    Идеальное центрирование, margin: auto [21/31]

    В следующих заданиях мы разберём примеры из жизни, в которых можно применять флексбокс.

    Самый насущный вопрос, который можно легко и изящно решить с помощью флексбокса, — как отцентровать элемент по вертикали и горизонтали так, чтобы центровка сохранялась при изменении размеров элемента или контейнера.

    Ответ прост: задать контейнеру раскладку флексбокса, а дочернему флекс-элементу margin: auto.

    В этом случае флекс-элемент уменьшит свой размер под содержимое и отцентруется по вертикали и горизонтали.

    Стоит обратить внимание на интересный момент. Если центруемых флекс-элементов в контейнере будет несколько, то отступы между ними будут равномерными. То есть будет происходить распределение элементов внутри флекс-контейнера чем-то похожее на justify-content: space-around.

    Давайте проверим этот момент на примере карточки товара, в которой картинка центруется внутри блока.


    1. Цель 1 Блоку .pictures задайте раскладку флексбокса,
    2. Цель 2 а затем для блока .picture задайте margin: auto.
    3. Цель 3 Измените размер картинки .picture img на 40px,
    4. Цель 4 а потом в HTML-редакторе добавьте ещё один блок .picture с такой же картинкой.
    ×

    Идеальное центрирование, флекс-выравнивания [22/31]

    А теперь давайте отцентруем элементы с помощью свойств флекс-контейнера без margin: auto на дочерних элементах.

    Заметьте разницу между тем, как распределяются элементы при разных значениях свойства justify-content.


    1. Цель 1 У блоков .picture уберите margin: auto,
    2. Цель 2 затем блоку .pictures задайте распределение флекс-элементов по центру главной оси
    3. Цель 3 и выравнивание по центру поперечной оси.
    4. Цель 4 Затем замените распределение по главной оси на space-around.
    ×

    «Гибкое» меню [23/31]

    Флексбокс полезен при создании блоков с дочерними элементами динамической длины. Хороший пример — меню.

    Часто встречаются дизайны, в которых пункты равномерно распределены по блоку меню. Первый пункт примыкает к левой части блока меню, а последний — к правой, причём с небольшими внутренними отступами.

    Эту задачу можно попытаться решить, задав фиксированные отступы и ширину пунктам меню. Но такой способ не подойдёт, если количество пунктов меню или подписи внутри них будут изменяться.

    И тут на помощь приходит флексбокс. Зададим меню раскладку флексбокса, пункты станут флекс-элементами. С помощью свойства распределения элементов justify-content добьёмся нужного результата.


    1. Цель 1 Блоку .menu задайте раскладку флексбокса,
    2. Цель 2 а затем равномерное распределение элементов по главной оси с половинными отступами по краям.
    ×

    «Гибкое» меню, часть 2 [24/31]

    Теперь можно запросто добавить в меню ещё один пункт или изменить ширину самого контейнера.

    Отступы между пунктами меню будут «гибко» меняться, подстраиваясь под новые условия.


    1. Цель 1 В .menu между двумя div с текстом Рыба и Молоко добавьте ещё один div со ссылкой с текстом Сметана.
    2. Цель 2 Затем задайте меню ширину 80%.
    ×

    «Гибкое» меню, часть 3 [25/31]

    С помощью раскладки флексбокса можно также легко управлять порядком следования элементов, не изменяя при этом HTML-код.

    Давайте заменим один из пунктов меню блоком с логотипом, а затем легко попереставляем его на разные места с помощью свойства order.


    1. Цель 1 Вырежьте блок .logo и вставьте его внутрь меню вместо div с текстом Сметана.
    2. Цель 2 Затем для .menu задайте центральное выравнивание элементов по поперечной оси.
    3. Цель 3 Блоку .logo задайте порядковый номер флекс-элемента -1,
    4. Цель 4 а потом 1.
    ×

    Вертикальный ряд иконок [26/31]

    Давайте используем раскладку флексбокса ещё в одном примере.

    Для начала выстроим два блока, идущих друг за другом, в ряд. Затем изменим порядок их отображения.

    Заметьте, что флекс-элементами внутри флекс-контейнера становятся только прямые потомки, элементы первого уровня вложенности.

    В нашем примере флекс-контейнер .post включает два флекс-элемента section и aside. Блоки внутри флекс-элементов ведут себя как обычно, флекс-поток их не затрагивает.


    1. Цель 1 Блоку .post задайте раскладку флексбокса,
    2. Цель 2 а затем для aside внутри .post задайте порядковый номер флекс-элемента -1.
    ×

    Вертикальный ряд иконок, часть 2 [27/31]

    Флекс-элемент внутри флекс-контейнера можно также сделать флекс-контейнером.

    Он будет одновременно вести себя и как флекс-элемент, то есть подчиняться правилам распределения и выравнивания своего родителя, и как самостоятельный флекс-контейнер. При этом его вложенные элементы первого уровня будут следовать только его флекс-правилам.

    В нашем примере давайте сделаем блок с иконками социальных сетей вложенным флекс-контейнером, а его дочерние флекс-элементы распределим по всей высоте блока.


    1. Цель 1 Блоку .post aside задайте раскладку флексбокса,
    2. Цель 2 направление главной оси сверху вниз,
    3. Цель 3 равномерное распределение флекс-элементов по главной оси без отступов по краям,
    4. Цель 4 а затем внешний отступ справа 20px.
    ×

    Вертикальный ряд иконок, часть 3 [28/31]

    Теперь, если изменить высоту флекс-элемента section, то изменится и высота элемента aside. А так как aside сам является флекс-контейнером, то изменение его высоты перераспределит его дочерние флекс-элементы — ссылки с иконками.

    Получается, что иконки всегда будут распределяться по высоте содержимого блока section.

    Давайте проверим это, добавив ещё немного текста в блок.


    1. Цель 1 Раскомментируйте в разметке два параграфа внутри блока .post.
    ×

    Сортировка элементов на CSS [29/31]

    Интересного эффекта можно достичь, если скомбинировать флексбокс и трюк с селектором :checked ~. Подробно :checked ~ разбирается в задании курса «Селекторы. Часть 3».

    Приём заключается в следующем: с помощью селектора по выделению чекбокса можно управлять порядком флекс-элементов, изменяя направление главной оси с помощью flex-direction. Лучше всего эффект работает, когда направление главной оси меняется с «сверху вниз» на «снизу вверх».

    При этом флекс-контейнер должен находиться в разметке на одном уровне с чекбоксом.

    Таким образом реализуется сортировка на CSS, без использования JavaScript.


    1. Цель 1 Блоку .sort-list задайте раскладку флексбокса
    2. Цель 2 и направление главной оси сверху вниз.
    3. Цель 3 При выделенном состоянии чекбокса .input-sort для блока .sort-list задайте направление главной оси снизу вверх.

    Переключайте чекбокс, чтобы сортировать элементы списка.

    ×

    Блоки одинаковой высоты [30/31]

    Ещё одна часто встречающаяся задача — реализовать раскладку с блоками одинаковой высоты.

    Надо учитывать, что содержимое блоков может быть разным и их высота может меняться.

    В обычной блочной модели есть фундаментальный недостаток — соседние блоки ничего не знают друг о друге, поэтому их высоты нельзя «связать». Получается, что все «стандартные» варианты для решения этой задачи не работают:

    А с помощью флексбоксов эта проблема решается легко и изящно, ведь флекс-элементы по умолчанию растягиваются на всю высоту контейнера.

    Попробуем починить раскладку на float с помощью флексбокса.


    1. Цель 1 Блоку .columns задайте раскладку флексбокса
    2. Цель 2 и перенос флекс-элементов на новую строку.
    ×

    Испытание: сложные палитры [31/31]

    Итак, вы подошли к финальному испытанию.

    Вам предстоит снова собирать палитру. Да не одну!

    На этот раз придётся воспользоваться всем изученным арсеналом свойств флексбокса. Также для прохождения может понадобиться повторение CSS-селекторов.

    Этот курс — первая часть серии о флексбоксе. До встречи на следующих курсах. Продолжение следует!