Flexbox
Флексбокс, display: flex[1/31]
Флексбокс — это первый CSS-механизм, предназначенный для построения сеток и создания сложных раскладок блоков.
Другие механизмы, с помощью которых мы раньше строили сетки, задумывались совсем не для этого: плавающие блоки нужны для создания блоков, которые обтекает текст, а таблицы используются для разметки табличных данных.
Флексбокс задумывался для создания «гибких» раскладок и хранит много тонкостей и чудес, о которых мы поговорим в этой серии курсов. А пока начнём с простого. Как включить флексбокс?
Очень просто: нужно задать элементу свойствоdisplay: flex;. После этого происходит два события:
- Элемент с
display: flex;превращается во «флекс-контейнер» и внутри него начинает происходить вся магия гибкой раскладки. - Непосредственные потомки этого элемента превращаются во «флекс-элементы» и начинают играть по новым правилам.
Первое, что вы заметите после выполнения этого задания, это то, что блоки растянутся на всю высоту контейнера. Да, внутри флексбокса можно делать элементы одинаковой высоты!
Поэкспериментируем!
Курс «Флексбокс, часть 1»
Главная ось, flex-direction[2/31]
Вспомните, как ведёт себя обычный поток документа. Блоки и текст располагаются слева направо и сверху вниз.
В привычной блочной модели направления «лево», «право», «верх» и «низ» неизменны. Но внутри флекс-контейнера эти понятия могут изменяться, потому что там можно изменять обычное направление потока.
Вместо направлений «лево» и «право» во флексбоксе используется понятие«главная ось». Поток флекс-элементов «течёт» вдоль главной оси от её начала к её концу.

По умолчанию главная ось направлена слева направо, но её можно разворачивать во всех направлениях с помощью свойстваflex-direction, которое задаётся для флекс-контейнера. Значения свойства:
row— значение по умолчанию, главная ось направлена слева направо.column— главная ось направлена сверху вниз.row-reverse— главная ось направлена справа налево.column-reverse— главная ось направлена снизу вверх.
Флекс-элементы всегда располагаются вдоль главной оси, независимо от её направления.
Поперечная ось[3/31]
Вместо направлений «верх» и «низ» во флексбоксе используется понятие«поперечная ось». Вдоль этой оси работают «вертикальные» выравнивания.

Поперечная ось всегда перпендикулярна главной оси и поворачивается вместе с ней:
- Если главная ось направлена горизонтально, то поперечная ось смотрит вниз.
- Если главная ось направлена вертикально, то поперечная ось смотрит направо.
Это не совсем логичное поведение, к которому надо привыкнуть. Получается, что поперечная ось никогда не смотрит вверх или влево. А свойства для поворота поперечной оси нет.
Давайте посмотрим на поведение поперечной оси вживую.
Распределение флекс-элементов, justify-content[4/31]
Вместо «горизонтального» выравнивания во флексбоксе используется свойство для распределения элементов вдоль главной оси —justify-content. Это свойство задаётся для флекс-контейнера.
Его значением по умолчанию являетсяflex-start. При этом значении элементы располагаются у начала главной оси.
Чтобы элементы располагались по центру главной оси, нужно задать дляjustify-contentзначениеcenter.
Давайте разместим коврики по центру комнаты.
В начале и в конце главной оси[5/31]
Чтобы флекс-элементы располагались в начале главной оси, свойствуjustify-contentнужно задать значениеflex-start. Оно же является и значением по умолчанию.
А значениеflex-endрасположит элементы в конце главной оси.
Обратите внимание, чтоjustify-content: flex-endне меняет порядок элементов, как это происходит при изменении направления осиflex-direction: row-reverse. Элементы просто прижимаются к концу главной оси.
Давайте опробуем эти значенияjustify-contentи разместим коврики в начале и в конце комнаты.
Равномерное распределение[6/31]
Помните ли вы режим горизонтального выравнивания«по ширине», когда текст распределялся в блоке равномерно, а края текста прижимались к краям блока? Совсем как в этом абзаце.
У флексбокса есть чем-то похожие значенияjustify-content, которые равномерно распределяют флекс-элементы вдоль главной оси:
space-between— расстояния между соседними элементами одинаковые, между элементами и краями флекс-контейнера отступов нет.space-around— расстояния между соседними элементами одинаковые, между элементами и краями флекс-контейнера есть отступ, равный половине расстояния между соседними элементами.
Сейчас мы добавим третьего кота и поэкспериментируем с этими значениямиjustify-content.
А пока небольшой итог. Свойствоjustify-contentуправляет распределением элементов вдоль главной оси и имеет пять значений:
значение по умолчанию
flex-start,flex-end,center,space-between,space-around.
Выравнивание флекс-элементов, align-items[7/31]
Вместо «вертикального» выравнивания во флексбоксе используется свойство для выравнивания элементов вдоль поперечной оси —align-items. Это свойство задаётся для флекс-контейнера.
Его значением по умолчанию являетсяstretch. Именно благодаря этому значению флекс-элементы и растягиваются на всю «высоту» флекс-контейнера. Если флекс-элементам задана высота, то растягиваться они не будут.
Чтобы элементы выровнялись по центру поперечной оси, нужно задать дляalign-itemsзначениеcenter.
Давайте выровняем коврики по центру комнаты вдоль поперечной оси и убедимся, что элементы действительно центруются, даже если у них разная высота.
В начале и в конце поперечной оси[8/31]
Чтобы расположить флекс-элементы в начале или в конце поперечной оси, нужно использовать значенияflex-startиflex-endдля свойстваalign-items.
Эти значения аналогичны значениям свойстваjustify-content, отличается только ось.
Проверим эти значения и разместим коврики сверху и снизу комнаты.
Выравнивание элементов по базовой линии[9/31]
Ещё одно значение свойстваalign-items— этоbaseline. Если задать его контейнеру, то флекс-элементы будут выравниваться по базовой линии текста в них. Эта воображаемая линия проходит по нижней части букв.
Если выровнять флекс-элементы по базовой линии, то они выстроятся так, чтобы текст в них был как бы на «одной строке».
Чтобы лучше понять поведениеbaseline, сравним его с другим значением —flex-start.
Мини-итог. Свойствоalign-itemsуправляет выравниванием элементов вдоль поперечной оси и имеет пять значений:
значение по умолчанию
stretch,flex-start,flex-end,center,baseline.
Эгоистичное выравнивание, align-self[10/31]
Распределение элементов по главной оси задаётся для всего флекс-контейнера и на все флекс-элементы действует одинаково. Задать какому-то элементу отличное от других распределение по главной оси нельзя. И это вполне логично, ведь тогда элементы будут «сталкиваться» друг с другом.
C поперечной осью всё проще. Можно сказать, что у каждого элемента она своя, и можно задавать им разное поперечное выравнивание. Для этого используется свойствоalign-self, которое задаётся для самих флекс-элементов, а не для флекс-контейнера.
У свойстваalign-selfте же самые значения, что и уalign-items.
Выравнивание одного элемента по базовой линии[11/31]
Аналогичноalign-itemsдля отдельного флекс-элемента можно задать и выравнивание по базовой линии с помощьюalign-selfсо значениемbaseline.
Давайте зададим выравнивание по базовой линии двум отдельным блокам.
Перенос флекс-элементов, flex-wrap[13/31]
Что будет, если флекс-элементов в контейнере станет больше, чем может уместиться в один ряд?
- Они будут сжиматься до минимально возможной ширины.
- Даже если им задать ширину явно, механизм флексбокса может её уменьшить.
- Если они перестанут помещаться в контейнер и после уменьшения, то они выйдут за его пределы, но продолжат располагаться в один ряд.
Это чем-то похоже на поведение ячеек в таблице.
Такое поведение можно изменить свойством флекс-контейнераflex-wrap. По умолчанию оно имеет значениеnowrap, то есть перенос флекс-элементов на новую строку запрещён.
Значениеwrapразрешает перенос флекс-элементов на новую строку, если они не помещаются в контейнер.
Давайте посмотрим на практике, как оно работает.
Перенос в обратном порядке[14/31]
Если перенос флекс-элементов разрешён, то ряды элементов располагаются вдоль поперечной оси. Первый ряд располагается в начале поперечной оси, а последний в конце. Но так работает только значениеwrap.
Если дляflex-wrapзадать значениеwrap-reverse, то элементы будут переноситься, а ряды будут располагаться в обратном порядке: первый в конце поперечной оси, а последний в начале.
Давайте добавим в комнату ещё котиков и попробуем переносить их на новую строку в обратном поперечной оси направлению.
Выравнивание строк флекс-контейнера, align-content[15/31]
Вспомним свойствоjustify-content, которое управляет распределением флекс-элементов вдоль главной оси.
Есть очень похожее свойствоalign-content, которое управляет выравниваниемрядовфлекс-элементов вдольпоперечнойоси. У этих свойств почти одинаковые значения:
flex-start,flex-end,center,space-between,space-around,и
stretch, которое есть уalign-content, но нет уjustify-content, и является значением по умолчанию.
Свойствоalign-contentсвязано и со свойствомalign-items, которое управляет выравниванием флекс-элементов вдоль поперечной оси.
В чём разница междуalign-contentиalign-items, когда работает одно, а когда работает другое? Вот ответы:
Если есть только один ряд флекс-элементов, то работает
align-items.Если есть несколько рядов, то работает
align-content.Подчеркнём, что
align-contentвлияет на ряды, а не на отдельные элементы.
В последней версии спецификации это поведение изменилось: теперь правильно, когдаalign-contentвыравнивает элементы в многострочном флекс-контейнере, даже если строка в контейнере единственная. Это изменение на момент окончания 2015 года применено только в браузерах Safari и Edge.
align-content: stretch и align-items[16/31]
Ранее мы говорили, что как только во флекс-контейнере появляется несколько рядов элементов, вместоalign-itemsначинает действовать свойствоalign-content.
В этом случаеalign-itemsне отключается полностью, а может влиять на отображение флекс-элементов в рядах.
Это происходит, когда мы используем дляalign-contentзначение по умолчанию —stretch. Оно растягивает ряды флекс-элементов, при этом оставшееся свободное место между ними делится поровну.
Отображение строк приalign-content: stretchзависит от значенияalign-items:
- Если у
align-itemsзадано значениеstretch, то элементы в строках растягиваются на всю высоту своей строки. - Если значение отлично от
stretch, то элементы в строках ужимаются под своё содержимое и выравниваются в строках в зависимости от значенияalign-items.
Давайте посмотрим на этот эффект вживую.
align-content: не-stretch и align-items[17/31]
Значениеalign-itemsвлияет на отображение рядов во флекс-контейнере, если уalign-contentзадано значениеstretch. В этом мы убедились в прошлом задании.
Есть ли похожее влияние на остальные значенияalign-content? Нет.
Убедимся в этом на примере значенияcenter, которое располагает ряды в середине поперечной оси так, что:
- отступов между соседними рядами нет (но отступы самих элементов сохраняются),
- расстояние между первым рядом и краем флекс-контейнера равно расстоянию между последним рядом и другим краем.
Остальные значения align-content[18/31]
Остальные четыре значения свойства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и возможность «растягивать» ряды по высоте.
Порядковый номер флекс-элемента, order[19/31]
И ещё одно свойство, которое мы рассмотрим в этом курсе, — этоorder, порядковый номер флекс-элемента.
Это очень полезное свойство, так как с его помощью можно менять порядок следования флекс-элементов в потоке, не меняя HTML-код.
По умолчанию порядковый номер флекс-элементов равен0, а сортировка элементов производится по возрастанию номера.
Порядковый номер задаётся целым числом, положительным или отрицательным. Например:
.flex-element {
order: -1; /* этот элемент станет отображаться первым в контейнере */
}
Давайте попробуем перетасовать коврики с котиками с помощью свойстваorder.
Идеальное центрирование, margin: auto[21/31]
В следующих заданиях мы разберём примеры из жизни, в которых можно применять флексбокс.
Самый насущный вопрос, который можно легко и изящно решить с помощью флексбокса, — как отцентровать элемент по вертикали и горизонтали так, чтобы центровка сохранялась при изменении размеров элемента или контейнера.
Ответ прост: задать контейнеру раскладку флексбокса, а дочернему флекс-элементуmargin: auto.
В этом случае флекс-элемент уменьшит свой размер под содержимое и отцентруется по вертикали и горизонтали.
Стоит обратить внимание на интересный момент. Если центруемых флекс-элементов в контейнере будет несколько, то отступы между ними будут равномерными. То есть будет происходить распределение элементов внутри флекс-контейнера чем-то похожее наjustify-content: space-around.
Давайте проверим этот момент на примере карточки товара, в которой картинка центруется внутри блока.
Идеальное центрирование, флекс-выравнивания[22/31]
А теперь давайте отцентруем элементы с помощью свойств флекс-контейнера безmargin: autoна дочерних элементах.
Заметьте разницу между тем, как распределяются элементы при разных значениях свойстваjustify-content.
«Гибкое» меню[23/31]
Флексбокс полезен при создании блоков с дочерними элементами динамической длины. Хороший пример — меню.
Часто встречаются дизайны, в которых пункты равномерно распределены по блоку меню. Первый пункт примыкает к левой части блока меню, а последний — к правой, причём с небольшими внутренними отступами.
Эту задачу можно попытаться решить, задав фиксированные отступы и ширину пунктам меню. Но такой способ не подойдёт, если количество пунктов меню или подписи внутри них будут изменяться.
И тут на помощь приходит флексбокс. Зададим меню раскладку флексбокса, пункты станут флекс-элементами. С помощью свойства распределения элементовjustify-contentдобьёмся нужного результата.
Вертикальный ряд иконок[26/31]
Давайте используем раскладку флексбокса ещё в одном примере.
Для начала выстроим два блока, идущих друг за другом, в ряд. Затем изменим порядок их отображения.
Заметьте, что флекс-элементами внутри флекс-контейнера становятся только прямые потомки, элементы первого уровня вложенности.
В нашем примере флекс-контейнер.postвключает два флекс-элементаsectionиaside. Блоки внутри флекс-элементов ведут себя как обычно, флекс-поток их не затрагивает.
Сортировка элементов на CSS[29/31]
Интересного эффекта можно достичь, если скомбинировать флексбокс и трюк с селектором:checked ~. Подробно:checked ~разбирается в задании курса «Селекторы. Часть 3».
Приём заключается в следующем: с помощью селектора по выделению чекбокса можно управлять порядком флекс-элементов, изменяя направление главной оси с помощьюflex-direction. Лучше всего эффект работает, когда направление главной оси меняется с «сверху вниз» на «снизу вверх».
При этом флекс-контейнер должен находиться в разметке на одном уровне с чекбоксом.
Таким образом реализуется сортировка на CSS, без использования JavaScript.
Блоки одинаковой высоты[30/31]
Ещё одна часто встречающаяся задача — реализовать раскладку с блоками одинаковой высоты.
Надо учитывать, что содержимое блоков может быть разным и их высота может меняться.
В обычной блочной модели есть фундаментальный недостаток — соседние блоки ничего не знают друг о друге, поэтому их высоты нельзя «связать». Получается, что все «стандартные» варианты для решения этой задачи не работают:
floatилиinline-blockне могут «связывать» высоты соседних блоков;таблицы и CSS-таблицы позволяют делать ячейки одинаковой высоты, но появляются ограничения, связанные с расположением элементов в строках;
минимальная высота не подходит, так как какой-то из блоков всегда может стать выше остальных;
конечно, можно задать всем блокам фиксированную высоту, но это решение совсем не универсальное.
А с помощью флексбоксов эта проблема решается легко и изящно, ведь флекс-элементы по умолчанию растягиваются на всю высоту контейнера.
Попробуем починить раскладку наfloatс помощью флексбокса.
Flex-элемент
Флекс-элементы и блочная модель[1/28]
В предыдущем курсе про флексбоксмы знакомились с базовыми понятиями этого механизма раскладки и подробно изучали, как работает выравнивание флекс-элементов. Ну а этот курс будет посвящён управлению размерами флекс-элементов.
Начнём с простого вопроса. Как работает привычная нам блочная модель внутри флекс-контейнера? Есть ли какие-нибудь отличия в поведении привычных свойств?
Ширина, высота, внутренние отступы и рамки для флекс-контейнеров и флекс-элементов работают как обычно: общий размер элементов складывается из этих компонентов. Это поведение так же можно менять с помощью свойстваbox-sizing.
Есть и несколько важных отличий:
- флекс-элементы, в отличие от блочных элементов, не растягиваются на всю ширину контейнера по умолчанию;
- на флекс-элементы не действует свойство
float.
Теперь поработаем с уже знакомыми свойствами и убедимся, что они работают привычным нам образом.
Особенности свойства margin[2/28]
В предыдущем заданиимы не упомянули про свойствоmargin, ведь оно таит много сюрпризов:
внешние отступы не схлопываются, ни по горизонтали, ни по вертикали;
внешние отступы не выпадают, ни из флекс-контейнера, ни из флекс-элементов;
значение
autoполучило премию журнала Форбс в номинации «Самое влиятельное значение CSS-свойства внутри флекс-контейнера».
Всё дело в механизме распределения свободного места. Если внутри флекс-контейнера есть свободное место, то оно перераспределяется так:
находятся элементы, у которых есть внешние отступы со значением
auto;всё свободное место в соответствующих направлениях отдаётся таким отступам (то есть задаётся определённый размер отступа в пикселях);
если элементов с автоматическими отступами на одном направлении несколько, то место между ними перераспределяется поровну;
только после этого запускаются механизмы выравнивания.
Поэтомуmargin: auto;влияет на положение флекс-элементов на обеих осях, а также «ломает»механизмы выравнивания, ведь выравнивание происходит, когда есть свободное место. Но если всё свободное место «перетекло» в автоматический отступ, то и выравнивать нечего.
Эти особенности можно использовать во благо. Например, с помощью автоматических отступов вы можете управлять расположением элементов вдоль главной оси. Давайте поэкспериментируем.
Выравнивание и внешние отступы[3/28]
В прошлом заданиимы проверили, как автоматический внешний отступ влияет на положение флекс-элементов на главной оси. Кроме того, мы убедились, что такие отступы «ломают» свойствоjustify-content.
Автоматическийmarginвлияет и на выравнивание флекс-элементов вдоль поперечной оси.
Если у флекс-элемента отступ сверху или снизу автоматический, то на него не влияют, ниalign-items, ниalign-self. Такой элемент прижмётся либо к верху контейнера, либо к низу.
А если задать автоматические отступы с противоположных сторон, то элемент разместится по центру флекс-контейнера, так как свободное место «впитается» отступами поровну.
Направление главной оси и внешние отступы[4/28]
Будет ли результат таким, как на картинке снизу, если повернуть главную ось в предыдущем задании?


Нет, не будет!
Дело в том, что «старые нефлексовые» свойства, такие как отступы или размеры, ничего не знают про направление осей. Они «мыслят по-старому», понятиями «верх» и «низ», «право» и «лево».
Поэтому когда главная ось направлена слева направо, горизонтальные отступы перемещают флекс-элементы вдольглавнойоси. Но если направить главную ось сверху вниз, то те же отступы начнут работать вдольпоперечнойоси.
То же относится и к вертикальным отступам.
Давайте повернём ось, а затем внесём правки и получим результат, как на картинке выше.
На момент написания курса в Safari и других WebKit-браузерах есть баг, из-за которого блоки могут позиционироваться некорректно.
Базовый размер флекс-элемента, flex-basis[5/28]
На примере отступов видно, что «старые» свойства внутри флекс-контейнера ведут себя достаточно глупо. Ширина и высота тоже не умеют реагировать на поворот главной оси. Поэтому ввели понятияглавный размерилиmain sizeи поперечный размерилиcross size.
Если главная ось направлена горизонтально, то главный размер — это ширина, свойствоwidth, а поперечный размер — это высота, свойствоheight. Если главная ось направлена вертикально, то всё наоборот.
А хотелось бы иметь «умное» свойство для задания размера флекс-элементов, которое знает про главную ось и «поворачивается» вместе с ней.
И такое свойство есть — этоflex-basis. Оно задаётбазовый размерфлекс-элемента или размер вдоль главной оси.
Еслиflex-basisне задан или его значение равноauto, то базовый размер берётся изwidthилиheight.
Свойствоflex-basisпринимает те же значения, что иwidth/height:
flex-basis: 100px; /* базовый размер 100 пикселей */
flex-basis: 50%; /* базовый размер 50% контейнера */
Свойствоflex-basis«сильнее» свойствwidthиheight, и если у флекс-элемента заданы все три свойства, тоflex-basisпереопределит либо ширину, либо высоту в зависимости от направления главной оси.
Коэффициент растягивания элементов, flex-grow[7/28]
В предыдущем заданиимы кое о чём умолчали. На самом деле, базовый размер — это не просто размер элемента вдоль главной оси, этоначальныйилиисходныйразмер вдоль главной оси.
Почему так важны этиначальныйилиисходный?
И снова всё дело в механизме перераспределения свободного места во флексбоксе.
Если внутри флекс-контейнера по главной оси остаётся свободное место, то мы можем попросить флекс-элемент, чтобы он увеличился и занял это место. Это делается с помощью свойстваflex-grow, которое можно назвать «коэффициентом флекс-жадности» флекс-элемента.
Свойствоflex-growпринимает неотрицательные числовые значения, его значение по умолчанию —0.
Если значениеflex-growравно нулю, то флекс-элемент «не претендует» на оставшееся свободное место во флекс-контейнере и не будет увеличиваться, чтобы занять это место.
Если значениеflex-growбольше нуля, то флекс-элемент будет увеличиваться, «захватывая» оставшееся свободное место.
Получается, что базовый размер — это исходный размер флекс-элементов до примененияflex-grow.
Пропорциональное растягивание элементов[8/28]
Если сразу у нескольких флекс-элементов значениеflex-growбольше нуля, то они будут делить свободное место между собой.
Свободное место будет добавляться флекс-элементам пропорционально значениям их «коэффициента жадности». Например, если во флекс-контейнере есть два элемента:
.element-1 { flex-grow: 1; }
.element-2 { flex-grow: 2; }
То второму элементу достанется в два раза больше свободного места, чем первому. Если изменить значения коэффициентов у этих элементов на такие:
.element-1 { flex-grow: 50; }
.element-2 { flex-grow: 100; }
То ничего не изменится, так как отношение коэффициентов не изменилось: 100 в два раза больше 50. То есть важно не само значение коэффициента, а его соотношение с коэффициентами остальных элементов.
Это задание-загадка на подбор пропорций. Вам нужно подобрать такие значенияflex-grow, чтобы итоговый размер элементов оказался таким же, как и у «линеек» снизу. Базовые размеры элементов и размеры флекс-контейнера вы узнаете из кода.
Сейчас поэкспериментируйте самостоятельно, а в следующем задании мы детально разберём алгоритм расчёта итогового размера флекс-элементов с ненулевымиflex-grow.
Подсказка: в простейшем решении коэффициенты будут целыми числами не больше 5.
Расчёт итогового размера с flex-grow[9/28]
1 шаг. Рассчитываем свободное место во флекс-контейнере:
Свободное место = Ширина контейнера - Сумма базовых размеров элементов
2 шаг. Считаем размер минимальной доли свободного места:
Доля свободного места = Свободное место / Сумма flex-grow всех элементов
3 шаг. Базовый размер каждого флекс-элемента увеличиваем на размер минимальной доли свободного места умноженной на значениеflex-growэтого элемента:
Итоговый размер = Базовый размер + (Доля свободного места * flex-grow)
Для верхнего блока с енотами хочется задать коэффициенты1и2. Но нужные размеры блоков получаются с коэффициентами1и3. Давайте посчитаем:
Свободное место = 300px - (50px * 2) = 200px
Доля свободного места = 200px / (1 + 3) = 50px
Итоговый размер зелёного енота = 50px + (50px * 1) = 100px
Итоговый размер коричневого енота = 50px + (50px * 3) = 200px
Но если задать флекс-элементам нулевой базовый размер, свободное место будет занимать всю ширину флекс-контейнера, и коэффициенты жадности будут другими.
Использоватьflex-basis: 0иflex-growдля точного управления относительными размерами не стоит. Лучше использовать базовый размер в процентах.
Тонкость.На размер оставшегося свободного места влияет не толькоflex-basis, но и рамки, и отступы. Еслиflex-basisявно задано нулевое значение, тоmin-widthна размер свободного места влиять не будет, так как ограничения размеров к флекс-элементам применяются уже после перераспределения свободного места.
Коэффициент сжатия элементов, flex-shrink[10/28]
Если сумма базовых размеров флекс-элементов больше, чем размер флекс-контейнера, то возникаетотрицательное пространство.
Механизм перераспределения работает не только для свободного места, но и для отрицательного пространства. Флекс-элементы умеют распределять отрицательное пространство между собой и сжиматься.
За уменьшение флекс-элементов отвечает свойствоflex-shrink, которое можно назвать «коэффициентом сжатия».
Свойствоflex-shrinkпринимает неотрицательные числовые значения, его значение по умолчанию —1.
Если значениеflex-shrinkбольше нуля, то флекс-элемент будет уменьшаться, «впитывая» часть отрицательного пространства, если оно существует.
Если значениеflex-shrinkравно нулю, то флекс-элемент уменьшаться не будет.
Флекс-элементы стараются быть максимально «гибкими» и не выпадать из своего контейнера, поэтому уflex-shrinkзначение по умолчанию равно1. Но если задавать нулевые значения для коэффициента сжатия, то выпадения элементов добиться можно.
Пропорциональное сжатие элементов[11/28]
Свойствоflex-shrinkочень похоже на свойствоflex-grow. Оно задаёт пропорции, в которых флекс-элементы «впитывают» отрицательное пространство.
Чем больше значение коэффициента сжатия у элемента, тем больше отрицательного пространства он «впитает» и тем сильнее сожмётся.
Когда базовые размеры флекс-элементоводинаковы, пропорции сжатия элементов считаются так же, как пропорции увеличения. Если базовые размеры флекс-элементов отличаются, то механизм усложняется. Подробно мы разберём его в следующем задании.
А пока снова поэкспериментируйте с коэффицентами в задании-загадке.
Вам нужно подобрать такие значенияflex-shrink, чтобы итоговый размер элементов оказался таким же, как у коричневой и зелёной «линеек», и чтобы над красной «линейкой» ничего не было.
На красной линейке показан размер отрицательного пространства, которое распределяется при сжатии флекс-элементов.
Базовые размеры элементов и размеры флекс-контейнера вы узнаете из кода.
Подсказка: в простейшем решении коэффициенты будут целыми числами не больше 5.
Расчёт итогового размера с flex-shrink[12/28]
Ниже описан механизм расчёта размеров элементов, когда места в контейнере не хватает:
1 шаг.Рассчитываем отрицательное пространство (ОП) во флекс-контейнере:
ОП = Ширина контейнера - Сумма базовых размеров элементов
2 шаг.Находим сумму произведений базовых размеров (СПБР) элементов на их коэффициенты сжатия:
СПБР = (Базовый размер1 * flex-shrink1) + (Базовый размер2 * flex-shrink2) + … + (Базовый размерn * flex-shrinkn)
3 шаг.Для каждого элемента считаем «нормированный коэффициент сжатия» (НКС), для чего произведение базового размера элемента на его коэффициент сжатия делим на СПБР:
НКС = (Базовый размер * flex-shrink) / СПБР
4 шаг.Базовый размер элемента уменьшаем на часть ОП пропорциональную НКС элемента:
Итоговый размер = Базовый размер - (НКС * ОП)
Получается, что доля отрицательного пространства, которую «впитает» элемент, зависит от двух факторов:
- соотношения коэффициента сжатия элемента с коэффициентами других элементов,
- соотношения базового размера элемента с базовыми размерами других элементов.
Именно поэтому в формулах присутствуют нормировки. А теперь снова попробуйте подобрать коэффициенты сжатия.
flex-shrink и min-width[13/28]
Решение предыдущего задания: коэффициенты должны быть1и1
Давайте рассчитаем размеры элементов из предыдущего заданияи убедимся в правильности описанного алгоритма.
Отрицательное пространство = 200px - 100px - 300px = -200px
Сумма произведений размеров на коэффициенты = (1 * 100px) + (1 * 300px) = 400px
Нормированный коэффициент 1 элемента = (1 * 100px) / 400px = 0.25
Нормированный коэффициент 2 элемента = (1 * 300px) / 400px = 0.75
Итоговый размер 1 элемента = 100px - (200px * 0.25) = 50px
Итоговый размер 2 элемента = 300px - (200px * 0.75) = 150px
Есть несколько тонкостей, касающихся сжатия флекс-элементов:
- элементы сжимаются в пределах своих базовых размеров, внутренние отступы и рамки не сжимаются;
- «ограничительные» свойства, такие как
min-width, применяются к элементам после этапа перераспределения свободного места или отрицательного пространства.
И эти тонкости могут приводить к неожиданным эффектам, когда элементы выпадают из флекс-контейнера. Давайте поэкспериментируем.
Сокращённое свойство flex[15/28]
С помощью сокращённого свойстваflexможно одновременно задать коэффициенты растягивания, сжатия и базовый размер флекс-элемента.
Свойствоflexсостоит из трёх компонентов, которые пишутся через пробел в следующем порядке:flex-grow,flex-shrinkиflex-basis. В примере ниже два правила аналогичны:
.flex-item {
flex: 1 2 300px;
}
.flex-item {
flex-grow: 1;
flex-shrink: 2;
flex-basis: 300px;
}
Ещё у свойстваflexесть особые значения:initial,auto,none. Также второй и третий компоненты необязательны. Ниже показаны различные значения свойства и их расшифровки.
flex: initial; -> flex: 0 1 auto;
flex: auto; -> flex: 1 1 auto;
flex: none; -> flex: 0 0 auto;
flex: 1 0; -> flex: 1 0 0%;
flex: 1; -> flex: 1 1 0%;
В некоторых браузерах неполные или особенные значения свойстваflexинтерпретируются с ошибками. Поэтому лучше задавать все три компоненты в значении этого свойства.
Многострочный флекс-контейнер и flex-shrink[16/28]
Во всех примерах, рассмотренных раньше, флекс-контейнер был однострочным, ведь перенос флекс-элементов на новую строку по умолчанию запрещён — работаетflex-wrap: nowrap;.
А как будут растягиваться и сжиматься элементы в многострочном контейнере, сflex-wrap: wrap;?
В таком контейнере свойствоflex-shrinkбудет работать как обычно, но необходимость в нём будет возникать намного реже. Ведь при нехватке места в строке флекс-элементы будут переноситься на новую строку.
Но если появятся флекс-элементы, базовый размер которых больше размера флекс-контейнера, то такие элементы будут сжиматься и занимать целую строку. Наверное, это единственный случай, когдаflex-shrinkделает что-то полезное в многострочном контейнере.
flex-basis: 100% и flex-wrap[18/28]
Познакомимся с интересным эффектом, который возникает при использовании базовых размеров в процентах.
Если задать базовый размер флекс-элемента100%и при этом включить перенос элементов на новую строку, то элементы расположатся столбцом, хотя главная ось контейнера будет по-прежнему направлена слева направо.
Заголовок с описанием на флексбоксах[19/28]
Мы рассмотрели теоретическую часть и приступаем к практической части этого курса. Давайте разберём на реальных элементах интерфейсов, в каких случаях бывает уместно использовать флексбокс.
Довольно распространённый ход в интерфейсе — блок с заголовком и небольшим уточняющим подзаголовком на одной строке. Заголовок находится в начале строки, а подзаголовок прижат к правому краю.
Если текст заголовка или подзаголовка сильно увеличится, то вёрстка не должна ломаться — тексты просто должны расположиться друг под другом.
Сверстать элемент с таким гибким поведением с помощьюfloatилиdisplay: tableне получится. Ведь нужно, чтоб блоки подписей одновременно и занимали свободное пространство, и чтобы их размеры зависели от текстового содержания, и чтобы в случае переполнения сетка перестраивалась.
Здесь нам поможет только флексбокс сflex-grow.
Для наглядности зададим текстовым блокам фоновый цвет и рамку, а в следующем задании уберём их.
«Гибкое» меню с переполнением[21/28]
А теперь давайте создадим ещё одно «гибкое» меню, похожее на то, что мы делали в задании прошлого курса.
Напомним, что в прошлом варианте пункты равномерно распределялись внутри контейнера меню с помощьюjustify-content: space-around.
Новый вариант меню будет более адаптивным: пункты меню будут переноситься на следующую строку, если места будет не хватать. А ещё для достижения красивой симметрии пункты будут растягиваться, чтобы занимать весь контейнер меню. И снова нам поможетflex-grow.
Создадим базовую раскладку и зададим перенос строк.
Поля ввода с динамической шириной[23/28]
Ещё один случай, когда может пригодиться флексбокс — поля ввода с динамической шириной. Требования к ним такие:
- На одной строке с полем могут находиться другие элементы: кнопки, ссылки, подписи.
- Размер дополнительных элементов не определён, он зависит от их содержимого.
- При этом поле должно растягиваться на всё оставшееся в родительском контейнере место.
- И изменять ширину при изменении размеров контейнера.
Решить эту задачу можно только при помощи флексбокса. Превратим контейнер поля ввода во флекс-контейнер, все элементы внутри него превратятся во флекс-элементы, базовый размер которых будет зависеть от их содержания —flex-basis: auto;. И останется только задать ненулевой коэффициент растягивания полям ввода.
В широком контейнере всё будет работать отлично. Проблемы могут появиться в слишком узких контейнерах: по умолчанию поля ввода не будут сжиматься после определённой ширины, что приведёт к выпаданию текста из остальных элементов.
Чтобы справиться с этими проблемами, надо задать всем элементам кроме полей ввода нулевой коэффициент сжатия, а самим полям ввода явно прописать минимальную ширину.
В этом задании в селекторах используется псевдокласс:not, который разбирается в курсе«Селекторы. Часть 2».
На момент написания курса в Safari и других WebKit-браузерах есть баг, из-за которого блоки могут позиционироваться некорректно.
Карточка курса[24/28]
Теперь давайте соберём на флексбоксе интерфейс с карточками курсов.
Флексбокс нужен, чтобы сделать этот блок адаптивным. Вы увидите, как гибко он адаптируется в следующих заданиях.
Начнём работу с отдельной карточки. Сделаем карточку флекс-контейнером и направим её главную ось сверху вниз. Это необходимо, чтобы в дальнейшем гибко управлять внутренними блоками карточки.
Напомним, что флекс-элементы могут одновременно быть и флекс-контейнерами. Мы превратим блок с мета-информацией в флекс-контейнер, чтобы расположить блоки с тегами и временем чтения.