Flex-grow 9999 хак.

Источник: Flex-grow 9999 Hack.
Автор:  Joren Van Hee.
Перевод: .

Ох уж эти немцы со своими длинными словами, взяли и забраковали мой CSS код. Нет, не буквально, конечно, но в каком-то смысле так оно и есть. Ситуацию спасло то, что за несколько дней до произошедшего я просмотрел презентацию Зои Микли Гилленуотер (Zoe Mickley Gilleneater) "Using Flexbox Today" («Использование Flexbox сегодня»), представленную в рамках конференции Frontend United. Именно ее речь вдохновила меня на решение возникшей проблемы с помощью Flexbox.

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

Если картина все еще неясна, не стоит переживать — пример поможет разобраться.

Предположим, что у нас имеется флекс-контейнер (display: flex) с двумя флекс-единицами в строке (flex-direction: row). Элемент A слева и элемент B справа. С целью предотвращения роста A элемента, для соответствующей единицы устанавливается нулевое (используемое по умолчанию) значение свойства flex-grow. Оставшееся свободное пространство строки должно быть заполнено вторым элементом B, что достигается установкой flex-grow: 1.

Мне нужно, чтобы при определенных обстоятельствах флекс-единицы размещались вертикально, друг над другом. То есть, когда свободного пространства недостаточно для содержания элемента B, ширина которого должна быть не меньше 20em, то он должен смещаться на нижнюю строку. Задачу можно решить путем добавления flex-wrap: wrap для контейнера и flex-basis: 20em для второй флекс-единицы.

.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}

.item-a {
flex-grow: 0;
}

.item-b {
flex-grow: 1;
flex-basis: 20em;
}

Увидеть то, что мы имеем на данном этапе можно здесь.

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

  1. Ширина элемента A неизвестна. В ней, к примеру, могут находиться слова, которые в другом языке длиннее (*вот вам и немцы).
  2. Неизвестна ширина содержащего компоненты родительского элемента, который может находиться в боковой колонке или другом подобном месте.

Давайте попробуем обойтись без медиа-запросов. Для начала изменим значение свойства flex-grow элемента А на 1. Теперь имеем другую проблему — элемент А будет увеличиваться даже если оба компонента находятся бок о бок в одной строке. Решение заключается в использовании абсурдно большого flex-grow значения для второго элемента В. Настолько большого, чтобы свести долю применяемого для первой флекс-единицы значения (1) практически к нулевой величине. Пусть это будет 9999.

.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}

.item-a {
flex-grow: 1;
}

.item-b {
flex-grow: 9999;
flex-basis: 20em;
}

Вот как выглядит финальная версия нашего примера.

Итак, в чем же секрет? С помощью значения свойства гибкого роста мы задаем долю доступного свободного пространства, которую получает форматируемая флекс-единица. Предположим, имеется 100 неиспользованных пикселей в строке. Тогда для флекс-единицы А мы можем выделить 1/4 часть (25px) пространства (flex-grow: 1), а второй флекс-единице В отдать оставшиеся три четверти (75px) свободного места (flex-grow: 3).

Применительно к нашему случаю флекс-единице А выделяется одна десятитысячная (1/10000) часть свободного пространства, что пересчитывается в 0 пикселей (1/10000*100 = 0,01). Теоретически, если места будет достаточно, то элемент А получит пару пикселей, но для того, чтобы это произошло понадобится реально большой экран. Если вам интересно насколько большим он должен быть, то посчитайте сами.

Вот эта прекрасная статья Криса Койера поможет глубже узнать как управлять ростом элементов в гибкой компоновке.

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

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