Веб-разработка
May 19

Гибкие флексбоксы flex — Тренажёр HTML Academy

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

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

Флексбокс

Чтобы контейнеру задать свойства «гибких контейнеров» или просто «флексбоксов», достаточно указать его тип display: flex;.

Сразу после этого бокс к которому было применено это свойство становится «флекс-контейнером», а его прямые потомки, то бишь дочерние элементы, становятся «флекс-элементами» или «флекс-итемами» (flex-item).

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

Я нагло взял картинки из тренажёров HTML Академии.

Это происходит потому, что во флекс-контейнере тоже меняется направление потока. Я когда писал про логику float как-то не задумывался, что во флексах, в общем-то ситуация похожая.

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

Управляет направлением этих осей свойство flex-direction, которое имеет четыре простых значения:

  • row — по умолчанию, «в строку», то есть главная ось направлена слева направо и флекс-итемы располагаются вдоль неё;
  • column — «в столбец», главная ось направлена сверху вниз, но при этом работают все гибкие правила для флекс-итемов;
  • row-reverse и column-reverse — оба свойства просто разворачивают ось соответственно, справа налево и снизу вверх.

Выравнивание флекс-элементов

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

  • flex-start — значение по умолчанию, итемы прижаты к началу главной оси;
  • flex-end — итемы прижаты к концу главной оси;
  • center — итемы расположены по центру контейнера вдоль главной оси.

И три значения, которые не прижимают, а распределяют итемы:

  • space-between — равномерно распределяет итемы вдоль всей главной оси, без отступов от краёв флекс-контейнера;
  • space-around — равномерно распределяет итемы вдоль главной оси, с отступом от края флекс-контейнера равным половине отступа между флекс-итемами;
  • space-evenly — равномерно распределяет итемы вдоль оси с равными отступами от краёв контейнера и между собой.

Будет, наверное, проще показать, чем пытаться объяснять все словами. Правда, в тренажёре у итемов есть еще внешние отступы margin, которые могут немного ввести в заблуждение. Поэтому я добавил поверх еще поля:

Вдоль поперечной оси тоже можно выравнивать итемы с помощью свойства align-items — у него пять значений:

  • stretch — по умолчанию, растягивает флекс-итем вдоль поперечной оси, если не задан конкретный размер;
  • flex-start — прижимает итемы к началу поперечной оси, при этом размер итема вдоль поперечной оси ужимается до размера контента;
  • flex-end — прижимает к концу поперечной оси;
  • center — выравнивает по центру вдоль поперечной оси;
  • baseline — выравнивание итемов по базовой линии текста.

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

Итак, с одной строкой флекс-итемов разобрались.

Перенос и выравнивание строк во флексбоксе

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

Не очень приятная особенность, но к счастью, переносом строки можно управлять с помощью свойства flex-wrap! Оно имеет три значения:

  • nowrap — по умолчанию, флекс-элементы не переносятся;
  • wrap — разрешает перенос элементов на новую строку, бокс флекс-итема начинает учитываться и перенос осуществляется если очередной бокс не умещается в строку;
  • wrap-reverse — перенос будет осуществляться в обратную сторону, то есть вверх, не поместившийся в строку элемент переместится выше, а строка сместиться вниз.

При включении переноса строки flex-wrap во флекс-контейнере начинает работать еще одно интересное свойство — align-content управление выравниванием строк.

Оно очень похоже на свойство justify-content и имеет почти такие же значения, включая значения распределения, например, space-between и подобные ему. Но имеет еще одно — stretch значение по умолчанию.

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

Важно понимать еще отличие align-items, отвечающего за выравнивание элементов на строке вдоль поперечной оси, от align-content, отвечающего за выравнивание строк в контейнере вдоль поперечной оси.

Опять же, проще будет показать на примере, иначе можно запутаться:

Важно еще заметить, что значение по умолчанию stretch работает только если оно задано обоим свойствам align-items и align-content. Иначе, если в одном из них задано отличное от stretch значение, то у второго оно игнорируется.

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


Ещё в этой части тренажёра рассмотрено свойство order отвечающий за порядковый номер флекс-итема. Свойства указывается именно элементу и с его помощью можно изменить его расположение.

Например задав значение -1 можно вывести элемент вперёд остальных, даже если он расположен после всех.

С положением и выравниванием элементов разобрались, переходим к размерам!

Блочная модель во флексбоксах

Флекс-контейнер сам по себе не изменяется и для него работает стандартная блочная модель. Для флекс-итемов же есть свои нюансы.

Им можно задать размеры width и height, рамку border и внутренние отступы padding, которые будут работать так же по стандартной блочной модели. К ним тоже можно применить свойство box-sizing для изменения расчёта размера бокса с учётом отступов.

С внешними отступами margin уже начинаются отличия:

  • margin не «схлопываются» ни горизонтально, ни вертикально;
  • margin не «выпадают» из флекс-контейнера и из флекс-итема;
  • значение margin: auto; работает во всех направлениях, включая по вертикали, при этом имеет приоритет над свойствами распределения флекс-элементов justify-content, align-items и align-self;

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

Аналогично, ширина width будет только горизонтальным размером указанного элемента, неважно что указано в свойстве flex-direction. Это с одной стороны логично, с другой стороны усложняет работу с флексбоксами.

Немного упрощает это дело ряд свойств придуманных специально для работы с флекс-итемами. Первый такой — flex-basis, который задаёт элементу его базовый размер вдоль главной оси флекс-контейнера.

Свойство flex-basis, в рамках флекс-контейнера, имеет приоритет над стандартными свойствами width и height и переопределит одно из них в зависимости от направления главной оси.

Почему размер базовый? Остальные два рассмотренных в тренажёре свойства — это модификаторы этого базового размера. Им посвящена значительная часть уроков, так как с ними много нюансов.

Коэффициенты расширения и сжатия

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

Например, если мы имеем два элемента во флекс-контейнере, с одинаковыми базовыми размерами flex-basis, то вот что получится с разными flex-grow:

Это простейший пример — flex-grow пытается занять максимальное количество свободного пространства. Поэтому если значения расширения равны, то оба элемента займут одинаковое пространство. Если же flex-grow задан только одному флекс-итему, то он займет всё свободное пространство и прижмёт второй элемент.

Важно заметить — занимается именно свободное, то есть не занятое базовыми размерами flex-basis пространство. Поэтому его тоже нужно учитывать в формуле расчёта:

Выглядит страшно, но, на самом деле, всё достаточно просто. Для упрощения формулы часто используется прием «нулевого» базового размера flex-basis и свойства min-width или min-height:

flex-basis: 0%;
min-width: 50px;

Таким образом расчет будет сильно упрощён и по сути прямо пропорционален значению flex-grow. Дело в том, что ограничительные свойства типа min/max применяются и проверяются уже после перераспределения свободного места.


Второй на очереди коэффициент сжатия flex-shrink — он похож на коэффициент расширения, но работает в обратную сторону. По умолчанию имеет значение 1, то есть все флекс-элементы пропорционально сжимаются, чтобы уместиться на одной строке.

Если же задать коэффициент сжатия flex-shrink: 0;, то флекс-итем не будет сжиматься и будет иметь фиксированный размер flex-basis независимо от оставшегося свободного места.

Если сумма всех flex-basis итемов в контейнере будет превышать его размер и при этом коэффициент сжатия всех элементов будет равен 0, то возникнет выпадение из контейнера. Или, как его назвали в тренажёрах, отрицательное пространство — область на которую выпал элемент или элементы.

Это, на мой взгляд, ну очень гипотетическая ситуация, но на её примере в тренажёре объясняется расчёт итогового размера элемента при сжатии. Предположим, что у нас значительно выпали элементы и нам нужно найти коэффициенты сжатия для них:

Выглядит кошмарно

Когда я увидел это в тренажёре я, мягко говоря, впечатлился. Здесь уже не упростишь — считай как есть, причем в итоге поиск одного коэффициента зависит от подстановки других. Оно находится достаточно быстро, но это, честно говоря, какой-то идиотизм.

Я могу только нафантазировать такую ситуацию, но скорее всего, в реальности эти подсчеты пригодятся один раз на тысячу. Хотя, понимать как работает сжатие флекс-итемов полезно и интересно.


Все эти три свойства объединяет в себе сокращенное свойство flex, правда, порядок значений не тот в котором мы их рассмотрели.

Порядок следующий — flex-grow, flex-shrink и flex-basis:

.item {
flex-grow: 0;
flex-shrink: 1;
flex-basis: 50px;
}
/* эквивалент */
.item {
  flex: 0 1 50px;
}

Испытания

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

Эти части одни из самых объемных в плане практики.

Перейдем к самим Испытаниям. Первые три на понимание свойств распределения и выравнивания флекс-итемов. Сначала крайне простой однострочный флексбокс:

Второе испытание закрепляет свойство направления оси flex-direction и свойство порядкового номера флекс итема order:

Третье испытание лютое комбо из многострочного флексбокса и селекторов, вспоминаем прошлый блок:

Далее три испытания на базовый размер flex-basis, понимание отступов и блочной модели и модификаторы flex-grow и flex-shrink. Четвёртое испытание опять на подбор циферок, нужно подвести флекс-итемы используя только margin:

Пятое испытание на понимание модификаторов flex-grow и flex-shrink:

И последнее шестое тоже на модификаторы, но в случае многострочного флекс-контейнера flex-wrap: wrap;:


Пожалуй, разделю еще на одну статью — о гридах поговорим в следующий раз. Флексы оказались темой еще более серьёзной и большой! Особенно впечатлили формулы модификаторов, но и сам подход гибкой раскладки достаточно трудноусваиваемый.

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

Просто копировать текст из конспектов бессмысленно, я же для себя стараюсь, для усвоения материала. Но это мои проблема, а вам спасибо большое за внимание!

Ссылки на предыдущие статьи по HTML Academy:

Знакомство с Веб-разработкой
Знакомство с HTML и CSS
Знакомство с JavaScript
Знакомство с PHP
Таблицы и подробно о формах
Наследование, каскады и селекторы
Блочная модель, поток и сетка на float
Гибкие флексбоксы display: flex <- Вы здесь
Удобные сетки на гридах display: grid
Пропуск блока «Погружение»
Позиционирование и двумерные трансформации
Теневое искусство и линейные градиенты
CSS-фильтры и Кекстаграм
Мастерские
Продвинутые Мастерские
...

Остальные статьи можно посмотреть у меня на главной странице блога.

Также мои соц. сетки, которые я продолжаю вести:

Мой Twitter
Мой Telegram
Мой Паблик ВК

Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!