CSS Grid для каталога курсов
Построим сетку курсов с CSS Grid и позволим числу колонок зависеть от доступной ширины.
В прошлом уроке Flexbox помог расположить бренд, навигацию и метаданные вдоль одной оси. Теперь изменим весь список курсов. На широком экране несколько карточек могут стоять рядом, а на узком должны возвращаться к одному столбцу. Для этой задачи зададим дорожки Grid и их ограничения, сохранив исходный порядок шести записей.
Не будем писать отдельные ширины каждой карточке. Сетка должна владеть распределением места между ними. Тогда добавление седьмой записи создаст новую ячейку по тем же правилам, а не потребует вычислять процент вручную. Наш пример ещё не содержит фильтрации: все шесть li участвуют в одном наборе, поэтому результат можно объяснить без скрытых состояний данных.
Дорожки и элементы сетки
Добавьте в CSS следующие правила:
.layout-lab .course-list {
display: grid;
grid-template-columns:
repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
gap: 1rem;
}
.layout-lab .course-list > li + li {
margin-block-start: 0;
}
.layout-lab .course-card {
block-size: 100%;
}
Ожидается несколько колонок, если ширина оболочки позволяет разместить их с учётом промежутков. На узком окне получится одна колонка. Старое верхнее поле у соседних li обнулено: теперь расстояниями между ячейками управляет gap. Если оставить оба механизма, элементы со второго места получат дополнительный вертикальный отступ, который уже не выражает нужное отношение в сетке.
Непосредственными grid-элементами списка являются li.course-slot. Карточка article вложена внутрь. Поэтому дорожки распределяют размеры оболочек, а block-size: 100% помогает карточке заполнить высоту своей ячейки. Сам текст внутри статьи пока использует обычный поток. От включения Grid на списке каждый потомок документа не получает автоматически собственную сетку.
Дорожка — это полоса между соседними линиями сетки. В нашем правиле описаны колонки. Строки создаются автоматически по мере размещения карточек. Важно различать внешний размер ячейки и внутреннюю компоновку записи. В пятнадцатом уроке карточка сможет сама стать grid-контейнером при достаточной локальной ширине, но это будет другой независимый контекст. Основы Grid приведены в MDN.
Как читать выражение колонок
Начнём с простого варианта repeat(3, 1fr). Он создаёт три равные гибкие колонки, но требует три даже там, где тексту уже тесно. Единица fr представляет долю распределяемого пространства, а не фиксированный процент страницы. Промежутки и другие ограничения участвуют в расчёте до распределения. Для нашего каталога жёсткое число колонок пока не нужно.
minmax задаёт нижнюю и верхнюю границы дорожки. Запись minmax(18rem, 1fr) просит не делать колонку уже восемнадцати rem и позволяет ей расширяться. Но если весь контейнер уже этого минимума, такая дорожка всё равно может выйти за его границы. Вложенный min(100%, 18rem) выбирает меньшую из доступной ширины и желаемого минимума. Так мы не требуем широкую колонку в очень узком контейнере.
auto-fit позволяет создать столько повторений, сколько помещается по правилу. Пустые дорожки могут схлопываться, а существующие записи получают свободное место. У auto-fill поведение пустых дорожек отличается. Для шести заполненных карточек в обычном состоянии разница иногда не видна, поэтому не нужно приписывать двум словам одинаковую роль. Полезно временно оставить одну запись и сравнить распределение ширины.
Число восемнадцать выбрано для учебного макета. Оно не является доказанной идеальной шириной каждой карточки ProfessorWeb. После ручного открытия нужно оценить длину названий и форму обложки. Если значения требуют уточнения, меняется параметр сетки, а не отдельная ширина пятой карточки. Такое место настройки делает компоновку объяснимой при расширении данных.
Высота записи и высота строки
Карточки в одной строке могут иметь разные объёмы текста. Дорожка строки учитывает требуемый размер содержимого, а оболочки по умолчанию растягиваются в своей области. Вложенная карточка с высотой сто процентов заполняет эту область. Поэтому фон соседних записей ожидаемо доходит до общего нижнего края, даже если одно описание короче другого.
Это не заставляет строки текста совпадать по вертикали во всех карточках. Длинное название всё равно займёт больше места и опустит описание. Для общей внутренней структуры существуют другие приёмы, включая отдельную сетку и subgrid, но сейчас они не нужны. Мы не обрезаем название ради зрительной ровности. Содержимое остаётся полным, а карточка растёт по нему.
Если метаданные должны всегда стоять у нижней границы, нужно отдельно описать внутреннее распределение статьи. block-size: 100% не переносит конкретный дочерний абзац вниз сам по себе. На этом шаге мы лишь выравниваем наружный фон. Разделение этих задач предотвращает попытку исправлять внутренний текст изменениями внешних колонок.
Порядок и свободные ячейки
Записи автоматически размещаются в порядке HTML. Мы не задаём им номера линий и не используем плотное заполнение. Такое ограничение сохраняет последовательность курсов при изменении ширины. Первая запись остаётся первой, даже если она выделена отдельным классом. Подсветка варианта не должна менять позицию без объяснения в содержимом.
Для ручного опыта удалите временно три последних li. Ожидается, что сетка продолжит работать с оставшимися курсами. Затем добавьте длинный заголовок и увеличьте размер текста в браузере. Возможная проблема будет связана с содержимым и ограничениями, а не с необходимостью иметь ровно шесть карточек. После наблюдения восстановите исходный набор, чтобы следующий урок использовал прежние данные.
Проверьте, не появилось ли горизонтальное прокручивание всей страницы. Если оно есть, выберите конкретную коробку, которая выступает за доступное место. Сетка не отменяет явно заданные ширины потомков и не гарантирует перенос любых строк. У обложки уже есть максимальная ширина, у описания разрешён перенос длинной последовательности; эти локальные правила продолжают работать внутри нового контекста.
Не назначайте всем карточкам ручные номера строк только ради фиксированного снимка. При добавлении нового курса или изменении числа колонок такие координаты могут оставить неожиданную пустоту. Автоматическое размещение здесь выражает именно нашу задачу: последовательный список одинакового типа. Явные области сетки полезны для других композиций, где позиции имеют самостоятельный смысл, но в каталоге каждая запись должна оставаться равноправным участником общего набора.
Промежуток принадлежит сетке и не включается в текст каждой карточки. При сравнении доступной ширины учитывайте, что между тремя колонками есть два промежутка. Нельзя просто разделить ширину контейнера на три и затем добавить gap поверх полученных размеров, если дорожки уже должны поместиться. Единица fr помогает распределить оставшееся пространство после таких условий, поэтому нам не потребовалось вручную вычислять ширину каждого li.
Каталог теперь использует Grid для списка и Flexbox для коротких групп. Обычный поток остаётся внутри карточек. В следующем уроке добавим изменения уровня всей страницы: размер главного заголовка, ограничение длины вводного текста и перестройку шапки, когда её элементы перестают помещаться удобно.