Пошук уроків, статей та іншого контенту
Розробіть макет блогу зі списком статей, картками публікацій, категоріями, бічною панеллю та окремою зоною навігації.
Створимо адаптивний макет блогу, у якому будуть:
окрема верхня навігація;
заголовок і опис блогу;
сітка карток статей;
бічна панель із категоріями;
блок популярних публікацій;
адаптивне розташування для вузьких екранів.
Для побудови макета використаємо семантичні HTML-елементи та CSS Grid.
Основна структура матиме такий вигляд:
body
└── header
└── nav
└── main
├── section.intro
└── div.content-layout
├── section.posts
└── aside.sidebar<header> — верхня частина сторінки;
<nav> — окрема зона навігації;
<main> — основний вміст сторінки;
<section> — логічні блоки контенту;
<article> — окрема стаття;
<aside> — додатковий вміст, наприклад категорії або популярні публікації;
<footer> — нижня частина картки або сторінки.
Створіть файл index.html і додайте до нього таку структуру:
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TechNotes — блог про веброзробку</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<div class="container header-content">
<a class="logo" href="/">TechNotes</a>
<nav class="main-navigation" aria-label="Головна навігація">
<ul class="navigation-list">
<li>
<a class="navigation-link active" href="/">Головна</a>
</li>
<li>
<a class="navigation-link" href="#articles">Статті</a>
</li>
<li>
<a class="navigation-link" href="#categories">Категорії</a>
</li>
<li>
<a class="navigation-link" href="#about">Про блог</a>
</li>
</ul>
</nav>
</div>
</header>
<main>
<section class="intro container">
<p class="eyebrow">Блог розробника</p>
<h1>Ідеї та практики сучасної веброзробки</h1>
<p class="intro-text">
Пояснюємо складні технічні концепції просто: від основ HTML і CSS
до створення зручних інтерфейсів.
</p>
</section>
<div class="container content-layout">
<section class="posts-section" id="articles" aria-labelledby="articles-title">
<div class="section-heading">
<div>
<p class="eyebrow">Останні матеріали</p>
<h2 id="articles-title">Нові статті</h2>
</div>
<a class="all-articles-link" href="#articles">
Усі статті
</a>
</div>
<div class="posts-grid">
<article class="post-card featured-post">
<div class="post-visual post-visual-purple">
<span>HTML</span>
</div>
<div class="post-content">
<div class="post-meta">
<span class="post-category">HTML</span>
<time datetime="2026-08-08">8 серпня 2026</time>
</div>
<h3>
<a href="#semantic-html">
Семантична HTML-розмітка для доступних сторінок
</a>
</h3>
<p>
Як правильно структурувати сторінку за допомогою семантичних
елементів HTML.
</p>
<footer class="post-footer">
<span>6 хв читання</span>
<a class="read-link" href="#semantic-html" aria-label="Читати статтю про семантичну HTML-розмітку">
→
</a>
</footer>
</div>
</article>
<article class="post-card">
<div class="post-visual post-visual-blue">
<span>CSS</span>
</div>
<div class="post-content">
<div class="post-meta">
<span class="post-category">CSS</span>
<time datetime="2026-08-05">5 серпня 2026</time>
</div>
<h3>
<a href="#css-grid">
CSS Grid: побудова складних макетів
</a>
</h3>
<p>
Розбираємо колонки, області сітки та адаптивне розташування
елементів.
</p>
<footer class="post-footer">
<span>8 хв читання</span>
<a class="read-link" href="#css-grid" aria-label="Читати статтю про CSS Grid">
→
</a>
</footer>
</div>
</article>
<article class="post-card">
<div class="post-visual post-visual-orange">
<span>UX</span>
</div>
<div class="post-content">
<div class="post-meta">
<span class="post-category">UX/UI</span>
<time datetime="2026-08-02">2 серпня 2026</time>
</div>
<h3>
<a href="#interface">
Як створити зрозумілу структуру інтерфейсу
</a>
</h3>
<p>
Принципи візуальної ієрархії, відступів і групування контенту.
</p>
<footer class="post-footer">
<span>5 хв читання</span>
<a class="read-link" href="#interface" aria-label="Читати статтю про структуру інтерфейсу">
→
</a>
</footer>
</div>
</article>
<article class="post-card">
<div class="post-visual post-visual-green">
<span>JS</span>
</div>
<div class="post-content">
<div class="post-meta">
<span class="post-category">JavaScript</span>
<time datetime="2026-07-29">29 липня 2026</time>
</div>
<h3>
<a href="#javascript-dom">
Робота з DOM без зайвої складності
</a>
</h3>
<p>
Як знаходити елементи на сторінці та змінювати їхній вміст.
</p>
<footer class="post-footer">
<span>7 хв читання</span>
<a class="read-link" href="#javascript-dom" aria-label="Читати статтю про роботу з DOM">
→
</a>
</footer>
</div>
</article>
</div>
</section>
<aside class="sidebar">
<section class="sidebar-card" id="categories">
<h2>Категорії</h2>
<ul class="category-list">
<li>
<a href="#html">
<span>HTML</span>
<span class="category-count">12</span>
</a>
</li>
<li>
<a href="#css">
<span>CSS</span>
<span class="category-count">18</span>
</a>
</li>
<li>
<a href="#javascript">
<span>JavaScript</span>
<span class="category-count">24</span>
</a>
</li>
<li>
<a href="#accessibility">
<span>Доступність</span>
<span class="category-count">8</span>
</a>
</li>
</ul>
</section>
<section class="sidebar-card popular-card">
<p class="eyebrow">Читають зараз</p>
<h2>Популярні статті</h2>
<ol class="popular-list">
<li>
<a href="#responsive-design">
<span class="popular-number">01</span>
<span>
<strong>Адаптивний дизайн: базові принципи</strong>
<small>10 хв читання</small>
</span>
</a>
</li>
<li>
<a href="#flexbox">
<span class="popular-number">02</span>
<span>
<strong>Flexbox для повсякденних задач</strong>
<small>7 хв читання</small>
</span>
</a>
</li>
<li>
<a href="#forms">
<span class="popular-number">03</span>
<span>
<strong>Зручні форми та стани елементів</strong>
<small>9 хв читання</small>
</span>
</a>
</li>
</ol>
</section>
<section class="sidebar-card about-card" id="about">
<h2>Про блог</h2>
<p>
TechNotes — навчальний блог для тих, хто створює вебінтерфейси
та хоче краще розуміти технології фронтенду.
</p>
</section>
</aside>
</div>
</main>
<footer class="site-footer">
<div class="container">
<p>© 2026 TechNotes</p>
</div>
</footer>
</body>
</html>Створіть файл styles.css. Спочатку додамо скидання стандартних відступів, змінні кольорів і загальні стилі.
:root {
--color-background: #f5f7fb;
--color-surface: #ffffff;
--color-text: #172033;
--color-muted: #687386;
--color-border: #e4e8f0;
--color-primary: #5b4bdb;
--color-primary-dark: #4638b9;
--color-dark-surface: #1d2638;
--radius-small: 10px;
--radius-medium: 16px;
--radius-large: 24px;
--shadow-card: 0 12px 30px rgba(34, 48, 84, 0.08);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background-color: var(--color-background);
color: var(--color-text);
font-family: Arial, sans-serif;
line-height: 1.6;
}
a {
color: inherit;
text-decoration: none;
}
.container {
width: min(1120px, calc(100% - 40px));
margin: 0 auto;
}Властивість box-sizing: border-box допомагає передбачувано розраховувати ширину елементів: внутрішні відступи та рамка входять у вказану ширину.
Функція min() обмежує ширину контейнера значенням 1120px, але не дозволяє йому бути ширшим за доступний простір із бічними відступами 20px.
Навігація має власний фон і нижню межу. Логотип та список посилань розташовуємо в один рядок за допомогою Flexbox.
.site-header {
background-color: var(--color-surface);
border-bottom: 1px solid var(--color-border);
}
.header-content {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 76px;
gap: 32px;
}
.logo {
color: var(--color-primary);
font-size: 1.35rem;
font-weight: 800;
letter-spacing: -0.04em;
}
.navigation-list {
display: flex;
align-items: center;
gap: 8px;
margin: 0;
padding: 0;
list-style: none;
}
.navigation-link {
display: block;
padding: 10px 14px;
border-radius: var(--radius-small);
color: var(--color-muted);
font-size: 0.95rem;
transition: background-color 180ms ease, color 180ms ease;
}
.navigation-link:hover,
.navigation-link:focus-visible,
.navigation-link.active {
background-color: #eeecff;
color: var(--color-primary);
}
.navigation-link:focus-visible,
.all-articles-link:focus-visible,
.post-card a:focus-visible,
.category-list a:focus-visible,
.popular-list a:focus-visible {
outline: 3px solid rgba(91, 75, 219, 0.35);
outline-offset: 3px;
}Клас active позначає поточний розділ. Псевдоклас :focus-visible забезпечує видимий стан для користувачів, які переміщуються сторінкою за допомогою клавіатури.
Заголовковий блок відокремимо від сітки статей вертикальними відступами.
.intro {
padding-top: 72px;
padding-bottom: 52px;
}
.eyebrow {
margin: 0 0 10px;
color: var(--color-primary);
font-size: 0.75rem;
font-weight: 800;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.intro h1 {
max-width: 720px;
margin: 0;
font-size: clamp(2.2rem, 5vw, 4.2rem);
line-height: 1.05;
letter-spacing: -0.06em;
}
.intro-text {
max-width: 620px;
margin: 24px 0 0;
color: var(--color-muted);
font-size: 1.1rem;
}Функція clamp() задає:
мінімальний розмір шрифту;
гнучкий розмір залежно від ширини екрана;
максимальний розмір шрифту.
Тому заголовок поступово змінює розмір, але не стає надто малим або великим.
Основний вміст складається з двох колонок:
широка колонка для статей;
вужча колонка для бічної панелі.
.content-layout {
display: grid;
grid-template-columns: minmax(0, 1fr) 300px;
align-items: start;
gap: 32px;
}
.posts-section {
min-width: 0;
}
.section-heading {
display: flex;
align-items: end;
justify-content: space-between;
gap: 20px;
margin-bottom: 24px;
}
.section-heading h2,
.sidebar-card h2 {
margin: 0;
font-size: 1.35rem;
line-height: 1.2;
}
.all-articles-link {
color: var(--color-primary);
font-size: 0.9rem;
font-weight: 700;
}
.all-articles-link:hover {
color: var(--color-primary-dark);
}Значення minmax(0, 1fr) для першої колонки важливе: воно дозволяє колонці стискатися, навіть якщо всередині є довгий текст.
Картки статей розташуємо в окремій CSS Grid-сітці. На широких екранах буде дві колонки.
.posts-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 24px;
}
.post-card {
overflow: hidden;
border: 1px solid var(--color-border);
border-radius: var(--radius-medium);
background-color: var(--color-surface);
box-shadow: var(--shadow-card);
transition: transform 180ms ease, box-shadow 180ms ease;
}
.post-card:hover {
transform: translateY(-4px);
box-shadow: 0 18px 36px rgba(34, 48, 84, 0.13);
}
.post-visual {
display: flex;
align-items: end;
min-height: 170px;
padding: 20px;
color: #ffffff;
font-size: 1.8rem;
font-weight: 800;
letter-spacing: -0.05em;
}
.post-visual-purple {
background: linear-gradient(135deg, #7869ed, #4332b8);
}
.post-visual-blue {
background: linear-gradient(135deg, #4b9ee8, #1854a2);
}
.post-visual-orange {
background: linear-gradient(135deg, #f6a04d, #d5542d);
}
.post-visual-green {
background: linear-gradient(135deg, #46be91, #24765d);
}
.post-content {
padding: 22px;
}
.post-meta {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
color: var(--color-muted);
font-size: 0.78rem;
}
.post-category {
color: var(--color-primary);
font-weight: 800;
text-transform: uppercase;
}
.post-card h3 {
margin: 16px 0 10px;
font-size: 1.2rem;
line-height: 1.3;
}
.post-card h3 a:hover {
color: var(--color-primary);
}
.post-card p {
margin: 0;
color: var(--color-muted);
font-size: 0.93rem;
}
.post-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid var(--color-border);
color: var(--color-muted);
font-size: 0.8rem;
}
.read-link {
display: grid;
width: 34px;
height: 34px;
place-items: center;
border-radius: 50%;
background-color: #eeecff;
color: var(--color-primary);
font-size: 1.2rem;
font-weight: 700;
}
.read-link:hover {
background-color: var(--color-primary);
color: #ffffff;
}У цьому прикладі перша картка має клас featured-post. За потреби її можна візуально виділити, наприклад збільшити верхню область:
.featured-post .post-visual {
min-height: 210px;
}
.featured-post h3 {
font-size: 1.35rem;
}Клас не змінює структуру HTML, а лише додає картці особливе оформлення.
Бічна панель містить самостійні картки. Це дозволяє візуально відділити категорії, популярні матеріали та інформацію про блог.
.sidebar {
display: grid;
gap: 24px;
}
.sidebar-card {
padding: 24px;
border: 1px solid var(--color-border);
border-radius: var(--radius-medium);
background-color: var(--color-surface);
}
.sidebar-card h2 {
margin-bottom: 20px;
}
.category-list,
.popular-list {
margin: 0;
padding: 0;
list-style: none;
}
.category-list {
display: grid;
gap: 8px;
}
.category-list a {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 12px 14px;
border-radius: var(--radius-small);
color: var(--color-text);
transition: background-color 180ms ease, color 180ms ease;
}
.category-list a:hover {
background-color: #f0efff;
color: var(--color-primary);
}
.category-count {
display: grid;
min-width: 28px;
height: 28px;
place-items: center;
border-radius: 50%;
background-color: #f0f2f7;
color: var(--color-muted);
font-size: 0.78rem;
}
.popular-card {
background-color: var(--color-dark-surface);
color: #ffffff;
}
.popular-card .eyebrow {
color: #aaa1ff;
}
.popular-list {
display: grid;
gap: 20px;
}
.popular-list li + li {
padding-top: 20px;
border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.popular-list a {
display: grid;
grid-template-columns: 34px 1fr;
gap: 12px;
}
.popular-number {
color: #aaa1ff;
font-size: 0.8rem;
font-weight: 800;
}
.popular-list strong {
display: block;
font-size: 0.9rem;
line-height: 1.35;
}
.popular-list small {
display: block;
margin-top: 6px;
color: #aeb7c9;
font-size: 0.75rem;
}
.about-card p {
margin: 0;
color: var(--color-muted);
font-size: 0.92rem;
}Селектор .category-list a стилізує все посилання категорії, а .category-list a:hover змінює його вигляд під час наведення. Кількість статей є окремим елементом, тому її можна оформити як круглий бейдж.
.site-footer {
margin-top: 72px;
padding: 28px 0;
border-top: 1px solid var(--color-border);
color: var(--color-muted);
font-size: 0.85rem;
}
.site-footer p {
margin: 0;
}На середніх екранах бічна панель стає нижчою за основний список статей. На вузьких екранах картки та навігація переходять в одну колонку.
@media (max-width: 900px) {
.content-layout {
grid-template-columns: 1fr;
}
.sidebar {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.about-card {
grid-column: 1 / -1;
}
}
@media (max-width: 640px) {
.container {
width: min(100% - 28px, 1120px);
}
.header-content {
align-items: flex-start;
flex-direction: column;
gap: 12px;
padding-top: 18px;
padding-bottom: 18px;
}
.navigation-list {
flex-wrap: wrap;
}
.navigation-link {
padding: 8px 10px;
font-size: 0.88rem;
}
.intro {
padding-top: 48px;
padding-bottom: 36px;
}
.intro h1 {
font-size: 2.4rem;
}
.section-heading {
align-items: flex-start;
flex-direction: column;
gap: 10px;
}
.posts-grid,
.sidebar {
grid-template-columns: 1fr;
}
.about-card {
grid-column: auto;
}
.post-visual,
.featured-post .post-visual {
min-height: 140px;
}
.site-footer {
margin-top: 48px;
}
}При ширині до 900px:
основна область і бічна панель займають окремі рядки;
блоки бічної панелі розташовуються у дві колонки.
При ширині до 640px:
навігація може переноситися на новий рядок;
статті розташовуються по одній;
бічна панель також переходить в одну колонку;
зменшуються відступи та висота декоративних блоків.
Перевірити адаптивність можна, змінюючи ширину вікна браузера або використовуючи режим перегляду для мобільних пристроїв у DevTools.
CSS Grid зручно використовувати для двовимірного розташування:
сторінка має колонки та рядки;
список статей утворює регулярну сітку;
бічна панель має кілька вертикальних блоків;
кількість колонок легко змінюється через медіазапити.
Flexbox у цьому прикладі використовується для одновимірних компонентів:
вирівнювання логотипа та навігації;
розташування метаданих статті;
вирівнювання заголовка секції та посилання;
вирівнювання елементів усередині картки.
Після запуску прикладу перевірте:
Чи зберігається однакова висота карток у рядку.
Чи не виходять довгі заголовки за межі картки.
Чи достатній контраст тексту на фоні.
Чи можна перейти всіма посиланнями за допомогою клавіші Tab.
Чи не з’являється горизонтальна прокрутка на вузькому екрані.
Чи зрозуміло, де закінчується список статей і починається бічна панель.
Для реального проєкту декоративні блоки .post-visual можна замінити на зображення, але структура картки при цьому залишиться такою самою.
.container {
width: 1120px;
}Такий контейнер буде ширшим за вузький екран. Користувач отримає горизонтальну прокрутку.
Краще обмежувати максимальну ширину та залишати бічні відступи:
.container {
width: min(1120px, calc(100% - 40px));
margin: 0 auto;
}<div>Якщо кожен блок створено через <div>, структура сторінки стає менш зрозумілою для браузера, пошукових систем і допоміжних технологій.
Для статей використовуйте <article>, для додаткового контенту — <aside>, а для навігації — <nav>.
Секції мають бути зрозумілими не лише візуально. Для цього використовуйте заголовки <h1>, <h2> та <h3> у правильній ієрархії.
На сторінці має бути один основний <h1>, а заголовки секцій і карток можуть використовувати <h2> та <h3>.
Навігаційні посилання краще розміщувати в <ul>, а кожне посилання — всередині <li>. Це забезпечує зрозумілу структуру та коректну роботу допоміжних технологій.
Відступи, комфортні для широкого монітора, можуть займати більшу частину вузького екрана. У медіазапитах зменшуйте горизонтальні та вертикальні відступи.
Якщо стилізувати лише :hover, користувачі клавіатури не бачитимуть, який елемент активний. Додавайте :focus-visible до інтерактивних елементів.
У цьому макеті ви:
створили семантичну структуру блогу;
винесли навігацію в окрему зону;
побудували сітку статей за допомогою CSS Grid;
оформили публікації як незалежні картки;
додали категорії та популярні статті в бічну панель;
використали Flexbox для вирівнювання елементів усередині компонентів;
зробили макет адаптивним за допомогою медіазапитів;
додали стани наведення та фокусу для посилань.