Flex: grow и shrink

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

Свойство grow («жадность») указывает на то, как ведёт себя ячейка, когда есть свободное место в строке. Чем больше grow, тем больше места займёт ячейка.

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

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

Котик
Автор котика: Phliar

Поведение grow

Вначале разберёмся как работает grow на таком примере:

<div class="layout-center-wrap mar10-tb">
    <div class="layout-wrap flex flex-wrap-tablet">
        <div class="flex-grow3 bg-green100 pad10">
            text
        </div>
        
        <div class="flex-grow2 bg-green200 pad10">
            text
        </div>
        
        <div class="flex-grow1 bg-green300 pad10">
            text
        </div>
    </div>
</div>

Первая ячейка с классом flex-grow3 имеет «жадность» 3. Вторая — 2 и третья — 1. Проверь этот пример и убедись, что именно в такой же пропорции браузер отобразил ячейки. В данном примере в сетке достаточно много места, а значит браузер расширил ячейки за счёт пустот с указанным значением grow.

Но что будет, если текста будет много и пустот не останется?

<div class="layout-center-wrap mar10-tb">
    <div class="layout-wrap flex flex-wrap-tablet">
        <div class="flex-grow3 bg-green100 pad10">
            text text text text text text text text text text text text text text text text text text text text
        </div>

        <div class="flex-grow2 bg-green200 pad10">
            text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
        </div>

        <div class="flex-grow1 bg-green300 pad10">
            text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
        </div>
    </div>
</div>

В этом примере текста уже много и последняя ячейка стала самой большой, хотя у неё указана самая большая «жадность». Поэтому запомни: grow работает только с пустым пространством. Если его нет, то браузер распределит ячейки согласно их содержимому.

Поведение shrink

В следующем примере заполняемость ячеек высокая, а значит будет действовать shrink — «степень сжимаемости».

<div class="layout-center-wrap mar10-tb">
    <div class="layout-wrap flex flex-wrap-tablet">
        <div class="flex-shrink1 bg-green100 pad10">
            text text text text text text text text text text text text text text text text text text text text
        </div>

        <div class="flex-shrink3 bg-green200 pad10">
            text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
        </div>

        <div class="flex-shrink4 bg-green300 pad10">
            text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
        </div>
    </div>
</div>

Хотя последняя ячейка самая большая по содержимому, но из-за бОльшего, чем у других значения flex-shrink4, оказалась самой узкой.

Таким образом, подбирая эти коэффициенты у ячеек можно подобрать и желаемую ширину.

Комбинируем

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

<div class="layout-center-wrap mar10-tb">
    <div class="layout-wrap flex flex-wrap-tablet">
        <div class="flex-grow1 flex-shrink1 bg-green100 pad10">
            text text text text text text text text text text text text text text text text text text text text
        </div>

        <div class="flex-grow2 flex-shrink5 bg-green200 pad10">
            text text text text text text text text text text text text text text text text text text text text
        </div>

        <div class="flex-grow2 flex-shrink5 bg-green300 pad10">
            text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
        </div>
    </div>
</div>

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

Обрати также внимание, как ведёт себя сетка на телефонах, где разрешён wrap-перенос.

Ограничения ширины

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

И здесь можно использовать обычные классы ширины, только с суффиксом -min (минимальный размер) или -max (максимальный). А также указывать классы для адаптивного дизайна.

<div class="layout-center-wrap mar10-tb">
    <div class="layout-wrap flex flex-wrap-tablet">
        <div class="flex-grow1 flex-shrink1 w50 w100-tablet bg-green100 pad10">
            text text text text text text text text text text text text text text text text text text text text 
        </div>
        
        <div class="flex-grow2 flex-shrink4 w200px-min w50-tablet w100-phone bg-green200 pad10">
            text text text text text text text text text text text text text text text text text text text text 
        </div>
        
        <div class="flex-grow2 flex-shrink5 w150px-min w50-tablet w100-phone bg-green300 pad10">
            text text text text text text text text text text text text text text text text text text text text
        </div>
    </div>
</div>

Как верстать такую сетку

Вначале нужно сделать каркас flex-сетки и разметить ячейки. Пока они пустые, нужно прописать классы для grow (доступны от 1 до 5). Так мы добиваемся нормальной пропорции, когда много места.

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

После этого проверяем поведение сетки на tablet и phone. Если сетка ведёт себя некорректно, то прописываем минимальную ширину или классы адаптивности для ячеек.

Большой плюс такого подхода в том, что нам не нужно подбирать ширину ячеек в процентах (или пикселях) — браузер будет сам размещать содержимое наиболее оптимальным способом. Наша задача только подкорректировать его поведение.

Задания

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