Работаем с Flexbox: flex-grow

Работаем с Flexbox: flex-grow

Больше вкусностей найдешь на моем канале - https://t.me/emotional_robot


В предыдущей статье мы разобрались со свойствами CSS, отвечающими за работу с flex-контейнером. В основном они позволяют позиционировать элементы различными способами. Но мы можем работать с самими flex-элементами напрямую, задавая им особое поведение внутри контейнера.

Этих свойств меньше, чем у flex-контейнера, и два из них совсем простые: "order", отвечающий за порядковый номер элемента, и "align-self", который переопределяет расположение конкретного элемента внутри контейнера (подробнее о всех свойствах здесь). Остальные свойства не так просто понять, поэтому мы их разберем по отдельности, и начнем со свойства "flex-grow".

Напоминаю, что все примеры я складываю в личном репозитории на GitHub. Спуливайте последние изменения и заходите в папку "src/flexbox-layout-examples/flex-grow". Сейчас потихоньку пройдемся по всем файлам. Как обычно, результат работы можно посмотреть, открыв в браузере файл "index.html".

Flex-grow


Настоящую мощь Flexbox открываешь для себя при использовании свойств для flex-элементов, одним из которых является flex-grow. Это свойство отвечает за расширение элемента внутри контейнера согласно определенному алгоритму.

Давайте откроем файл "index.html" в браузере и попробуем уменьшить окно по ширине до максимально возможного. Обратите внимание на область с числами:

Они показывают размер двух элементов внутри flex-контейнера в зависимости от размеров окна браузера. Давайте посмотрим на код. Откройте файл "index.html" и найдите блок между <body> и <script> (на код внутри <script> не смотрите, это JavaScript, он пока нам не интересен).

В этом блоке добавлено два элемента: section и aside, ниже них расположен список, который мы видим на скриншоте выше, и ссылка на следующий пример <a>. Мы хотим разобраться, что творится, собственно, с section и aside при изменении размеров окна браузера.

Откройте файл "style.css" и посмотрите на свойства. У нас есть flex-контейнер с максимальной шириной 900 пикселей, и два элемента с разными значениями flex-grow: 2 для section и 1 для aside. Сложив два и два (стили и результат в браузере) можно подумать, что flex-grow работает по такому принципу: во сколько раз больше flex-grow одного элемента, во столько раз будет больше сам элемент. И такой принцип вроде как работает в первом примере: ширина section всегда в два раза больше ширины aside, как бы мы ни меняли размер окна. Это главная ошибка при знакомстве с flex-grow - такое поведение справедливо только для пустых элементов (не содержащих никакого контента, даже текста). Однако, когда в них появляется контент, стройная теория о flex-grow мгновенно разрушается.

Откройте файл "1.html" в браузере и проведите те же манипуляции. Теперь откройте файл "1.css". Заметили, что несмотря на те же значения flex-grow, что и в предыдущем примере, размер aside теперь всегда больше, чем section? Делаем вывод, что flex-grow работает по-другому. Давайте разбираться.

Как работает flex-grow на самом деле


Когда мы применим "display: flex" для родительского элемента и ничего больше не поменяем, то дочерние элементы встанут горизонтально, не смотря ни на что. Если будет недостаточно места, то они сократятся в размере. С другой стороны, если будет слишком много места, то они не будут расти, потому что Flexbox хочет, чтобы мы определили, на какое значение им нужно вырасти. Таким образом, прежде, чем указывать браузеру, каким по ширине должен быть элемент, flex-grow определяет, как оставшееся место распределяется среди flex-элементов и насколько велика доля каждого из них.

Flex-контейнер распределяет свободное место своим элементам, пропорционально их flex-grow фактору.

Давайте рассмотрим наглядный пример. Когда мы создали flex-контейнер, все его элементы расположатся в одну строку без переносов. Если суммарная длина элементов меньше длины контейнера, у нас останется свободное пространство:

Далее, мы решаем, сколько частей свободного места получит каждый элемент. В нашем предыдущем примере первый элемент получил 2/3 оставшегося места - flex-grow: 2, а второй элемент 1/3flex-box: 1. Зная, сколько flex-grow значений будет в сумме (в нашем случае 2 + 1 = 3), мы будем знать, на какое число делить оставшееся место:

Теперь у нас есть количество распределяющихся частей. Каждый элемент получает соответствующее количество частей, основываясь на его flex-grow значении:

Математически это будет выглядеть следующим образом (числа взяты с потолка, нам нужно понять алгоритм вычислений):

1) У нас есть четыре величины, необходимые для вычислений:

  1. Ширина родителя: 900px;
  2. Ширина секции: 99px;
  3. Ширина бокового элемента: 623px;
  4. Общее количество flex-grow значений: 3;

2) Рассчитываем оставшееся место: 900 — 99 — 623 = 178.

3) Делим это число на сумму flex-grow: 178 / 3 = 59.33.

4) Вычисляем размер частей, которые должны добавиться к section и aside:

  1. section: 59.33 * 2 = 118.66 ~ 119
  2. aside: 59.33 * 1 = 59.33 ~ 59

5) Складываем полученные значения с размерами section и aside:

  1. section: 99 + 119 = 218
  2. aside: 623 + 59 = 682

Вот таким хитрым способом работает flex-grow. Пару раз проведёте подобные манипуляции - и, считайте, понимание flex-grow у вас в кармане. Я предлагаю вам проверить этот алгоритм на самом первом примере (который находится в "index.html" и "style.css") и убедиться в его правильности даже для пустых элементов (то бишь, ширина section и aside равна нулю).

flex-grow и flex-basis


Как вы поняли, важной частью алгоритма распределения оставшегося места в контейнере является размер элемента. Его можно задать явно, например, с помощью свойства "width". Но что делать, если нет оставшегося места или мы не хотим полагаться на изначальную ширину элемента, но значение flex-grow надо выставить?

Для решения этой задачи существует свойство "flex-basis". Оно определяет изначальный размер элемента. Иначе говоря, свойство "flex-basis" устанавливает flex основу: изначальный главный размер flex-элемента, перед тем как свободное пространство будет распределено в соответствии с flex факторами.

Откройте файл "2.html" в браузере и посмотрите на результат. Вся разница с предыдущим примером только в том, что section и aside получили flex-basis свойство (смотрите файл "2.css"): у section это 400 пикселей, у aside - 200 пикселей. Из-за этого свойства алгоритм вычисления оставшегося места изменился - вместо реальных размеров элементов за основу берется flex-basis:

  1. Рассчитываем оставшееся место: 900 - 400 - 200 = 300.
  2. Определяем ширину одной свободной части по flex-grow: 300 / 3= 100.
  3. Распределяем оставшееся место: section: 400 + (2 * 100) = 600, aside: 200 + (1 * 100) = 300

Мы еще поговорим подробнее о flex-basis, особенно о разнице между ним и свойством width.

Последний закрепляющий пример "3.html" и "3.css" предлагаю вам разобрать самостоятельно. В случае затруднений и вопросов пишите мне.

Итого

Мы разобрались с первым действительно непростым свойством Flexbox под названием "flex-grow". Оно отвечает за распределение оставшегося места в контейнере по его элементам. Разобрав алгоритм по косточкам, попробовав проверить его на нескольких примерах, вы усвоите это свойство и не будете испытывать проблем при решении задачи о грамотном распределении пустого пространства внутри flex-контейнеров.

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



Report Page