Инженерная практика

Адаптивный CSS Grid: почему 1fr не спасает от переполнения

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

На макете три аккуратные карточки, а на телефоне появился горизонтальный скролл. Вы меняете ширину контейнера, уменьшаете gap и ставите overflow-x: hidden. Визуально проблема пропала, но часть адреса или примера кода стала недоступна. Чтобы исправить причину, нужно разделить ширину трека, минимальную ширину элемента и поведение его содержимого.

Почему колонка 1fr может оказаться слишком широкой

Доля fr участвует в распределении свободного пространства. Но одиночная запись 1fr имеет автоматическую минимальную границу: она не равна обещанию «помести сюда любой текст». Длинное неразрывное слово, фиксированная картинка или блок pre могут влиять на минимальную ширину. В результате трек не сжимается до ожидаемой доли, даже если внешнему контейнеру задана ширина 100%.

Используйте DevTools, чтобы найти конкретный блок за правой границей. Временно включите outline для элементов, посмотрите вычисленные min-width и grid-template-columns. Проверьте, не находится ли внутри вложенный flex-контейнер с собственной автоматической минимальной шириной. Размером управляет вся цепочка родителей, поэтому одна правка на самом глубоком слове не всегда достаточна.

Сетка карточек, которая помещается в узкий контейнер

Ниже самостоятельный пример. Размер 18rem задаёт желательную нижнюю границу карточки. min(100%, 18rem) позволяет уменьшить её, когда контейнер уже этого значения. auto-fit схлопывает свободные треки, а 1fr распределяет оставшееся место между существующими карточками. Это подходит для однотипного списка; для главного материала и боковой панели лучше описать отдельную композицию.

TSX<section class="catalog" aria-label="Учебные материалы"> <article class="item"><h2>React и запросы</h2><p>Отмена и устаревшие ответы.</p></article> <article class="item"><h2>TypeScript и API</h2><p class="long">very-long-unbroken-api-response-property-name-for-layout-testing</p></article> <article class="item"><h2>Пример кода</h2><pre tabindex="0" role="region" aria-label="Длинный пример"><code>const address = 'https://example.test/one/very/long/path/without/line/breaks';</code></pre></article> </section>

JavaScript/* Скопируйте вместе с HTML выше в пустую страницу */ * { box-sizing: border-box; } body { margin: 0; padding: 1rem; font-family: system-ui; } .catalog { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); gap: 1rem; } .item { min-width: 0; padding: 1rem; border: 1px solid #64748b; } .item h2, .long { overflow-wrap: anywhere; } .item pre { max-width: 100%; overflow-x: auto; padding: 1rem; background: #eef2ff; } .item img { max-width: 100%; height: auto; } :focus-visible { outline: 3px solid #2145db; outline-offset: 3px; }

Когда нужна запись minmax(0, 1fr)

У двух областей разной важности, например статьи и оглавления, можно явно задать grid-template-columns: minmax(0, 1fr) 18rem. Основная колонка получает доступное пространство без автоматической нижней границы трека. При уменьшении экрана переведите обе области в одну колонку. min-width: 0 на дочернем элементе остаётся полезным: он описывает минимальную ширину самого элемента, а не размер трека.

Выберите, что переносить, а что прокручивать

Заголовок или URL обычно можно перенести. overflow-wrap: anywhere разрешает разрыв длинной последовательности при нехватке места и влияет на расчёт min-content. Пример кода сохраняет пробелы и структуру: здесь внутренний горизонтальный скролл может быть понятнее произвольных переносов. Не превращайте всю страницу в прокручиваемое полотно только ради одной длинной строки.

Прокручиваемый блок должен быть достижим с клавиатуры. В примере pre получил tabindex="0" и доступное имя. Видимый фокус помогает понять, куда попадут нажатия стрелок. Эти атрибуты полезны для проверки браузеров, в которых scroll-контейнер не становится фокусируемым автоматически. Не добавляйте tabindex к каждому абзацу: это делает обычное чтение неудобным.

Как проверить адаптивность после исправления

  1. Откройте пример при ширине 320, 375, 768 и 1440 пикселей. Сравните scrollWidth корневого элемента с шириной viewport.
  2. Подставьте очень длинный заголовок и URL без пробелов. Добавьте карточку с картинкой и проверьте её реальную ширину.
  3. Увеличьте масштаб браузера до 200%, затем проверьте основной сценарий. При 400% оцените переход в одну колонку и сохранность текста.
  4. Пройдите Tab до примера кода. Убедитесь, что фокус виден и содержимое можно прокрутить, не сдвигая всю страницу.
  5. Проверьте, что изменение не обрезало меню, выпадающий список и индикатор фокуса. Скриншот только первого экрана этого не доказывает.

Измерение scrollWidth полезно как быстрый сигнал, но не заменяет чтение страницы. Скрытый overflow может дать хороший результат измерения и одновременно потерять содержимое. Тест должен проверить не только отсутствие скролла, но и доступность длинного примера. Поэтому сначала выбирайте ожидаемое поведение, затем фиксируйте его автоматической проверкой.

Практика и первичные источники

Примените подход к своему каталогу, затем проверьте доступность формы поиска и скорость интерфейса. Для обсуждения проекта сохраните скриншот до исправления, CSS и объяснение причины; критерии ревью есть в практикуме.

Определения размеров трека: MDN - minmax. Автоматическая минимальная ширина: MDN - min-width. Перенос содержимого: MDN - overflow-wrap. Пример показывает сетку материалов, а не универсальную систему компоновки любого приложения.

Вопросы по теме

Чем minmax(0, 1fr) отличается от 1fr?
У 1fr вне minmax автоматическая нижняя граница. minmax(0, 1fr) задаёт нулевую нижнюю границу трека, чтобы содержимое не заставляло колонку занимать больше доступного места.
Нужно ли ставить overflow-x: hidden на body?
Обычно это скрывает следствие и может обрезать контент или фокус. Найдите элемент, который расширяет страницу, и выберите перенос либо внутреннюю прокрутку.
Можно ли обойтись без media query для карточек?
Для равноправных карточек подходит auto-fit с minmax. Сложной странице с боковым меню или разной важностью областей часто нужны явные изменения компоновки.

Читайте также

Все статьи

Обсудим вашу подготовку?

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

Отвечаю лично, поэтому прошу рассказать о ситуации подробно. Все поля обязательны, кроме отмеченных. После отправки покажу ссылку на мой Telegram: напишите туда, и начнём разговор.

Что не получается, что уже пробовали. От 100 знаков, сейчас 0.
Где работали или учились, сколько лет, какой стек, сколько откликов и собеседований. От 100 знаков, сейчас 0.
PDF или DOCX, до 5 МБ. Файл видит только администратор.
GitHub, hh, LinkedIn, сайт. Можно несколько, через пробел или с новой строки.