Будущее плиточных веб-макетов уже настало! После того, как Mozilla заложила фундамент, потребовались годы работы команды Apple WebKit и множество этапов обсуждений в CSS Working Group с разработчиками всех браузеров, чтобы стало понятно, как всё это должно работать.

Представляем вашему вниманию CSS Grid Lanes.

.container {
  display: grid-lanes;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 16px;
}

Попробовать их можно уже сегодня в Safari Technology Preview 234.

Как работают Grid Lanes

Давайте подробно разберём, как создать вот такой классический макет.

Classic masonry-style layout of photos of various aspect ratios, all the same width, aligned in six columns
Демо фотогалереи можно посмотреть в Safari Technology Preview

Во-первых, HTML.

<main class="container">
  <figure><img src="photo-1.jpg"></figure>
  <figure><img src="photo-2.jpg"></figure>
  <figure><img src="photo-3.jpg"></figure>
  <!-- etc -->
</main>

Для начала применим display: grid-lanes к элементу main для создания контейнера Grid, готового к изготовлению подобного макета. Затем мы используем grid-template-columns для создания полос со всеми возможностями CSS Grid.

В этом случае мы будем применять repeat(auto-fill, minmax(250px, 1fr)) для создания гибких столбцов шириной не менее 250 пикселей. Браузер сам будет решать, сколько столбцов нужно создать, заполняя всё имеющееся пространство.

Далее gap: 16px создаёт промежутки между полосами в 16 пикселей и промежутки между элементами полос тоже шириной 16 пикселей.

.container {
  display: grid-lanes;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 16px;
}

Вот и всё! Всего в трёх строках CSS, совершенно без медиа-запросов и container queries, мы создали гибкий макет, который будет хорошо выглядеть во всех размерах экранов.

Можно представить его в виде шоссе, на котором машины едут плотно друг к другу.

Cartoon drawing of a highway from above. Nine cars fill four lanes of traffic, bumper to bumper. Each car has a number labeling it, showing the order these would be in HTML.
Машины пронумерованы в том порядке, в котором они будут встречаться в HTML.

Как и в классической библиотеке Masonry, когда браузер решает, куда поместить каждый элемент, следующий будет размещаться в том столбце, в котором он будет ближе к верхней части окна. Как и на шоссе, каждая машина «меняет полосу движения», чтобы оказаться в той полосе, которая позволит ей продвинуться вперёд дальше всего.

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

Сила Grid

Переменные размеры полос

Так как Grid Lanes используют всю мощь CSS Grid для задания полос при помощи grid-template-*, можно очень легко создавать изобретательные вариации дизайна.

Например, можно создать гибкий макет с попеременно идущими узкими и широкими столбцами, в котором первый и последний столбец всегда узкие, даже когда количество столбцов меняется с изменением размера вьюпорта. Это можно реализовать при помощи grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr) minmax(16rem, 2fr)) minmax(8rem, 1fr).

Demo layout of photos, where the 1st, 3rd, 5th, and 7th column are narrow, while the 2nd, 4th and 6th columns are twice as wide.
Демо фотогалереи можно посмотреть в Safari Technology Preview

Благодаря использованию синтаксиса grid-template-* возможности становятся практически безграничными.

Span элементов

Так как мы можем использовать всю мощь структуры Grid, то, разумеется, можно и применять в полосах span.

A complex layout of titles with teaser text for over two dozen articles — telling people what they'll experience if they open the article. The first teaser has a very large headline with text, and spans four columns. Five more teasers are medium-sized, bowl and next to the hero. The rest of the space available is filled in with small teasers. None of the teasers have the same amount of content as the rest. The heights of each box are random, and the layout tucks each box up against the one above it.
Демо макета газетных статей можно посмотреть в Safari Technology Preview
main {
  display: grid-lanes;
  grid-template-columns: repeat(auto-fill, minmax(20ch, 1fr));
  gap: 2lh;
}
article { 
  grid-column: span 1; 
}
@media (1250px < width) {
  article:nth-child(1) { 
    grid-column: span 4;             
  }
  article:nth-child(2), article:nth-child(3), article:nth-child(4), article:nth-child(5), article:nth-child(6), article:nth-child(7), article:nth-child(8) { 
    grid-column: span 2; 
  }
}

Для всех тизеров статей сначала задаётся span в один столбец. Затем конкретно первому элементу задаётся span на четыре столбца, а элементам со второго по восьмой — span на два столбца. Это создаёт гораздо более динамичный графический дизайн, чем типичный макет, преимущественно использовавшийся в течение последнего десятилетия, где всё имеет одинаковую ширину и высоту.

Размещение элементов

Также при помощи Grid Lanes можно размещать элементы явным образом. В примере ниже заголовок всегда находится в последнем столбце, вне зависимости от количества столбцов.

A layout of paintings — each has a bit of text below the painting: title, etc. The paintings are laid out in 8 columns. Over on the right, spanning across two columns is the header of the website.
Демо макета веб-сайта музея можно посмотреть в Safari Technology Preview
main {
  display: grid-lanes;
  grid-template-columns: repeat(auto-fill, minmax(24ch, 1fr));
}
header {
  grid-column: -3 / -1;
}

Смена направления

Да, полосы могут идти в обоих направлениях! Во всех приведённых выше примерах создан «водопад», в котором контент выстраивается в столбцы. Но Grid Lanes можно использовать и для создания макета в другом направлении, в виде «кирпичной кладки».

Contrasting cartoon drawings: on the left, waterfall layout with boxes lined up in columns, falling down the page. And "brick" layout, with boxes flowing left to right, stacked like bricks in rows.

Браузер автоматически создаёт «водопадный» макет, если определить столбцы при помощи grid-template-columns:

.container {
  display: grid-lanes;
  grid-template-columns: 1fr 1fr 1fr 1fr;
}

Если вам нужно создать «кирпичную кладку», то задайте строки при помощи grid-template-rows:

.container {
  display: grid-lanes;
  grid-template-rows: 1fr 1fr 1fr;
}

Благодаря новому значению по умолчанию normal для grid-auto-flow, это работает автоматически. Браузер определяет, создавать ему столбцы или строки, на основании того, чем вы задали полосы: grid-template-columns или grid-template-rows.

CSS Working Group пока продолжает обсуждение того, какое свойство должно в явном виде управлять направлением потока и каким должен быть его синтаксис. Группа размышляет над тем, следует ли использовать grid-auto-flow или создать новые свойства, например, grid-lanes-direction. Если вам любопытно изучить рассматриваемые варианты или поделиться своими мыслями, то прочитайте дискуссию.

Однако поскольку normal всё равно будет исходным значением, необязательно ждать этого решения, чтобы приступить к освоению Grid Lanes. Если вы определите только одно направление — grid-template-rows или grid-template-columns — то всё будет без проблем работать. (Но если что-то пойдёт не так, то проверьте, не задано ли для grid-auto-flow конфликтующее значение. При необходимости его можно сбросить при помощи unset.)

Чувствительность к размещению

Для Grid Lanes создана новая концепция «допуска» (tolerance). Она позволяет настраивать степень требовательности алгоритма при выборе размещения элементов.

Взгляните на иллюстрацию. Обратите внимание, что машина 4 немного короче машины 1. Если «допуск» равен нулю, то машина 6 окажется в самой правой полосе, а машина 7 — слева. Машина 6 окажется за машиной 4 справа, потому что так она продвинется чуть вперёд по «дороге» (ближе к верхней границе контейнера Grid). Тогда машина 7 займёт следующий ближайший к вершине слот и окажется за машиной 1 слева. Что мы получаем в итоге? Первая группировка контента по горизонтали упорядочена как 1, 2, 3, 4, а вторая — как 7, 5, 6.

Same cartoon drawing of the highway of bumper to bumper traffic from above.

Однако разница в длине между машинами 1 и 4 очень мала. Машина 6 несущественно ближе к верхней части страницы. И то, что элемент 6 находится справа, а элемент 7 — слева, вероятно, окажется неожиданным, особенно для пользователей, перемещающихся между контентом при помощи Tab, или если порядок контента каким-либо образом указан.

На практике такие крошечные различия в размерах неважны. Браузер должен считать размеры элементов наподобие машин 1 и 4 равными. Именно поэтому по умолчанию item-tolerance имеет значение 1em, то есть при выборе расположения следующего элемента будут учитываться различия в длине контента больше 1 em.

Если вы хотите, чтобы расположение элементов меньше скакало, то можно увеличить значение item-tolerance. На иллюстрации ниже допуск равен половине длины машины, потому машины, по сути, размещаются слева направо и переезжают в другую полосу, только чтобы избежать очень длинного лимузина. Теперь контент сгруппирован по горизонтали так: 1, 2, 3, 4, а потом 5, 6, 7.

Now the highway has the cars ordered in a fashion that's less chaotic.

Допуск можно сравнить с степенью терпеливости водителей. Захотят ли они менять полосу только для того, чтобы оказаться на несколько сантиметров впереди, или они переместятся, только если в другой полосе много места? Весомую для них величину пространства можно задать в item-tolerance.

Помните, что люди, перемещающиеся по странице с помощью Tab, будут видеть каждый элемент в фокусе выделенным, и могут потреблять информацию страницы через программу чтения экрана. Слишком большое значение item tolerance может привести к неприятным скачкам вверх и вниз по макету. Слишком малое значение допуска может привести к нежелательным переходам туда и обратно. Настраивайте item-tolerance так, чтобы значение соответствовало размерам и вариациям размеров вашего контента.

В настоящее время это свойство называется item-tolerance в спецификации и в Safari Technology Preview 234. Однако всё ещё есть вероятность того, что его название поменяется, возможно, на что-то типа flow-tolerance или pack-tolerance. Если вам нравится какое-то из названий или вы придумали что-то получше, то можете поделиться мнением. Прежде, чем использовать это свойство на веб-сайтах в продакшене, посмотрите, какое окончательное название выберут для этого свойства.

Попробуйте демо

Попробуйте Grid Lanes в Safari Technology Preview 234! Все демо на webkit.org/demos/grid3 были дополнены новым синтаксисом, в том числе и другие сценарии использования Grid Lanes. Они полезны не только для изображений! Например, огромный футер меню с кучей ссылок внезапно оказывается удобным.

A layout of 15 groups of links. Each has between two and nine links in the group — so they are all very different heights from each other. The layout has five columns of these groups, where each group just comes right after the group above it. Without any regard for rows.
Демо огромного меню можно посмотреть в Safari Technology Preview
.container {
  display: grid-lanes;
  grid-template-columns: repeat(auto-fill, minmax(max-content, 24ch));
  column-gap: 4lh;
}

Что дальше?

CSS Working Group предстоит принять несколько последних решений. Но в целом, фича уже готова к применению в виде, описанном в этой статье. Пришла пора её использовать. И наконец-то уже можно запоминать её базовый синтаксис!

Было бы здорово, если бы вы создали демо! Покажите, какие новые сценарии использования вы сможете придумать. И сообщайте нам о найденных багах или возможных улучшениях. Ссылки, комментарии и идеи отправляйте Джен Симмонс в Bluesky или Mastodon.

Наша команда работала над этой фичей с середины 2022 года, реализуя её в WebKit и участвуя в составлении стандарта веба. Нам не терпится увидеть, что получится у вас с её помощью.