Понимание Flexbox более глубоко

С тех пор, как появился display: flex, создание макетов с использованием CSS стало легким делом. Одной из сложных вещей всегда было понять, как работают flex-grow и flex-shrink. Какая математика стоит за ними? Это моя попытка их упростить.

Часть 1. Введение

Мы начнем с базовой страницы, родительского блока div, содержащего три элемента div: один, два и три соответственно. Один, два и три имеют высоту 100 пикселей и ширину 50 пикселей. Посмотрите на следующую картинку (код будет следовать).

Как мы видим, у нас есть родительский div и три дочерних div с красным, синим и зеленым цветами соответственно. Родительский div имеет желтый цвет.

Приведенный выше файл ляжет в основу нашей будущей статьи. Я буду отображать только макеты и соответствующий CSS. Остальной код останется прежним.

Часть 2. Flex-Grow

Давайте дадим каждому дочернему div свойство flex-grow 1.

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

В следующем примере давайте присвоим значения 1, 2 и 3 красному, синему и зеленому цветам соответственно.

Как видим, все трое выросли на разную величину. Их размеры:

  • Красный: 104,5 (рост на 54,5)
  • Синий: 159 (рост на 109)
  • Зеленый: 213,5 (рост на 163,5)
  • Родительский размер: 477 (свободное пространство, занятое с использованием flex-grow, составляет 227)

Как мы видим, пространство, которое было доступно дочерним div, пропорционально делится в соответствии со значением flex-grow.

  • Красный: 277 * (1/6) = 54,5
  • Синий: 277 * (2/6) = 109
  • Зеленый: 277 * (3/6) = 163,5

Примечание. Ваши значения будут отличаться в зависимости от размера экрана. По умолчанию flex-grow равно нулю.

Формула для flex-grow:

Доступное пространство * (flex-grow значение дочернего элемента / сумма всех flex-grow значений)

Часть 3. Флекс-термоусадка.

Давайте сделаем что-нибудь интересное и сделаем значение ширины родительского элемента равным 100 пикселей. Это сделает родительское значение на 50 пикселей меньше, чем общее значение его дочерних элементов.

Как видим, все трое детей уменьшились в размерах. Все они теперь имеют размер 33,33. Значение по умолчанию flex-shrink - 1. Поскольку свободного места не было, они уменьшились, чтобы освободить 50 пикселей в пространстве.

Сделаем flex-shrink значение 1,2 и 3 соответственно для детей.

Как видим, все трое уменьшились и теперь имеют разные размеры. Красный имеет наименьшее значение flex-shrink (наименьшее сжатие), а зеленый - наибольшее значение flex-shrink (наибольшее сжатие).

Посмотрим на их размеры.

  • Красный: 41,6667 (уменьшился на 8,3333)
  • Синий: 33,3333 (уменьшение на 16,6667)
  • Зеленый: 25 (уменьшился на 25)
  • Родительский размер: 100 пикселей (дети должны освободить 50 пикселей в пространстве)

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

  • Красный: 50 * (1/6) = 8,3333
  • Синий: 50 * (2/6) = 16,6667
  • Зеленый: 50 * (3/6) = 25

Формула уменьшения размера:

Освобождаемое пространство * (flex-shrink значение дочернего элемента / сумма всех flex-shrink значений)

Интересно то, что рост всех троих детей разный. Сделаем их 40, 50 и 60 соответственно.

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

  • Красный: 26,6667 (уменьшился на 13,3333)
  • Синий: 33,3333 (уменьшение на 16,6667)
  • Зеленый: 40 (уменьшился на 20)

Как мы видим, все три имеют одинаковые значения flex-shrink, но все уменьшились на разные значения. Легко заметить, что они уменьшились пропорционально своему размеру. Красный сжался меньше всего, так как был самым маленьким, а зеленый сжался больше всего, потому что он был самым большим.

  • Красный: 50 * (40/150) = 13,3333
  • Синий: 50 * (50/150) = 16,6667
  • Зеленый: 50 * (60/150) = 20

Теперь давайте изменим их flex-shrink значения на 3,2 и 1, чтобы сделать вещи немного интереснее, и сведем их к окончательной формуле.

Посмотрим на их размеры.

  • Красный: 18,5667 (уменьшение на 21,4333)
  • Синий: 32,15 (уменьшение на 17,85)
  • Зеленый: 49,2833 (уменьшился на 10,7167)

Все трое уменьшились пропорционально своим размерам и их flex-shrink значениям. На этот раз формула немного отличается. Они уменьшились пропорционально кратному значению flex-shrink и его размеру.

Множители составляют 40 * 3 для красного, 50 * 2 для синего и 60 * 1 для зеленого.

  • Красный: 50 * (120/280) = 21,43333
  • Синий: 50 * (100/280) = 17,85
  • Зеленый: 50 * (60/280) = 10,7167

Формула для flex-shrink:

Общее пространство, подлежащее уменьшению * [flex-shrink значение * начальная ширина / сумма (flex-shrink значение * начальное значение) всех элементов]

Часть 4. Еще несколько примеров

Часть 5. flex-direction и flex-base.

В приведенном выше примере все было вычислено по ширине. Это потому, что по умолчанию основная ось была горизонтальной, поскольку flex-direction было строкой. Если flex-direction - столбец, основная ось становится вертикальной, а flex-grow и flex-shrink изменяют высоту элемента, а не ширину элемента.

Давайте посмотрим на пример. Высота родительского элемента составляет 300 пикселей, а flex-direction - столбец. Красный, Синий и Зеленый имеют высоту 50 пикселей соответственно.

Если я добавлю к дочерним элементам flex-grow свойств, они будут расти в вертикальном направлении, поскольку flex-direction - столбец.

Flex-basis - это начальная длина ширины или высоты, в зависимости от flex-direction. Для строки это ширина. Для столбца это высота.

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

flex: 1 1 100; # flex-grow flex-shrink flex-basis

Есть еще четыре свойства, которые можно использовать для ребенка. Это min-width, max-width, min-height и max-height. Дочерний элемент останется ограниченным в этих четырех.

Дочернему элементу автоматически присваивается свойство отображения flex-item.

Часть 6. Заключение

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