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

Пример макета
Пример макета

Рассмотрим пример реализации на CodePen. Мы видим 5 блоков с ассиметричным расположением. Блоки 2, 3 и 4 имеют одинаковую высоту, в то время как блоки 1 и 5 имеют отличные от остальных блоков высоты. При изменении ширины окна браузера блоки уменьшаются в ширину, и в какой-то момент переходят в одну колонку. В блоке 4 находится текст, который при изменении ширины блока растягивает блоки 3 и 4 по высоте, сохраняя при этом структуру сетки.

▎Как это работает

CSS Grid — это способ разделить контейнер на строки и столбцы. Для создания асимметричной структуры нужно указать, сколько строк должен занимать каждый блок. Для этого понадобятся следующие свойства:

grid-gap

Это свойство задает размер промежутков между блоками по обеим осям.

grid-auto-rows

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

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

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

grid-row-end 

Это свойство определяет сколько строк занимает элемент, или на какой строке элемент заканчивается в сетке.

Мы используем это свойство со значение span n, где n это количество строк, которое должен охватывать блок.

В нашем примере высота строки (grid-auto-rows: auto), это значит, что фактически она равна нулю и увеличивается только тогда, когда содержимое будет растягивать блок. Однако, поскольку задан grid-gap, именно это значение будет влиять на расчет высоты блоков.

Если по макету высота блока 150px, а размер промежутков 10px, то количество строк  рассчитывается следующим образом: 150 / 10 + 1 = 16. Поэтому в нашем примере  для первого блока задано grid-row-end: span 16. Для остальных блоков количеств строк рассчитывается аналогично. 

▎Горизонтальное позиционирование

grid-template-columns

Это свойство отвечает за размеры и расположение колонок в контейнере.

Мы используем значение repeat(), позволяющее повторять набор правил для столбцов.

Указав максимальное количество колонок 2 и минимальную ширину колонки 200px, мы обеспечиваем горизонтальную эластичность сетки.

Подробное о реализации автоматического заполнения, можно прочитать в этой статье:

https://css-tricks.com/an-auto-filling-css-grid-with-max-columns/

▎Итого

Если высота блоков в макете кратна значению промежутка (grid-gap), легко совместить точную верстку (Pixel Perfect) с резиновой.

Для автоматического растягивания блоков по высоте используйте grid-auto-rows: auto. Высоту блоков можно задать, указав количество занимаемых строк, вычисляемое по формуле: Высота блока в макете / Значение промежутка + 1

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

Комментарии (4)


  1. itBestRay
    05.01.2025 09:34

    Классный пример, он наглядно показывает, что для Pinterest-подобных сеток совсем не обязательно вручную высчитывать магические отступы. Единственный момент: если динамически меняется содержимое (например, тексты длиннее), надо внимательно следить за grid-gap, чтобы высота не стала неожиданно “съезжать”


    1. kossyak Автор
      05.01.2025 09:34

      На мой взгляд, то что содержимое может немного растянуть блоки это не критично. Но это можно решить, изначально сделав в дизайне макета высоту блоков чуть больше. Я видел такой пример, где на десктопной версии под тестом остается пространство. На крайний случай, можно использовать медиа запросы, немного увеличивая высоту строки grid-auto-rows: 2px; Таким образом мы увеличиваем высоту всех блоков, но сохраняем их пропорции относительно друг-друга.


  1. Ntano
    05.01.2025 09:34

    А что делаем если блоки динамикой с сервера валятся?)


    1. kossyak Автор
      05.01.2025 09:34

      Можно определить вариации размерности блоков, вряд ли их будет больше 5. И для каждого из вариантов задать свои значение занимаемых строк. Например grid-row-end: span 5; grid-row-end: span 10; grid-row-end: span 15; И со стороны бэкенда для каждой карточки передавать вариант размера блока, можно его рассчитывать от количества символов в тексте, если это картинки, то от высоты изображения. В любом случает нужно писать дополнительный код. Сетка подразумевает, что между размерами блоков есть связь (пропорции), если ее нет, то только js в помощь.