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

Вы задали grid-template-columns: 1fr 1fr 1fr, положили в ячейку длинный текст без пробелов — и колонка растянулась, сломав всю раскладку. Или сверстали флекс-строку, где элементы отказываются сжиматься и вылезают за родителя с горизонтальным скроллом на мобильном. Это не баги браузера, а следствие того, как считаются размеры в CSS Grid и Flexbox. Ниже — грабли, на которые наступают чаще всего, с причиной и рабочим фиксом. Актуально для всех браузеров, поддерживающих Grid (с 2017 года), примеры проверялись в Chrome 120+ и Firefox 121+.
Грабля 1: элемент не сжимается ниже своего содержимого
Самая частая проблема флекс- и грид-раскладок. Вы даёте элементу flex: 1 или колонку 1fr, а он всё равно шире, чем должен быть, и появляется горизонтальный скролл.
Причина в свойстве min-width (для строк — min-height). По умолчанию у флекс- и грид-элементов оно равно auto, а это значит «не меньше, чем минимальный размер содержимого». Длинное слово, широкая картинка или таблица внутри не дают ячейке сжаться, сколько бы fr вы ни писали.
/* было: колонка распирается длинным содержимым */
.grid {
display: grid;
grid-template-columns: 1fr 2fr;
}
/* стало: разрешаем ячейкам сжиматься */
.grid > * {
min-width: 0;
}
/* для флекса аналогично */
.flex-item {
min-width: 0;
}
Проверка: горизонтальный скролл исчез, длинный текст переносится или обрезается многоточием, если добавить overflow: hidden; text-overflow: ellipsis.
Если раскладка «поехала» вправо и появился горизонтальный скролл — первым делом ставьте min-width: 0 на подозрительный элемент. В девяти случаях из десяти дело в нём.
Грабля 2: fr не то, что проценты
Единица fr распределяет свободное пространство, оставшееся после того, как учтены все фиксированные размеры, gap и минимальный размер содержимого. Из-за этого две колонки 1fr 1fr необязательно окажутся равной ширины: если в одной лежит широкая картинка, она заберёт больше.
Когда нужны действительно равные колонки независимо от содержимого:
.grid {
display: grid;
/* minmax(0, 1fr) заставляет колонки быть строго равными,
игнорируя минимальный размер содержимого */
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
}
minmax(0, 1fr) обнуляет минимум и решает разом и эту граблю, и первую — содержимое больше не распирает колонку.
Грабля 3: gap вместо margin, но не везде
Раньше отступы между элементами делали через margin и потом убирали лишний край хаком :last-child. Сейчас для Grid и Flexbox есть gap — он не добавляет отступ по внешним краям контейнера. Но есть нюанс: gap для Flexbox поддерживается не так давно, как для Grid.
gapв CSS Grid — с самого появления спецификации, вопросов нет.gapв Flexbox — Safari научился его понимать только с версии 14.1 (апрель 2021). Если вам нужна поддержка старых Safari, для флекса придётся возвращаться кmargin.
Ещё частая путаница: gap не участвует в расчёте width: 100% у процентных элементов. Если у вас три колонки по width: 33.33% плюс gap, сумма превысит 100% и последний элемент упадёт вниз. Решение — не мешать проценты с gap, а использовать fr или calc().
Грабля 4: auto-fit против auto-fill
Адаптивную сетку «сколько влезет колонок» делают через repeat() с ключевыми словами auto-fit или auto-fill. Их путают, а поведение разное.
| Значение | Что делает при нехватке элементов | Когда выбрать |
|---|---|---|
auto-fill | Создаёт пустые невидимые колонки-«призраки», элементы прижаты влево | Нужно сохранить фиксированную ширину карточек, даже если их мало |
auto-fit | Схлопывает пустые треки, оставшиеся элементы растягиваются на всю ширину | Нужно, чтобы карточки заполнили строку целиком |
.cards {
display: grid;
/* карточки минимум 220px, растягиваются и заполняют строку */
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
}
Проверка: положите в сетку один элемент. С auto-fit он растянется на всю ширину, с auto-fill — останется 220px в левом углу.
Грабля 5: элемент растягивается на всю высоту строки
Вы кладёте карточки в грид или флекс-строку, и все они принимают высоту самой высокой — картинка внутри растягивается, фон занимает пустое место. Это работа значения по умолчанию align-items: stretch.
Часто это как раз то, что нужно (равные по высоте карточки). Но если элемент должен занимать только свою высоту — переопределите:
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* элементы не растягиваются по высоте трека */
align-items: start;
}
Для отдельного элемента — align-self: start. То же stretch по умолчанию срабатывает и на растянутой картинке, которая «плющится»: задайте ей align-self: start или object-fit: cover с фиксированной высотой.
Грабля 6: percentage height не работает без высоты у родителя
Классика, не связанная напрямую с Grid, но всплывает в сетках постоянно. Вы задаёте элементу height: 100%, а он игнорируется. Причина: процентная высота считается от высоты родителя, а если у родителя высота auto — считать не от чего.
В Grid и Flexbox это решается иначе, чем в старом потоке: не нужно тянуть height: 100% через всю цепочку родителей. Элемент в грид-ячейке или флекс-контейнере растянется сам за счёт stretch. А внутри карточки прижать футер к низу проще через margin-top: auto на флексе, чем через проценты:
.card {
display: flex;
flex-direction: column;
}
.card__footer {
/* прижимает футер к низу карточки любой высоты */
margin-top: auto;
}
Грабля 7: named grid areas и опечатки
Раскладка через grid-template-areas читаемая, но молча ломается от одной опечатки. Если имя области в grid-area элемента не совпадает с именем в шаблоне — элемент просто не встанет на место, и ошибки в консоли не будет.
.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; }
Каждая строка в кавычках — ряд, число слов в строке должно совпадать с числом колонок. Повторяющееся имя (как sidebar выше) растягивает область на несколько ячеек, но только если ячейки образуют прямоугольник — «лесенкой» область задать нельзя, шаблон будет проигнорирован целиком.
Что смотреть дальше
Когда базовые грабли позади, полезно разобрать:
- DevTools — в Chrome и Firefox включите оверлей Grid (иконка grid рядом с элементом в инспекторе): он рисует линии треков и их номера, это быстрее, чем гадать по коду.
- subgrid — позволяет вложенной сетке выравниваться по трекам родителя. Поддержка появилась в Firefox давно, в Chrome — с версии 117 (2023). Проверяйте на caniuse перед использованием в продакшене.
- Логические свойства —
inline-size,gapсrow-gap/column-gapдля мультиязычных интерфейсов с разным направлением текста.
Инвалидация ретро-хаков вроде float-сеток — отдельная тема, здесь мы её не трогаем. Если поддерживаете только современные браузеры, float для раскладки уже не нужен.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: CSS Grid Layout — MDN Web Docs, Basic concepts of flexbox — MDN Web Docs
Частые вопросы
У меня всё равно горизонтальный скролл после min-width: 0, что ещё проверить?
Grid не работает в моём браузере, что делать?
Чем gap отличается от margin и что лучше?
Почему колонки 1fr 1fr получаются разной ширины?
Grid или Flexbox — что выбрать для раскладки?
Как проверить, что сетка не сломается на мобильном?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.