Flex grow


Поддержка браузерами

11.0+ 28.0+ 29.0+ 17.0+ 9.0+

Описание

CSS свойство flex-grow указывает сколько свободного пространства может занять flex-элемент относительно других элементов внутри flex-контейнера.

Значение по умолчанию: 0
Применяется: к flex-элементам
Анимируется: да
Наследуется: нет
Версия: CSS3
Синтаксис JavaScript: object.style.flexGrow=»2″;

Синтаксис

flex-grow: число;

Значения свойства


Значение Описание
число Значение по умолчанию 0, указывает что элемент имеет заданные размеры или размеры относительно его содержимого.

Все положительные значения указывают, как будет распределяться свободное пространство между всеми flex-элементами. Например, есть 5 элементов с шириной в 100px каждый, они лежат в контейнере с шириной в 1000px. Если каждому из них задать flex-grow: 1, то свободное пространство в 500px будет поделено на 5 и поровну разделено между всеми элементами (по 100px на каждый).

Если одному из 5 элементов задать flex-grow: 6, то 500px будет разделено на 10 частей (так как в сумме значения свойства flex-grow дали 10) и элементам со значением 1 достанется по 50px (500 : 10 · 1 = 50) свободно пространства, а элементу со значением 6 — 300px (500 : 10 · 6 = 300).

Если только одному из flex-элементов было задано свойство flex-grow с любым положительным значение, то этот элемент займёт всё свободное пространство.

Пример

Всем flex-контейнерам, кроме синего задано flex-grow: 1;, они не имеют фиксированной ширины, поэтому пространство flex-контейнера будет распределятся в зависимости от значения свойства flex-grow:

puzzleweb.ru

Как flex-grow не работает

Прежде чем погрузиться в функциональность flex-grow


, я бы хотел объяснить, где ошибся сначала.

Я подумал, что все flex-элементы с flex-grow:1 будут равной ширины. А если одному из элементов установить flex-grow:2, то он будет вдвое больше остальных.

Звучит неплохо. Кажется, что именно это и происходит в ранее упомянутом примере на CodePen. Ширина родительского элемента 900px, вычисленная ширина элемента section с flex-grow:2 600px, а элемента aside с flex-grow:1 — 300px.

Как видите, в демо-примере всё работает замечательно, в отличие от примера из реальной жизни, где это не работало вообще, даже с одинаковым CSS. Как выяснилось, проблема была не в CSS, а в контенте (точнее в его отсутствии). Демо-пример работает, поскольку в нём используются только два пустых элемента, и он слишком прост, чтобы отобразить важные особенности свойства.

Как flex-grow действительно работает

Я только что описал, как flex-grow не работает, но показал демо-пример, который делает как раз то, чего, по моим словам, делать не должен (позже я объясню причину)

Чтобы прояснить ситуацию, я сделал ещё один пример на Codepen. Настройки остались такими же, но на этот раз в элементах section и aside есть контент. Теперь соотношение уже не 2:1, и элемент с flex-grow:1 фактически больше элемента с flex-grow:2.

Объяснение

У родительского элемента с display: flex;


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

Иначе говоря:

flex-контейнер распределяет свободное пространство между своими элементами (пропорционально их коэффициентам flex-grow), чтобы заполнить контейнеры, или сужает их (пропорционально их коэффициентам flex-shrink), чтобы предотвратить переполнение.

https://drafts.csswg.org/css-flexbox/#flexibility

Демонстрация

Эту идею гораздо легче понять на наглядном примере.

Для начала установим свойству display родительского элемента значение flex, и теперь дочерние элементы становятся flex-элементами и располагаются горизонтально друг за другом.

step1

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


), а второй — 1/3 (flex-grow: 1). Зная общее количество значений flex-grow, мы получаем число, на которое делим оставшееся пространство.

step2

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

step3

Вычисление

Теория и наглядный пример — это приятно, но давайте не поленимся и посчитаем этот пример сами.

Для вычисления понадобятся четыре числа: ширина родительского элемента, исходная ширина элементов section и aside и общее число значений flex-grow, которое мы собираемся использовать.

родительская ширина: 900px
ширина section: 99px
ширина aside: 623px
сумма значений flex-grow: 3

1. Для начала нужно вычислить оставшееся пространство

Это не сложно. Возьмём родительскую ширину и вычтем из неё общую начальную ширину каждого дочернего элемента.

900 - 99 - 623 = 178  

родительская ширина − начальная ширина section − начальная ширина aside = оставшееся пространство

2. Далее нужно определить, сколько приходится на один flex-grow

Вычислив оставшееся пространство, нужно определить, на сколько долей его разделить. Здесь важно понимать, что мы делим оставшееся пространство не на число элементов, а на сумму значений flex-grow


. Так что в нашем случае это 3 (flex-grow: 2 + flex-grow: 1)

178 / 3 = 59.33  

оставшеся пространство/сумма значений flex-grow = «один flex-grow»

3. И наконец, доли оставшегося пространства распределяется между всеми элементами

Исходя из их значений flex-grow, section получает две доли (2 * 59.33), а aside — 1 (1 * 59.33). Эти числа добавляются к начальной ширине каждого элемента.

99 + (2 * 59.33) = 217.66 (≈218px)  

начальная ширина section + (значение flex-grow у section * «один flex-grow») = новая ширина

и

623 + (1 * 59.33) = 682.33 (≈682px)  

начальная ширина aside + (значение flex-grow у aside * «один flex-grow») = новая ширина

Элементарно, так ведь?

Хорошо, но почему первый демо-пример работает?

Формула получена, и теперь давайте выясним, как нам удалось заполучить фактически нужные числа в первом Codepen, даром что мы действовали совершенно наобум.


родительская ширина: 900px
ширина section: 0px
ширина aside: 0px
сумма значений flex-grow: 3

1. Вычисляем оставшееся пространство

900 - 0 - 0 = 900  

2.  Определяем, сколько приходится на один flex-grow

900 / 3 = 300  

3. Распределяем доли оставшегося пространства

0 + (2 * 300) = 600  0 + (1 * 300) = 300  

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

flex-grow и flex-basis

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

А если оставшегося пространства нет или вместо начальной ширины элементов нам хочется задействовать установленное нами значение? Можно ли и в этом случае использовать flex-grow?

Конечно, можно. Есть свойство flex-basis


, которое определяет начальный размер элемента. Если вы используете flex-basis в сочетании с flex-grow, то способ вычисления ширин меняется.

<‘flex-basis’>. Этот компонент устанавливает отдельное свойство flex-basis и указывает базовый размер: начальный главный размер flex-элемента до распределения свободного пространства в соответствии с flex-grow и flex-shrink.

https://drafts.csswg.org/css-flexbox/#valdef-flex-flex-basis

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

Я подправил предыдущий пример, добавив к каждому элементу flex-basis. Вот результат.

родительская ширина: 900px
ширина section: 400px (значение flex-basis)
ширина aside: 200px (значение flex-basis)
сумма значений flex-grow: 3

1. Вычисляем оставшееся пространство

900 - 400 - 200 = 300  

2.  Определяем, сколько приходится на один flex-grow

300 / 3 = 100  

3. Распределяем доли оставшегося пространства

400 + (2 * 100) = 600  200 + (1 * 100) = 300  

Кстати, совсем не обязательно использовать значения в пикселях и надеяться на авось, проценты тоже годятся.

Работа с боксовой моделью

Чтобы уж точно ничего не бояться, проверим, что произойдёт при добавлении padding


и margin. В принципе, ничего особенного. На первом шаге вычисления просто не забывайте вычесть также и отступы.

Единственное, что стоит отметить — что с точки зрения box-sizing поведение flex-basis соответствует свойству width. А значит, при изменении свойства box-sizing изменится вычисление, а следовательно и результаты. Если box-sizing присвоить значение border-box, то в вычислении участвовали бы только значения flex-basis и margin, поскольку padding уже включён в ширину.

Несколько полезных примеров

Ладно, оставим математику. Я покажу несколько примеров, как можно эффективно использовать flex-grow в проектах.

Больше никаких width: [ x ]%

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

See the Pen flex-grow by Manuel Matuzovic (@matuzo) on CodePen.

Резиновая трехколоночная раскладка («Святой Грааль») с фиксированными колонками в пикселях

Смешивание фиксированных и плавающих ширин в колоночных раскладках возможно и с float


, но это сложно, не очевидно и негибко. Конечно, для Flexbox с небольшой магией flex-grow и flex-basis это пустяки.

See the Pen Layout using fluid and fixed widths by Manuel Matuzovic (@matuzo) on CodePen.

 

Заполнение любым элементом оставшегося пространства

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

See the Pen Filling up the remaining space in a form by Manuel Matuzovic (@matuzo) on CodePen.

Ещё больше примеров можно найти на сайте «Решено с помощью Flexbox» Филипа Уолтона.

Что говорит спецификация

Согласно спецификации, вместо flex-grow нам следует использовать короткую запись flex.

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

https://drafts.csswg.org/css-flexbox/#flex-grow-property

Но будьте осторожны! С простым flex: 1;


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

Если хотите использовать flex в нашем случае, то лучше указывать его примерно так:

flex: 2 1 auto; /* (<flex-grow> | <flex-shrink> | <flex-basis>) */  

Где можно изучить Flexbox

Если хотите подробнее изучить Flexbox, воспользуйтесь этими ресурсами:

  • Полное руководство по Flexbox Криса Койера
  • Путешествия по Flexbox Криса Райта
  • Flexbox на лягушках Томаса Парка
  • Что за Flexbox? Веса Боса
  • flexboxin5
  • Flexbox-тестер Майка Рейтмюллера

Резюме и усвоенные уроки

flex-grow странный? Неа, ничуть. Нам просто нужно понять как он работает и что делает. Элемент с flex-grow:3 не будет втрое больше элемента с flex-grow:1, а к его начальной ширине добавится в 3 раза больше пикселей, чем к другому элементу.

Я извлёк урок из тестирования flex-grow c двумя пустыми элементами, из-за которого я сначала неправильно понял, как оно работает, и, естественно, пришел было к неправильным выводам. Следует проверять новые возможности в максимально реалистичной среде, чтобы лучше представлять, как они работают и ведут себя.

css-live.ru

Свойство #1: Flex-Basis

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

Наше первое свойство, на мой взгляд одно из наименее хорошо объясняемых свойств, в руководствах по Flexbox.

Но, не волнуйтесь. Оно на самом деле довольно простое.

flex-basis управляет размером элемента по умолчанию, до того как он будет управляться другими Flexbox свойствами (об этом позже).

На GIF’ке ниже, это означает что оно взаимозаменяемо с свойством width.
Пример flex-basis

Flex-basis влияет на размер элемента относительно основной оси.

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

 Оси Flexbox

Обратите внимание на то, что мы вручную переключили height на width. Таким образом flex-basis попеременно определяет ширину или высоту, в зависимости от flex-direction.

Свойство #2: Flex Grow

Теперь мы собираемся немного усложнить задачу.

Во первых, давайте установим для наших квадратов одинаковую ширину в 120px.

Пример flex-grow

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

Хорошо, давайте попробуем увеличить flex-grow до 1 у каждого квадрата:

Пример flex-grow

Квадраты заняли всю ширину контейнера, а пространство между ними распределилось равномерно. Значение свойства flex-grow переопределяет значение свойства width.

Путаница в flex-grow, заключается в том, что же на самом деле означает его значение? Что на самом деле подразумевает flex-grow: 1?

Вот как выглядит flex-grow, если каждому квадрату установить значение 999:

Пример flex-grow

Это… тоже самое.

Это потому что flex-grow не абсолютное значение, а относительное.

Важно не то какое значение flex-grow квадрата само по себе, а какое оно по отношению к другим квадратам.

Если для всех квадратов мы установим значение flex-grow: 1;, а затем будем изменять это значение для Квадрата #3, то мы увидим изменения:

Пример flex-grow

Чтобы на самом деле понимать, что здесь происходит, давайте немного погрузимся в математику.

Значение flex-grow для каждого квадрата начинается с 1. Если мы сложим flex-grow каждого квадрата, то в итоге получим 6. Таким образом, контейнер разделён на 6 отдельных секций. Каждый квадрат занимает 1/6 от доступного пространства в контейнере.

Когда мы устанавливаем flex-grow: 2; для Квадрата #3, то контейнер делится на 7 различных секций, так как сумма свойств flex-grow равна 1+1+2+1+1+1.

Квадрат #3 занимает 2/7 от всего пространства, а остальные занимают по 1/7.

Когда мы устанавливаем flex-grow: 3; для Квадрата #3, контейнер делится на 8 различных секций (1 + 1 + 3 + 1 + 1 + 1) и Квадрат #3 занимает 3/8, а остальные по 1/8.

И так далее.

Flex-grow пропорционален. Если мы установим всем квадратам flex-grow: 4;, а Квадрату #3 flex-grow: 12;, то получим точно такой же результат как если бы это было 1 и 3 соответственно:

Пример flex-grow

Важно, что flex-grow для квадрата пропорционален, другим квадратам.

Ну и в качестве заключительной заметки запомните, что и как flex-basis, flex-grow применяется относительно основной оси. Наши квадраты будут  будут увеличиваться по ширине, только если мы не будем устанавливать flex-direction: column;.

Свойство #3: Flex Shrink

Flex-shrink — это противоположное свойство для flex-grow, определяющее насколько квадрат может сжиматься.

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

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

Давайте посмотрим на него в действии. Ниже на GIF’ке, у всех квадратов установлено свойство flex-grow: 1;, поэтому они занимают весь контейнер, и flex-shrink: 1;, так что они могу сжиматься.

Пример flex-shrink

Теперь давайте установим Квадрату #3 свойство flex-shrink на 0. Ему запрещено сжиматься, поэтому он увеличивается когда размер контейнера становиться больше, но не сжимается меньше установленной ширины в 120px.

Flex growПример flex-shrink

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

Опять же, flex-shrink пропорционален. Если у одного квадрата flex-shrink: 6;, а у остальных flex-shrink: 2;, то один из квадратов будет сжиматься в 3 раза быстрее, чем остальные.

Обратите внимание на формулировку: квадрат с 3-кратным flex-shrink будет сжиматься в 3 раза быстрее. Это не означает, что он будет сжиматься на 1/3 ширины.

Свойство #4: Flex

Flex — это сокращение для grow, shrink и basis вместе взятых.

По умолчанию установлены значения в 0 (grow) 1 (shrink) и auto (basis).

Для нашего заключительного примера, давайте упростим до двух квадратов.

Вот их свойства:

 .square#one {  flex: 2 1 300px; } .square#two {  flex: 1 2 300px; }

У них одинаковый flex-basis. Это означает, что если в контейнере достаточно места для них обоих (600px контейнер плюс margin’ы и padding’и), они оба будут по 300px;

Но когда контейнер увеличивается, Квадрат #1 (у которого flex-grow выше) будет увеличиваться в 2 раза быстрее. А когда контейнер сжимается, Квадрат #2 (у которого flex-shrink выше) будет сжиматься в два раза быстрее.

Теперь всё вместе:

Пример flex

Как всё сжимается и увеличивается

Вот что может сбивать с толку, дак это когда Квадрат #1 увеличивается, он не увеличивается чтобы быть в два раза больше Квадрата #2. Точно также, когда Квадрат #2 сжимается, он не сжимается до того чтобы быть в два раза меньше Квадрата #1 — даже если пропорция flex-shrink 2 к 1.

Это не их размер который равен 2 к 1 или 1 к 2. Это их уровень сжатия и увеличения.

Немного математики

Начальный размер контейнера равен 640px. После учёта внутренних отступов 20px с каждой стороны контейнера, этого места достаточно для того чтобы flex-basis обоих квадратов вернулся в 300px.

Когда ширина контейнера устанавливается в 430px, мы теряем 210px. Квадрат #1 с flex-shrink: 1;, теряет 70px. Квадрат #2 с flex-shrink: 2;, теряет 140px;

Когда контейнер сжимается до 340px, мы теряем 300px пространства. Квадрат #1 теряет 100px, Квадрат #2 теряет 200px.

Потерянное пространство делится в соответствии с их значениями flex-shrink.

Такая же история и с flex-grow. Когда контейнер вырастает до 940px, мы получаем 300px дополнительного пространства, Квадрат #1 получается дополнительные 200px, а Квадрат #2 получает дополнительные 100px.

Когда дело доходит до flex свойств, пропорции — это название игры.

Пример flex

На GIF’ке выше вы можете увидеть как ширина регулируется в соответствии с отношениями, с дельтой (∆) показывающей разницу от flex-basis.

Заключение

В качестве финального заключения: flex-basis управляет тем насколько элемент будет большим вдоль основной оси, до того момента как происходит увеличение или сжатие. Flex-grow определяет насколько он будет увеличиваться пропорционально лежащих на одном уровне элементов, а flex-shrink определяет насколько он будет уменьшаться.

tuhub.ru


You May Also Like

About the Author: admind

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.