CSS Grid на практике: частые ошибки новичков и как их чинить
Разбираем реальные грабли CSS Grid: почему макет разъезжается на мобильных, откуда берётся горизонтальный скролл и как исправить каждую ошибку.

Вы сверстали сетку на CSS Grid, в десктопном браузере всё ровно, а на телефоне карточки вылезли за экран и появился горизонтальный скролл. Или колонки не хотят растягиваться, хотя вы написали 1fr. Ниже — восемь ошибок, которые допускают почти все, кто только перешёл на Grid, с текстом проблемы и рабочим исправлением. Работает во всех актуальных браузерах (Grid Level 1 поддерживается с 2017 года, subgrid и gap — отдельно, о них ниже).
Что нужно иметь под рукой: любой современный браузер и его DevTools. В Chrome и Firefox есть инспектор Grid — он подсвечивает линии сетки и номера треков прямо на странице. Без него вы будете чинить макет вслепую.
1. Путают 1fr и auto
Самая частая. Новичок пишет grid-template-columns: auto auto auto, ждёт три равные колонки, а получает колонки разной ширины — по размеру содержимого.
auto — это «размер по контенту». Колонка с длинным текстом станет шире соседней. 1fr — это доля свободного места: три колонки по 1fr всегда равны между собой независимо от содержимого.
/* Разъедется по контенту */
.grid { grid-template-columns: auto auto auto; }
/* Три равные колонки */
.grid { grid-template-columns: 1fr 1fr 1fr; }
/* То же короче */
.grid { grid-template-columns: repeat(3, 1fr); }Проверка: включите инспектор Grid и посмотрите на ширину треков. Если они разные при одинаковом fr — значит, где-то остался auto или в ячейке лежит неразрывный элемент, который распирает колонку (о нём в пункте 4).
2. Отступы делают через margin вместо gap
Из привычки по флексбоксу и float новичок ставит margin на элементы сетки, чтобы развести их. Начинается война с крайними отступами: первый и последний элемент прижаты к краю неровно, приходится городить :first-child и :last-child.
В Grid для промежутков между треками есть gap (раньше — grid-gap, свойство переименовано, но старое имя всё ещё работает как алиас). Он не добавляет отступ по внешним краям сетки — только между ячейками.
/* Так не надо */
.item { margin: 10px; }
/* Так надо: 16px между строками и колонками */
.grid { display: grid; gap: 16px; }
/* Разные отступы: сначала строки, потом колонки */
.grid { gap: 24px 16px; }3. 1fr не сжимается, и появляется горизонтальный скролл
Вот здесь спотыкаются даже те, кто уже освоил fr. Пишете repeat(3, 1fr), кладёте в ячейку длинное слово или картинку без max-width — и на узком экране сетка вылезает за контейнер, страницу можно проскроллить вбок.
Ключевой факт:1fr— это на самом делеminmax(auto, 1fr). Минимум трека равен размеру его содержимого, а не нулю. Поэтому неразрывный контент раздувает колонку сильнее, чем вы просили.
Лечится явным минимумом minmax(0, 1fr) — трек тогда сможет сжаться меньше содержимого, а переполнение уйдёт внутрь ячейки, где его уже ловят overflow или min-width: 0.
/* Колонка не сожмётся уже контента — возможен скролл */
.grid { grid-template-columns: repeat(3, 1fr); }
/* Колонка может сжаться, скролл не появится */
.grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }4. Дочерний flex- или grid-элемент не даёт колонке сжаться
Смежная проблема. Если внутри ячейки лежит вложенный flex-контейнер с длинным текстом, он по умолчанию имеет min-width: auto и отказывается сужаться. Внешняя колонка растёт вслед за ним.
/* Вложенный элемент сможет сжаться и перенести текст */
.card { min-width: 0; }
/* Для длинных слов и ссылок дополнительно */
.card__text { overflow-wrap: break-word; }Проверка: если после minmax(0, 1fr) скролл остался — ищите вложенный элемент с min-width: auto. Инспектор покажет, что именно ячейка шире трека.
5. Ручной раскладкой ломают адаптив
Новичок радуется grid-column: 1 / 3 и расставляет каждый блок вручную по линиям. На десктопе красиво. На мобильном все элементы остаются на своих жёстко заданных линиях и наезжают друг на друга, потому что колонок уже не три, а одна.
Для карточек, которые должны сами переноситься, ручная раскладка не нужна вовсе. Берите автоматический адаптив без единого медиазапроса:
.grid {
display: grid;
/* Колонки минимум 240px, дальше делят место поровну.
Их число само меняется от ширины контейнера */
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 16px;
}auto-fill держит пустые треки, если места много; auto-fit их схлопывает, и уцелевшие карточки растягиваются на всю ширину. Разницу видно только когда элементов меньше, чем помещается колонок.
6. Не понимают порядок сокращения в grid-area
Свойство grid-area: 1 / 2 / 3 / 4 читается не по часовой стрелке, а в порядке row-start / column-start / row-end / column-end. Перепутали местами — элемент прыгает не туда, и вы правите цифры наугад.
| Позиция в сокращении | Что означает |
|---|---|
| первое число | начальная строка (row-start) |
| второе | начальная колонка (column-start) |
| третье | конечная строка (row-end) |
| четвёртое | конечная колонка (column-end) |
На больших макетах читаемее задавать области именами через grid-template-areas — тогда цифры линий не нужны вообще, а перестройка под мобильный сводится к переписыванию строки шаблона в медиазапросе.
.layout {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-areas:
"sidebar header"
"sidebar main";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
@media (max-width: 600px) {
.layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"sidebar"
"main";
}
}7. Забывают про неявные строки
Вы задали три колонки, а число элементов не кратно трём. Grid сам добавляет строки — они называются неявными. Их высота по умолчанию auto, и разнобой по высоте карточек в последнем ряду выглядит неряшливо. За высоту таких строк отвечает grid-auto-rows, о котором новички не знают.
/* Все строки, включая автоматически созданные,
минимум 180px, но могут вырасти под контент */
.grid { grid-auto-rows: minmax(180px, auto); }8. Grid там, где хватило бы Flexbox
Grid — для раскладки в двух измерениях сразу: строки и колонки вместе. Одну строку кнопок или горизонтальное меню проще и надёжнее собрать на Flexbox. Не тащите Grid в каждый контейнер: для одномерных цепочек он даёт лишнюю сложность без выигрыша.
Грубый ориентир: если элементы выстраиваются по одной оси и вам важен их перенос по мере нехватки места — это flex-wrap. Если вы одновременно управляете и строками, и колонками — это Grid.
Если не получилось
- Горизонтальный скролл на мобильном. Ищите
1frбезminmax(0, ...)либо вложенный элемент сmin-width: auto. Включите инспектор Grid и сравните ширину трека с шириной контейнера. - Колонки разной ширины при одинаковом
fr. Где-то осталсяautoв шаблоне или неразрывный контент распирает трек. - Элемент не встал на заданную линию. Проверьте порядок чисел в
grid-area— это row/column start/end, а не по часовой стрелке. - Свойства
gapбудто нет. Убедитесь, что оно стоит на контейнере сdisplay: grid, а не на самих элементах. - Карточки не переносятся. Проверьте, что используете
auto-fill/auto-fit, а не фиксированное число вrepeat.
Что дальше
Освоив базовую сетку, посмотрите на subgrid — он позволяет вложенной сетке наследовать линии родителя и выравнивать содержимое карточек друг с другом (поддержка в актуальных версиях Chrome, Firefox и Safari, но перед использованием на проде сверьте её по caniuse под нужные вам браузеры). Проверяйте макеты не только на изменении ширины окна, но и с реальным длинным контентом — большинство описанных ошибок всплывает именно на нём. Инвалидация вёрстки под RTL и печатные стили — отдельные темы, здесь их не трогаем.
Поиск источников: Реальные статьи и книги со ссылками, библиография по ГОСТ
Спросить за 15 ₽Источники: CSS Grid Layout — MDN Web Docs, CSS Grid Layout Module Level 1 — W3C
Частые вопросы
А если мне нужно поддерживать старые браузеры?
Почему у меня появился горизонтальный скролл, хотя всё в 1fr?
В чём разница между auto-fill и auto-fit?
Когда лучше Grid, а когда Flexbox?
Работает ли gap в Grid везде?
Почему элемент не встаёт туда, куда я указал в grid-area?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.