Пошук уроків, статей та іншого контенту
Створимо адаптивний макет сторінки з шапкою, навігацією, основним вмістом і бічною панеллю через Grid Areas.
Створимо адаптивну сторінку з такою структурою:
шапка (header);
навігація (nav);
основний вміст (main);
бічна панель (aside);
підвал (footer).
Розкладку побудуємо за допомогою CSS Grid Areas. На широких екранах навігація буде ліворуч, основний вміст — у центрі, а бічна панель — праворуч. На вузьких екранах блоки розміщуватимуться вертикально.
Для макета використаємо іменовані області:
"header header header"
"nav main aside"
"footer footer footer"Кожен рядок описує окремий рядок Grid, а кожне слово — назву області.
CSS-властивість grid-template-areas визначає цю схему:
.page {
display: grid;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}Щоб елемент потрапив у певну область, йому потрібно призначити відповідне значення grid-area:
.site-header {
grid-area: header;
}
.main-navigation {
grid-area: nav;
}Назви областей не є значеннями класів. Вони працюють як координати всередині Grid-контейнера.
Для макета використаємо семантичні HTML-елементи. Це допомагає браузерам, пошуковим системам і допоміжним технологіям правильно визначати призначення частин сторінки.
<body>
<div class="page">
<header class="site-header">
<a class="logo" href="/">TechSpace</a>
<p class="site-description">Практичні матеріали для розробників</p>
</header>
<nav class="main-navigation" aria-label="Головна навігація">
<ul class="navigation-list">
<li><a href="#articles">Статті</a></li>
<li><a href="#courses">Курси</a></li>
<li><a href="#projects">Проєкти</a></li>
<li><a href="#about">Про платформу</a></li>
</ul>
</nav>
<main class="main-content" id="articles">
<article class="article">
<p class="article-category">CSS Layout</p>
<h1>Як будувати макети за допомогою Grid Areas</h1>
<p class="article-lead">
Іменовані області допомагають описувати структуру сторінки
зрозуміло та наочно.
</p>
<p>
CSS Grid дає змогу відокремити структуру макета від конкретного
розташування елементів у HTML. Завдяки цьому одну й ту саму
структуру можна адаптувати для різних розмірів екрана.
</p>
<h2 id="courses">Переваги іменованих областей</h2>
<ul>
<li>схема макета читається безпосередньо в CSS;</li>
<li>легко змінювати порядок блоків на різних екранах;</li>
<li>зменшується кількість ручного позиціонування;</li>
<li>структура стає зрозумілішою під час підтримки коду.</li>
</ul>
<p>
На відміну від позиціонування через номери рядків і колонок,
Grid Areas описують макет на рівні його логічних частин.
</p>
</article>
</main>
<aside class="sidebar">
<section class="sidebar-section">
<h2>Популярне</h2>
<ul class="sidebar-list">
<li><a href="#css">CSS Container Queries</a></li>
<li><a href="#flexbox">Flexbox у складних компонентах</a></li>
<li><a href="#performance">Оптимізація стилів</a></li>
</ul>
</section>
<section class="sidebar-section">
<h2>Підписка</h2>
<p>Отримуйте нові матеріали раз на тиждень.</p>
<button type="button">Підписатися</button>
</section>
</aside>
<footer class="site-footer">
<p>© 2025 TechSpace</p>
<p>Матеріали для веброзробників</p>
</footer>
</div>
</body>Спочатку створимо контейнер сітки та призначимо йому області:
.page {
display: grid;
grid-template-columns: 220px minmax(0, 1fr) 280px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
}grid-template-columns: 220px minmax(0, 1fr) 280px;Тут визначено три колонки:
навігація має фіксовану ширину 220px;
основний вміст займає весь доступний простір;
бічна панель має ширину 280px.
Функція minmax(0, 1fr) важлива для основного вмісту. Значення 0 дозволяє колонці стискатися, а 1fr віддає їй доступну частину вільного простору.
Якщо використати лише 1fr, довгий рядок або широкий дочірній елемент може спричинити горизонтальне переповнення Grid-контейнера. Значення minmax(0, 1fr) робить мінімальний розмір колонки явним.
grid-template-rows: auto 1fr auto;Рядки працюють так:
шапка отримує висоту за вмістом;
середній рядок займає весь вільний простір;
підвал отримує висоту за вмістом.
Разом із min-height: 100vh це дозволяє притиснути підвал до нижньої частини вікна, навіть якщо основного вмісту мало.
.site-header {
grid-area: header;
}
.main-navigation {
grid-area: nav;
}
.main-content {
grid-area: main;
}
.sidebar {
grid-area: aside;
}
.site-footer {
grid-area: footer;
}Ім’я в grid-area має точно збігатися з іменем у grid-template-areas. Наприклад, grid-area: header відповідає області header.
Нижче наведено повний документ, який можна зберегти у файл index.html і відкрити в браузері.
<!doctype html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Макет із Grid Areas</title>
<style>
:root {
--color-background: #f4f7fb;
--color-surface: #ffffff;
--color-text: #172033;
--color-muted: #64748b;
--color-border: #dbe3ef;
--color-accent: #2563eb;
--color-accent-dark: #1d4ed8;
--content-width: 1440px;
--page-padding: clamp(1rem, 3vw, 3rem);
--gap: clamp(1rem, 2vw, 2rem);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background: var(--color-background);
color: var(--color-text);
font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.6;
}
a {
color: inherit;
}
.page {
display: grid;
grid-template-columns: 220px minmax(0, 1fr) 280px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
gap: var(--gap);
width: min(100%, var(--content-width));
min-height: 100vh;
margin: 0 auto;
padding: var(--page-padding);
}
.site-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
grid-area: header;
padding: 1.5rem;
border: 1px solid var(--color-border);
border-radius: 1rem;
background: var(--color-surface);
}
.logo {
color: var(--color-accent);
font-size: 1.5rem;
font-weight: 800;
text-decoration: none;
}
.site-description {
margin: 0;
color: var(--color-muted);
text-align: right;
}
.main-navigation {
grid-area: nav;
align-self: start;
padding: 1.25rem;
border: 1px solid var(--color-border);
border-radius: 1rem;
background: var(--color-surface);
}
.navigation-list,
.sidebar-list {
display: grid;
gap: 0.5rem;
margin: 0;
padding: 0;
list-style: none;
}
.navigation-list a,
.sidebar-list a {
display: block;
padding: 0.65rem 0.75rem;
border-radius: 0.5rem;
text-decoration: none;
}
.navigation-list a:hover,
.navigation-list a:focus-visible,
.sidebar-list a:hover,
.sidebar-list a:focus-visible {
background: #eff6ff;
color: var(--color-accent-dark);
}
.main-content {
min-width: 0;
grid-area: main;
padding: clamp(1.25rem, 3vw, 3rem);
border: 1px solid var(--color-border);
border-radius: 1rem;
background: var(--color-surface);
}
.article {
max-width: 72ch;
margin: 0 auto;
}
.article-category {
margin: 0 0 0.5rem;
color: var(--color-accent);
font-size: 0.875rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
h1,
h2 {
line-height: 1.2;
}
h1 {
margin: 0 0 1rem;
font-size: clamp(2rem, 5vw, 4rem);
text-wrap: balance;
}
h2 {
margin-top: 2rem;
}
.article-lead {
color: var(--color-muted);
font-size: 1.2rem;
}
.sidebar {
display: grid;
align-content: start;
gap: 1rem;
grid-area: aside;
}
.sidebar-section {
padding: 1.25rem;
border: 1px solid var(--color-border);
border-radius: 1rem;
background: var(--color-surface);
}
.sidebar-section h2 {
margin: 0 0 0.75rem;
font-size: 1.15rem;
}
.sidebar-section p {
color: var(--color-muted);
}
button {
width: 100%;
padding: 0.75rem 1rem;
border: 0;
border-radius: 0.5rem;
background: var(--color-accent);
color: #ffffff;
cursor: pointer;
font: inherit;
font-weight: 700;
}
button:hover,
button:focus-visible {
background: var(--color-accent-dark);
}
.site-footer {
display: flex;
justify-content: space-between;
gap: 1rem;
grid-area: footer;
padding: 1rem 1.25rem;
border-top: 1px solid var(--color-border);
color: var(--color-muted);
font-size: 0.9rem;
}
.site-footer p {
margin: 0;
}
@media (max-width: 1100px) {
.page {
grid-template-columns: 200px minmax(0, 1fr);
grid-template-areas:
"header header"
"nav main"
"aside aside"
"footer footer";
}
.sidebar {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 700px) {
.page {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
.site-header,
.site-footer {
align-items: flex-start;
flex-direction: column;
}
.site-description {
text-align: left;
}
.navigation-list {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.sidebar {
grid-template-columns: 1fr;
}
}
@media (max-width: 420px) {
.navigation-list {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="page">
<header class="site-header">
<a class="logo" href="/">TechSpace</a>
<p class="site-description">Практичні матеріали для розробників</p>
</header>
<nav class="main-navigation" aria-label="Головна навігація">
<ul class="navigation-list">
<li><a href="#articles">Статті</a></li>
<li><a href="#courses">Курси</a></li>
<li><a href="#projects">Проєкти</a></li>
<li><a href="#about">Про платформу</a></li>
</ul>
</nav>
<main class="main-content" id="articles">
<article class="article">
<p class="article-category">CSS Layout</p>
<h1>Як будувати макети за допомогою Grid Areas</h1>
<p class="article-lead">
Іменовані області допомагають описувати структуру сторінки
зрозуміло та наочно.
</p>
<p>
CSS Grid дає змогу відокремити структуру макета від конкретного
розташування елементів у HTML. Завдяки цьому одну й ту саму
структуру можна адаптувати для різних розмірів екрана.
</p>
<h2 id="courses">Переваги іменованих областей</h2>
<ul>
<li>схема макета читається безпосередньо в CSS;</li>
<li>легко змінювати порядок блоків на різних екранах;</li>
<li>зменшується кількість ручного позиціонування;</li>
<li>структура стає зрозумілішою під час підтримки коду.</li>
</ul>
<p>
Одна і та сама HTML-структура може мати різне візуальне
представлення на різних ширинах екрана.
</p>
</article>
</main>
<aside class="sidebar">
<section class="sidebar-section">
<h2>Популярне</h2>
<ul class="sidebar-list">
<li><a href="#css">CSS Container Queries</a></li>
<li><a href="#flexbox">Flexbox у складних компонентах</a></li>
<li><a href="#performance">Оптимізація стилів</a></li>
</ul>
</section>
<section class="sidebar-section">
<h2>Підписка</h2>
<p>Отримуйте нові матеріали раз на тиждень.</p>
<button type="button">Підписатися</button>
</section>
</aside>
<footer class="site-footer">
<p>© 2025 TechSpace</p>
<p>Матеріали для веброзробників</p>
</footer>
</div>
</body>
</html>На широкому екрані використовується схема з трьома колонками:
.page {
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}На екрані середньої ширини бічна панель переміщується під основний вміст:
@media (max-width: 1100px) {
.page {
grid-template-columns: 200px minmax(0, 1fr);
grid-template-areas:
"header header"
"nav main"
"aside aside"
"footer footer";
}
}У цій схемі aside займає обидві колонки:
"aside aside"На малих екранах усі області стають одним вертикальним потоком:
@media (max-width: 700px) {
.page {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
}Важливо, що HTML при цьому не змінюється. Змінюється лише візуальна схема Grid.
grid-template-areasПравильно:
grid-template-areas:
"header header"
"main aside"
"footer footer";Неправильно:
grid-template-areas:
"header header header"
"main aside"
"footer footer footer";У неправильній схемі рядки мають різну кількість комірок, тому декларація не буде коректною.
Правильно:
grid-template-areas:
"header header"
"main main"
"aside aside";Неправильно:
grid-template-areas:
"header main"
"header aside";У другому прикладі область header утворює вертикальний прямокутник — це допустимо. Натомість така форма вже некоректна:
grid-template-areas:
"header header main"
"header aside aside";Тут область header має форму, яку неможливо описати одним прямокутником.
Якщо частина сітки має залишатися порожньою, використовують символ .:
.page {
display: grid;
grid-template-areas:
"header header"
"nav main"
". footer";
}Крапка означає комірку без іменованої області.
Основний вміст може містити довгі слова, URL-адреси, код або інші широкі елементи. Для Grid-елемента корисно явно встановити:
.main-content {
min-width: 0;
}Без цього мінімальний розмір Grid-елемента іноді визначатиметься його вмістом, а не доступною шириною колонки. У результаті сторінка може отримати горизонтальне прокручування.
Для тексту статті також можна обмежити довжину рядка:
.article {
max-width: 72ch;
margin: 0 auto;
}Одиниця ch приблизно відповідає ширині символу 0 у поточному шрифті. Обмеження ширини робить довгі текстові рядки зручнішими для читання.
grid-template-areas змінює візуальне розташування елементів, але не змінює порядок елементів у DOM.
Наприклад, на широкому екрані візуально можна розмістити aside праворуч, хоча в HTML він іде після main. На вузькому екрані він природно з’явиться після основного вмісту.
Це зручно, якщо порядок у HTML уже відповідає логіці читання:
шапка;
навігація;
основний матеріал;
додатковий вміст;
підвал.
Не варто змінювати порядок лише для того, щоб отримати певне візуальне розташування. У складніших випадках це може створити невідповідність між візуальним порядком і порядком навігації з клавіатури або читання скринридером.
Grid Areas описують структуру макета декларативно:
.page {
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}Під час використання position: absolute розробник вручну визначає координати елементів. Такий підхід складніше адаптувати, оскільки блоки вилучаються з нормального потоку документа.
Grid Areas краще підходять для великих областей сторінки:
шапки;
бічної навігації;
основної колонки;
додаткової панелі;
підвалу.
Водночас внутрішній вміст окремої області можна верстати за допомогою власного Grid або Flexbox. Наприклад, навігація сторінки є Grid-елементом у зовнішньому макеті, але її список також може мати власну сітку:
.navigation-list {
display: grid;
gap: 0.5rem;
}Внутрішня сітка не конфліктує із зовнішньою. Кожен Grid-контейнер керує лише своїми безпосередніми дочірніми елементами.
Під час розробки відкрийте інструменти розробника браузера та перевірте:
чи всі необхідні елементи мають grid-area;
чи відповідають назви grid-area назвам у grid-template-areas;
чи не виникає горизонтальне переповнення;
чи не стають текст і кнопки надто вузькими;
чи зберігається логічний порядок на мобільному екрані;
чи не перекриваються області після зміни ширини вікна.
Для перевірки адаптивності поступово змінюйте ширину viewport. Важливо тестувати не лише типові ширини, а й проміжні значення, оскільки проблеми часто з’являються саме між основними брейкпоінтами.
.page {
grid-template-areas:
"header main";
}
.site-header {
grid-area: top;
}У цьому випадку top не існує в схемі сітки. Потрібно використовувати однакову назву:
.site-header {
grid-area: header;
}Якщо для одного breakpoint задано дві колонки, кожен рядок області має містити дві назви або дві крапки:
grid-template-columns: 1fr 1fr;
grid-template-areas:
"main aside"
"footer footer";Не можна залишати в одному з рядків три комірки.
display: gridgrid-template-areas працює лише для Grid-контейнера:
.page {
display: grid;
grid-template-areas:
"header"
"main";
}Якщо display: grid відсутній, іменовані області не застосовуються.
Схема на кшталт цієї може бути непридатною для вузьких екранів:
grid-template-columns: 300px 900px 300px;Сума ширин перевищить ширину більшості вікон. Для гнучкої колонки краще використовувати minmax(0, 1fr), а для вузьких екранів — окрему адаптивну схему з однією колонкою.
overflow-x: hidden як виправленняГлобальне приховування горизонтального переповнення не усуває причину проблеми. Спочатку потрібно перевірити:
фіксовані ширини;
довгі рядки;
мінімальні розміри Grid-елементів;
зображення або інші дочірні елементи.
Для основної колонки часто необхідно додати min-width: 0.
grid-template-areas дає змогу описати макет іменованими областями.
Значення grid-area пов’язує HTML-елемент із відповідною областю.
Схема повинна мати однакову кількість комірок у кожному рядку.
Одна іменована область має утворювати прямокутну форму.
Адаптивність можна реалізувати зміною grid-template-areas у media queries.
minmax(0, 1fr) і min-width: 0 допомагають уникати горизонтального переповнення.
Семантичний порядок HTML бажано зберігати логічним незалежно від візуальної схеми.
Grid Areas зручно використовувати для макета сторінки, а Grid або Flexbox — для внутрішньої структури окремих блоків.