Узнаем как управлять размерами и отступами флекс-элементов и как работают коэффициенты растяжения и сжатия, а также потренируемся создавать «гибкие» раскладки и элементы интерфейса.
В предыдущем курсе про флексбокс мы знакомились с базовыми понятиями этого механизма раскладки и подробно изучали, как работает выравнивание флекс-элементов. Ну а этот курс будет посвящён управлению размерами флекс-элементов.
Начнём с простого вопроса. Как работает привычная нам блочная модель внутри флекс-контейнера? Есть ли какие-нибудь отличия в поведении привычных свойств?
Ширина, высота, внутренние отступы и рамки для флекс-контейнеров и флекс-элементов работают как обычно: общий размер элементов складывается из этих компонентов. Это поведение так же можно менять с помощью свойства box-sizing.
Есть и несколько важных отличий:
float.Теперь поработаем с уже знакомыми свойствами и убедимся, что они работают привычным нам образом.
.skate, на которых сидят еноты, ширину 75px и высоту 300px (минимальные размеры изменять не нужно),10px.box-sizing: border-box.В предыдущем задании мы не упомянули про свойство margin, ведь оно таит много сюрпризов:
внешние отступы не схлопываются, ни по горизонтали, ни по вертикали;
внешние отступы не выпадают, ни из флекс-контейнера, ни из флекс-элементов;
значение auto получило премию журнала Форбс в номинации «Самое влиятельное значение CSS-свойства внутри флекс-контейнера».
Всё дело в механизме распределения свободного места. Если внутри флекс-контейнера есть свободное место, то оно перераспределяется так:
находятся элементы, у которых есть внешние отступы со значением auto;
всё свободное место в соответствующих направлениях отдаётся таким отступам (то есть задаётся определённый размер отступа в пикселях);
если элементов с автоматическими отступами на одном направлении несколько, то место между ними перераспределяется поровну;
только после этого запускаются механизмы выравнивания.
Поэтому margin: auto; влияет на положение флекс-элементов на обеих осях, а также «ломает» механизмы выравнивания, ведь выравнивание происходит, когда есть свободное место. Но если всё свободное место «перетекло» в автоматический отступ, то и выравнивать нечего.
Эти особенности можно использовать во благо. Например, с помощью автоматических отступов вы можете управлять расположением элементов вдоль главной оси. Давайте поэкспериментируем.
.skate внешние отступы со всех сторон 10px.margin-left: auto; второму скейту,margin-right: auto; четвёртому скейту..spot распределение по главной оси на flex-end и убедитесь, что ничего не изменилось
.В прошлом задании мы проверили, как автоматический внешний отступ влияет на положение флекс-элементов на главной оси. Кроме того, мы убедились, что такие отступы «ломают» свойство justify-content.
Автоматический margin влияет и на выравнивание флекс-элементов вдоль поперечной оси.
Если у флекс-элемента отступ сверху или снизу автоматический, то на него не влияют, ни align-items, ни align-self. Такой элемент прижмётся либо к верху контейнера, либо к низу.
А если задать автоматические отступы с противоположных сторон, то элемент разместится по центру флекс-контейнера, так как свободное место «впитается» отступами поровну.
.spot выравнивание флекс-элементов вдоль поперечной оси на stretch.margin-top: auto; второму скейту.margin-bottom: auto;.Будет ли результат таким, как на картинке снизу, если повернуть главную ось в предыдущем задании?
Нет, не будет!
Дело в том, что «старые нефлексовые» свойства, такие как отступы или размеры, ничего не знают про направление осей. Они «мыслят по-старому», понятиями «верх» и «низ», «право» и «лево».
Поэтому когда главная ось направлена слева направо, горизонтальные отступы перемещают флекс-элементы вдоль главной оси. Но если направить главную ось сверху вниз, то те же отступы начнут работать вдоль поперечной оси.
То же относится и к вертикальным отступам.
Давайте повернём ось, а затем внесём правки и получим результат, как на картинке выше.
На момент написания курса в Safari и других WebKit-браузерах есть баг, из-за которого блоки могут позиционироваться некорректно.
.spot направление главной оси на column.margin-top и добавьте свойство margin-left: auto;.margin-bottom и добавьте свойство margin-right: auto;.На примере отступов видно, что «старые» свойства внутри флекс-контейнера ведут себя достаточно глупо. Ширина и высота тоже не умеют реагировать на поворот главной оси. Поэтому ввели понятия главный размер или 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 переопределит либо ширину, либо высоту в зависимости от направления главной оси.
.racoon-orange задайте ширину 300px и высоту 100px.100%..spot на column. Смотрите, как ширина и высота меняются при повороте оси из-за заданного базового размера.
Итак, пришла пора проверить знания.
В этом испытании вам предстоит расположить блоки на палитре в нужном порядке. Задача — подобрать размеры элементов и их внешние отступы.
Обратите внимание, что HTML-код изменять нельзя, и в этом коде заблокированы свойства для выравнивания флекс-элементов. Поэтому выравнивать придётся по-другому.
Подсказка: размеры и неавтоматические отступы кратны 5.
В предыдущем задании мы кое о чём умолчали. На самом деле, базовый размер — это не просто размер элемента вдоль главной оси, это начальный или исходный размер вдоль главной оси.
Почему так важны эти начальный или исходный?
И снова всё дело в механизме перераспределения свободного места во флексбоксе.
Если внутри флекс-контейнера по главной оси остаётся свободное место, то мы можем попросить флекс-элемент, чтобы он увеличился и занял это место. Это делается с помощью свойства flex-grow, которое можно назвать «коэффициентом флекс-жадности» флекс-элемента.
Свойство flex-grow принимает неотрицательные числовые значения, его значение по умолчанию — 0.
Если значение flex-grow равно нулю, то флекс-элемент «не претендует» на оставшееся свободное место во флекс-контейнере и не будет увеличиваться, чтобы занять это место.
Если значение flex-grow больше нуля, то флекс-элемент будет увеличиваться, «захватывая» оставшееся свободное место.
Получается, что базовый размер — это исходный размер флекс-элементов до применения flex-grow.
Задайте коэффициент растягивания flex-grow равный 1:
.racoon-green.racoon-orange.Если сразу у нескольких флекс-элементов значение 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.
.spot-1 значения flex-grow так, чтобы их ширина стала равной ширине «линеек»..spot-2.В этом задании можно менять только значения flex-grow.
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 на размер свободного места влиять не будет, так как ограничения размеров к флекс-элементам применяются уже после перераспределения свободного места.
.spot-1 значения flex-grow так, чтобы их ширина стала равной ширине «линеек»..spot-2.В этом задании можно менять только значения flex-grow.
Если сумма базовых размеров флекс-элементов больше, чем размер флекс-контейнера, то возникает отрицательное пространство.
Механизм перераспределения работает не только для свободного места, но и для отрицательного пространства. Флекс-элементы умеют распределять отрицательное пространство между собой и сжиматься.
За уменьшение флекс-элементов отвечает свойство flex-shrink, которое можно назвать «коффициентом сжатия».
Свойство flex-shrink принимает неотрицательные числовые значения, его значение по умолчанию — 1.
Если значение flex-shrink больше нуля, то флекс-элемент будет уменьшаться, «впитывая» часть отрицательного пространства, если оно существует.
Если значение flex-shrink равно нулю, то флекс-элемент уменьшаться не будет.
Флекс-элементы стараются быть максимально «гибкими» и не выпадать из своего контейнера, поэтому у flex-shrink значение по умолчанию равно 1. Но если задавать нулевые значения для коэффициента сжатия, то выпадения элементов добиться можно.
.spot-1 .skate задайте базовый размер флекс-элементов 300px..racoon-brownСвойство flex-shrink очень похоже на свойство flex-grow. Оно задаёт пропорции, в которых флекс-элементы «впитывают» отрицательное пространство.
Чем больше значение коэффициента сжатия у элемента, тем больше отрицательного пространства он «впитает» и тем сильнее сожмётся.
Когда базовые размеры флекс-элементов одинаковы, пропорции сжатия элементов считаются так же, как пропорции увеличения. Если базовые размеры флекс-элементов отличаются, то механизм усложняется. Подробно мы разберём его в следующем задании.
А пока снова поэкспериментируйте с коэффицентами в задании-загадке.
Вам нужно подобрать такие значения flex-shrink, чтобы итоговый размер элементов оказался таким же, как у коричневой и зелёной «линеек», и чтобы над красной «линейкой» ничего не было.
На красной линейке показан размер отрицательного пространства, которое распределяется при сжатии флекс-элементов.
Базовые размеры элементов и размеры флекс-контейнера вы узнаете из кода.
Подсказка: в простейшем решении коэффициенты будут целыми числами не больше 5.
flex-shrink так, чтобы их ширина стала равной ширине «линеек».В этом задании можно менять только значения flex-shrink.
Ниже описан механизм расчёта размеров элементов, когда места в контейнере не хватает:
1 шаг. Рассчитываем отрицательное пространство (ОП) во флекс-контейнере:
ОП = Ширина контейнера - Сумма базовых размеров элементов
2 шаг. Находим сумму произведений базовых размеров (СПБР) элементов на их коэффициенты сжатия:
СПБР = (Базовый размер1 * flex-shrink1) + (Базовый размер2 * flex-shrink2) + … + (Базовый размерn * flex-shrinkn)
3 шаг. Для каждого элемента считаем «нормированный коэффициент сжатия» (НКС), для чего произведение базового размера элемента на его коэффициент сжатия делим на СПБР:
НКС = (Базовый размер * flex-shrink) / СПБР
4 шаг. Базовый размер элемента уменьшаем на часть ОП пропорциональную НКС элемента:
Итоговый размер = Базовый размер - (НКС * ОП)
Получается, что доля отрицательного пространства, которую «впитает» элемент, зависит от двух факторов:
Именно поэтому в формулах присутствуют нормировки. А теперь снова попробуйте подобрать коэффициенты сжатия.
flex-shrink так, чтобы их ширина стала равной ширине «линеек».В этом задании можно менять только значения flex-shrink.
Решение предыдущего задания: коэффициенты должны быть 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, применяются к элементам после этапа перераспределения свободного места или отрицательного пространства.И эти тонкости могут приводить к неожиданным эффектам, когда элементы выпадают из флекс-контейнера. Давайте поэкспериментируем.
.racoon-brown задайте нулевой коэффициент сжатия..racoon-green задайте минимальную ширину 50px25px.По многочисленным просьбам фанатов заданий на подбор коэффициентов мы создали это испытание, в котором вы снова сможете насладиться математикой и подсчётом дробей.
В заблокированном HTML-коде заданы базовые размеры блоков, которые вам изменять нельзя. Но отталкиваясь от этих размеров, вы можете понять, в каком блоке использовать коэффициенты растяжения, а в каком — коэффициенты сжатия. И, конечно, подобрать значения коэффициентов.
Подсказка: итоговые размеры блоков кратны 50, а коэффициенты — небольшие целые числа.
С помощью сокращённого свойства 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 задайте всем скейтбордам .skate коэффициент растягивания 0, коэффициент сжатия 1, базовый размер 200px.1, коэффициент сжатия 0, базовый размер 200px,2.Во всех примерах, рассмотренных раньше, флекс-контейнер был однострочным, ведь перенос флекс-элементов на новую строку по умолчанию запрещён — работает flex-wrap: nowrap;.
А как будут растягиваться и сжиматься элементы в многострочном контейнере, с flex-wrap: wrap;?
В таком контейнере свойство flex-shrink будет работать как обычно, но необходимость в нём будет возникать намного реже. Ведь при нехватке места в строке флекс-элементы будут переноситься на новую строку.
Но если появятся флекс-элементы, базовый размер которых больше размера флекс-контейнера, то такие элементы будут сжиматься и занимать целую строку. Наверное, это единственный случай, когда flex-shrink делает что-то полезное в многострочном контейнере.
500px..spot.В отличие от flex-shrink, свойство flex-grow в многострочном флекс-контейнере срабатывает намного чаще и пользы приносит намного больше.
В каждой строке такого контейнера может быть свободное место и механизм перераспределения этого места работает построчно.
Поэтому возможность «растянуть» флекс-элементы, чтобы строки заполнялись по ширине полностью, будет возникать достаточно часто.
.spot последним скейт с Зелёным Енотом — див с классами skate и racoon-green..spot задайте перенос флекс-элементов на новую строку,1.skate и racoon-brown.Познакомимся с интересным эффектом, который возникает при использовании базовых размеров в процентах.
Если задать базовый размер флекс-элемента 100% и при этом включить перенос элементов на новую строку, то элементы расположатся столбцом, хотя главная ось контейнера будет по-прежнему направлена слева направо.
Поэкспериментируем.
100%,.spot задайте перенос флекс-элементов на новую строку.Мы рассмотрели теоретическую часть и приступаем к практической части этого курса. Давайте разберём на реальных элементах интерфейсов, в каких случаях бывает уместно использовать флексбокс.
Довольно распространённый ход в интерфейсе — блок с заголовком и небольшим уточняющим подзаголовком на одной строке. Заголовок находится в начале строки, а подзаголовок прижат к правому краю.
Если текст заголовка или подзаголовка сильно увеличится, то вёрстка не должна ломаться — тексты просто должны расположиться друг под другом.
Сверстать элемент с таким гибким поведением с помощью float или display: table не получится. Ведь нужно, чтоб блоки подписей одновременно и занимали свободное пространство, и чтобы их размеры зависели от текстового содержания, и чтобы в случае переполнения сетка перестраивалась.
Здесь нам поможет только флексбокс с flex-grow.
Для наглядности зададим текстовым блокам фоновый цвет и рамку, а в следующем задании уберём их.
.card-title задайте фоновый цвет #c8dcff и сплошную рамку толщиной 1px и цветом #999999..card-title задайте раскладку флексбокса.card-title-main задайте коэффициент растягивания 1.А теперь давайте проверим, как сработает наша раскладка, если текста станет немного больше.
На случай «переполнения» зададим контейнеру перенос флекс-элементов на новую строку.
Кекс любит флекс на Инструктор Кекс и удивительный флекс,.card-title задайте перенос флекс-элементов на новую строку..card-title рамку и фоновый цвет.А теперь давайте создадим ещё одно «гибкое» меню, похожее на то, что мы делали в задании прошлого курса.
Напомним, что в прошлом варианте пункты равномерно распределялись внутри контейнера меню с помощью justify-content: space-around.
Новый вариант меню будет более адаптивным: пункты меню будут переноситься на следующую строку, если места будет не хватать. А ещё для достижении красивой симметрии пункты будут растягиваться, чтобы занимать весь контейнер меню. И снова нам поможет flex-grow.
Создадим базовую раскладку и зададим перенос строк.
.menu задайте раскладку флексбокса,Акула.Теперь остаётся задать элементам меню коэффициент растяжения и проверить, как будет вести себя меню, если мы решим изменить его ширину, либо добавить пункты.
Получившееся решение удобно применять для адаптации к мобильным интерфейсам. При этом даже не потребуется добавлять дополнительные стили для мобильных вьюпортов.
.menu задайте коэффициент растягивания 1,Сом..menu ширину 300px,200px.Ещё один случай, когда может пригодиться флексбокс — поля ввода с динамической шириной. Требования к ним такие:
Решить эту задачу можно только при помощи флексбокса. Превратим контейнер поля ввода во флекс-контейнер, все элементы внутри него превратятся во флекс-элементы, базовый размер которых будет зависеть от их содержания — flex-basis: auto;. И останется только задать ненулевой коэффициент растягивания полям ввода.
В широком контейнере всё будет работать отлично. Проблемы могут появиться в слишком узких контейнерах: по умолчанию поля ввода не будут сжиматься после определённой ширины, что приведёт к выпаданию текста из остальных элементов.
Чтобы справиться с этими проблемами, надо задать всем элементам кроме полей ввода нулевой коэффициент сжатия, а самим полям ввода явно прописать минимальную ширину.
В этом задании в селекторах используется псевдокласс :not, который разбирается в курсе «Селекторы. Часть 2».
На момент написания курса в Safari и других WebKit-браузерах есть баг, из-за которого блоки могут позиционироваться некорректно.
.input-container задайте раскладку флексбокса,.input задайте коэффициент растягивания 1..input-container до 200px,.add-on задайте нулевой коэффициент сжатия,.input задайте минимальную ширину 50px.Теперь давайте соберём на флексбоксе интерфейс с карточками курсов.
Флексбокс нужен, чтобы сделать этот блок адаптивным. Вы увидите, как гибко он адаптируется в следующих заданиях.
Начнём работу с отдельной карточки. Сделаем карточку флекс-контейнером и направим её главную ось сверху вниз. Это необходимо, чтобы в дальшнейшем гибко управлять внутренними блоками карточки.
Напомним, что флекс-элементы могут одновременно быть и флекс-контейнерами. Мы превратим блок с мета-информацией в флекс-контейнер, чтобы расположить блоки с тегами и временем чтения.
.card задайте раскладку флексбокса,.card-meta,.card-category задайте коэффициент растягивания 1.Пришло время добавить вторую карточку. Её код уже есть в разметке.
Для управления раскладкой карточек превратим их родительский блок в флекс-контейнер.
И теперь уже карточки стали одновременно и флекс-элементами, и флекс-контейнерами.
.cards задайте раскладку флексбокса,.card задайте внешний отступ 10px.Карточки выстроились в один ряд и теперь их высота одинакова. Это произошло потому, что их родительский элемент — флекс-контейнер с поперечным выравниванием stretch.
Сейчас мы сделаем так, чтобы кнопки «Пройти курс» выравнивались по нижнему краю карточки. Для этого:
.card-content положительный коэффициент растяжения, чтобы он занял всё свободное место в карточке..card-content в флекс-контейнер с главной осью, направленной сверху вниз..card-content.Вспомните, как на первом шаге мы сделали карточки флекс-контейнерами. Без этого нельзя было бы растянуть вложенные блоки «в высоту» с помощью flex-grow.
.card-content задайте коэффициент растягивания 1,.card-button задайте внешний отступ сверху auto.На последнем шаге мы поработаем с раскладкой карточек.
Сделаем так, чтобы карточки переносились на новую строку, если им не хватает места в контейнере. А если свободное место на строке осталось, то карточки будут его занимать.
А чтобы было видно, как будут вести себя несколько карточек, мы добавили специальную обёртку с зумом.
.cards..card удалите максимальную ширину, задайте ей базовый размер 300px1..cards до 700px. Обратите внимание, как перестроятся карточки.Теперь вы знаете достаточно, чтобы пройти финальное испытание.
В нём снова нужно создать гибкую раскладку, но на этот раз задача усложнилась. Теперь блоков стало больше, они расположены не в один ряд и у них разные размеры.
Вам понадобится подобрать базовые размеры, отступы, некоторые коэффициенты и пару других флексовых свойств.
Подсказка: как всегда отступы и базовые размеры (до перераспределения свободного места) кратны 5.
До встречи на следующих курсах. Продолжение следует!