Если ты верстал витрину товаров или фотогалерею в духе Pinterest, то знаешь эту классическую боль. Карточки имеют разную высоту: где-то снимок вертикальный, где-то заголовок длиннее. Нам хочется прижать их друг к другу по вертикали в плотные колонки без пустот — в вебе это называют раскладкой masonry (плиточной кладкой).
Обычный двухмерный CSS Grid для этого не подходил: его сетка создает жесткие пересечения строк и колонок. Если в первой строке один элемент вытянулся на 500 пикселей, вся строка послушно раздувается, а под соседними блоками зияют дыры. Многоколоночный column-count тоже не спасал: он заполняет колонки сверху вниз, ломая порядок чтения слева направо.
В итоге разработчики годами подключали скрипты вроде Masonry.js. Библиотека в рантайме вычисляла координаты через getBoundingClientRect() и расставляла инлайновые стили top и left. Я не раз видел, как это приводило к сдвигам макета (CLS), дерганой прокрутке и жору батареи. Но костылям пришел конец: браузеры согласовали нативный режим display: grid-lanes.
Битва гигантов: почему согласования ждали почти десять лет
Спор о синтаксисе masonry в рабочей группе CSSWG тянулся с 2017 года:
- Команды Mozilla и WebKit (Apple Safari) настаивали, что плиточная кладка должна расширять CSS Grid через значение
grid-template-rows: masonry. Главный плюс — переиспользование привычного аппарата Grid: отступовgap, функцийrepeat()иminmax(), субгридов и именованных линий. - Команда Google Chromium считала, что Grid по своей сути строго двухмерен, а плитка управляет лишь одной осью. Гугл предлагал изолированный контекст
display: masonryс собственными свойствами.
В конце 2025 года консорциум W3C утвердил компромисс. Спецификация вошла в черновик W3C CSS Grid Layout Module Level 3 под именем display: grid-lanes (дорожки сетки). Движок WebKit уже реализовал синтаксис в Safari Technology Preview 234 и Safari 26.4+, а авторы выпустили интерактивный справочник Field Guide to CSS Grid Lanes. Ранее мы разбирали черновые подходы в статье о том, как display: grid-lanes становится нативной альтернативой JS-сеткам, а свежие детали раскрыли портал Piccalilli и канал Библиотека фронтендера.
Анатомия механизма: как браузер упаковывает карточки в дорожки
Слово «lanes» (дорожки) точно описывает суть. Представь кассы в супермаркете: колонки — это очереди. Покупатель с тележкой (карточка контента) подходит к кассовой зоне и встает туда, где очередь сейчас короче всего.
В стандартном Grid браузер выравнивает блоки одновременно по строкам и колонкам. В Grid Lanes жесткая сетка задается только по оси треков (обычно колонкам), а вдоль оси упаковки элементы укладываются независимо по алгоритму заполнения (fill algorithm):
- Разметка дорожек: браузер вычисляет ширину колонок через привычный синтаксис:
.masonry-gallery {
display: grid-lanes;
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
gap: 1.5rem;
}
- Счетчики высоты: движок отслеживает накопленную высоту каждой колонки с учетом отступов
gap. - Приоритет явных позиций: элементы со
span 2или жестко заданными координатами размещаются первыми, бронируя место. - Авторазмещение: для каждого следующего элемента браузер находит дорожку с наименьшей текущей высотой, помещает карточку туда и обновляет высоту дорожки.
Вся математика выполняется на C++ прямо в конвейере компоновки браузера, обеспечивая стабильные 60 кадров в секунду.
Укрощение хаоса: зачем браузерам свойство fit-tolerance
Жадный алгоритм упаковки таит неприятный баг. Допустим, колонка №1 имеет высоту 400px, а соседняя колонка №2 — 398px. Разница всего в два пикселя незаметна глазу, но алгоритм считает колонку №2 строго короче. Браузер бросает следующую карточку во второй столбец, ломая естественный порядок чтения слева направо.
Для решения этой проблемы рабочая группа ввела свойство fit-tolerance (допуск подгонки):
fit-tolerance: 0— абсолютная плотность. Браузер всегда выбирает самую низкую колонку, игнорируя порядок элементов в HTML.fit-tolerance: 1em(значениеnormalпо умолчанию) — разумный баланс. Дорожки с разницей высот в пределах1emсчитаются равными. Среди них браузер выбирает ту, которая сохраняет порядок чтения слева направо.fit-tolerance: infinite— строгий приоритет порядка разметки. Карточки идут строго по очереди, даже если внизу остаются пустоты.
.masonry-gallery {
display: grid-lanes;
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
gap: 1.25rem;
fit-tolerance: 1em;
}
.card-featured {
grid-column: span 2;
}
Субгриды и кирпичная кладка: скрытые суперсилы синтаксиса
Интеграция с CSS Grid дает нативную поддержку CSS Subgrid. Внутри карточки могут быть картинка, заголовок, текст и кнопка. Благодаря субгридам внутренние элементы выравниваются по общим линиям:
.recipe-card {
display: grid;
grid-template-columns: subgrid;
}
Если же тебе нужна горизонтальная раскладка переменной ширины (эффект кирпичной стены), достаточно переключить ось треков на строки:
.horizontal-brick {
display: grid-lanes;
grid-template-rows: repeat(3, 200px);
gap: 1rem;
}
Карточки будут упаковываться слева направо в три горизонтальные полосы, находя самую короткую строку.
Грабли доступности и безопасный запуск в продакшене
У нативной плитки есть уязвимое место — доступность (a11y). Когда элементы раскладываются по кратчайшим колонкам, визуальный порядок на экране расходится с физическим порядком в DOM.
Пользователь с клавиатурой (Tab) или скринридером идет строго по HTML-дереву. Мы подробно разбирали, как автоматическая раскладка CSS Grid Lanes нарушает доступность интерфейсов по стандарту WCAG 2.4.3: если фокус прыгает между колонками хаотично, ориентироваться невозможно.
Если карточки образуют связанную хронологическую цепочку, задавай fit-tolerance: infinite либо верстай каждую карточку как автономный смысловой блок <article>.
Для безопасного продакшена используй прогрессивное улучшение через @supports:
/* Базовый фоллбек для всех браузеров */
.cards-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
gap: 1.5rem;
align-items: start;
}
/* Нативные дорожки для поддерживающих браузеров */
@supports (display: grid-lanes) {
.cards-container {
display: grid-lanes;
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
gap: 1.5rem;
fit-tolerance: 1em;
}
}
Старые браузеры покажут классическую сетку с выравниванием по верхнему краю, а современные пользователи получат монолитную плитку без единой строчки JS.
