Готовые макеты: holy grail, sticky footer, карточки

Собираем из Grid и Flexbox проверенные временем макеты: holy grail, прилипающий футер, центрирование и резиновую сетку карточек.

Макетный паттерн — это готовый, многократно проверенный рецепт раскладки страницы (шапка-сайдбар-контент-футер, карточки, центрирование), который решает типовую задачу минимумом CSS.

Зачем это знать на практике

Девяносто процентов интерфейсов — это пять-шесть повторяющихся макетов. Зная их наизусть, вы не изобретаете велосипед на каждом проекте и не тащите тяжёлый фреймворк ради «шапки и сайдбара». Современные Grid и Flexbox решают классические задачи, на которые раньше уходили float-хаки и таблицы, буквально в несколько строк. Этот набор рецептов — ваш быстрый старт для любой страницы.

Holy Grail на Grid

«Святой Грааль» вёрстки — шапка, подвал во всю ширину и три колонки между ними (навигация, контент, сайдбар), где центральная тянется. Двадцать лет это была боль на float; на Grid — несколько строк с именованными областями:

.holy-grail {
  display: grid;
  grid-template:
    "header header header" auto
    "nav    main   aside " 1fr
    "footer footer footer" auto
    / 200px 1fr 240px;     /* ширины колонок после слэша */
  min-height: 100vh;
  gap: 16px;
}
.holy-grail > header { grid-area: header; }
.holy-grail > nav    { grid-area: nav; }
.holy-grail > main   { grid-area: main; }
.holy-grail > aside  { grid-area: aside; }
.holy-grail > footer { grid-area: footer; }

Шорткат grid-template объединяет области, высоты строк и (после /) ширины колонок. Строка контента получает 1fr — она съедает всю свободную высоту, прижимая футер вниз. Боковые колонки фиксированы, main тянется. Под мобильный достаточно переписать одну карту областей в медиазапросе, сложив всё в столбик.

А вот разметка, к которой подключается этот CSS:

<div class="holy-grail">
  <header>Шапка</header>
  <nav>Навигация</nav>
  <main>Основной контент</main>
  <aside>Сайдбар</aside>
  <footer>Подвал</footer>
</div>

Sticky footer: подвал у нижнего края

Прилипающий футер — когда контента мало, подвал всё равно прижат к низу окна, а не висит посреди экрана; когда контента много — футер уезжает вниз естественно. Самый чистый способ — flex-колонка с растущим контентом:

body {
  min-height: 100vh;       /* тело минимум на весь экран */
  margin: 0;
  display: flex;
  flex-direction: column;  /* шапка-контент-футер в столбик */
}
main { flex: 1; }          /* контент забирает всё свободное место */

Здесь flex: 1 на main заставляет контент растянуться и вытолкнуть футер к низу. Альтернатива на Grid: body { min-height: 100vh; display: grid; grid-template-rows: auto 1fr auto; } — средняя строка 1fr делает то же самое. Не путайте этот приём с position: sticky — у них разные задачи: sticky приклеивает элемент при прокрутке, а sticky footer держит подвал внизу короткой страницы.

Резиновая сетка карточек одной строкой

Адаптивную галерею карточек, которая сама меняет число колонок, мы уже видели в уроке про Grid. Это настолько частый паттерн, что заслуживает повтора как самостоятельный рецепт:

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
  gap: 24px;
}

Обратите внимание на min(100%, 260px) внутри minmax: на очень узких экранах (уже 260px) это не даст карточке прорвать контейнер — её минимум станет равен 100% ширины, и она аккуратно займёт всю строку. Без этой обёртки на телефоне-«малыше» появилась бы горизонтальная прокрутка. Один auto-fill заменяет три-четыре медиазапроса «на 2 / 3 / 4 колонки».

Центрирование: раз и навсегда

«Как отцентрировать div» перестало быть мемом. И Flexbox, и Grid центрируют по обеим осям двумя-тремя свойствами:

/* Flexbox */
.center-flex {
  display: flex;
  justify-content: center; /* по горизонтали */
  align-items: center;     /* по вертикали */
  min-height: 100vh;
}

/* Grid — ещё короче */
.center-grid {
  display: grid;
  place-items: center;     /* сразу обе оси */
  min-height: 100vh;
}

Шорткат place-items: center — это align-items: center плюс justify-items: center одной строкой. Для центрирования одного блока в Grid это самый лаконичный способ из существующих.

Панель «контент + действие по краям»

Ещё один вездесущий рецепт — шапка-тулбар, где заголовок слева, кнопки справа, всё по центру вертикали:

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between; /* раскидать по краям */
  gap: 16px;
}
/* прижать конкретную группу вправо, не трогая остальных: */
.toolbar .actions { margin-left: auto; }

Трюк margin-left: auto на элементе flex-строки съедает всё свободное место слева от него и толкает его (и всё, что правее) к правому краю — удобно, когда space-between не подходит из-за числа элементов.

Как это работает под капотом

Все эти паттерны опираются на два механизма. Первый — 1fr и flex: 1, которые поглощают свободное пространство по своей оси; именно они «выталкивают» футер вниз и растягивают центральную колонку. Второй — связка min-height: 100vh + растущий трек: высота вьюпорта задаёт минимум, а 1fr/flex: 1 распределяет остаток, поэтому на короткой странице футер всё равно у нижнего края, а на длинной — уезжает за экран. Центрирование же работает потому, что и Grid, и Flexbox умеют выравнивать по двум осям сразу, чего не давала старая поточная модель: place-items/(justify-content + align-items) ставят единственный элемент ровно в середину контейнера независимо от его размеров. Понимание этой пары — «кто ест свободное место» и «кто выравнивает по двум осям» — позволяет собрать почти любой макет без подбора магических чисел.

Частые ошибки

Sticky footer без min-height на контейнере. Если у body нет min-height: 100vh, растущему main нечего растягивать на короткой странице, и футер всплывает к середине. Минимум по высоте обязателен.

Карточки без min() переполняют узкий экран. minmax(260px, 1fr) на телефоне уже 260px даёт горизонтальную прокрутку; обёртка min(100%, 260px) это снимает.

Путают sticky footer и position: sticky. Это разные вещи: первый держит подвал внизу короткой страницы (Flexbox/Grid), второй приклеивает элемент при прокрутке (position: sticky; top: 0).

Лишний margin: 0 auto при flex-центрировании. Привычка центрировать блок через margin: 0 auto внутри уже flex-контейнера сбивает выравнивание — здесь достаточно justify-content/align-items на родителе.

Итоги

  • Holy Grail собирается на Grid через grid-template с именованными областями; строка контента 1fr прижимает футер.
  • Sticky footer — это flex-колонка (flex-direction: column) или Grid (grid-template-rows: auto 1fr auto) при min-height: 100vh и flex: 1/1fr на контенте.
  • Резиновая галерея: repeat(auto-fill, minmax(min(100%, 260px), 1fr)) — обёртка min() спасает от прокрутки на узких экранах.
  • Центрирование: place-items: center (Grid) или justify-content + align-items (Flexbox).
  • Под капотом всё держится на «кто ест свободное место» (1fr/flex: 1) и «кто выравнивает по двум осям».
Проверьте себя
1. Почему на короткой странице sticky footer всплывает к середине экрана?
AУ контейнера (body) не задан min-height: 100vh, поэтому растущему контенту нечего растягивать
BНе хватает position: sticky на футере
CФутеру нужен margin-top: auto в любом случае
DGrid не умеет прижимать футер, нужен только Flexbox
2. Зачем в резиновой сетке писать minmax(min(100%, 260px), 1fr) вместо minmax(260px, 1fr)?
AЧтобы на экранах уже 260px карточка не прорывала контейнер и не появлялась горизонтальная прокрутка
BЧтобы карточки всегда были шириной ровно 260px
CЧтобы отключить auto-fill
DЭто синонимы, разницы нет