HTML & CSS

Адаптивний дизайн. Media Queries. Частина 1

Основи адаптивного дизайну: viewport meta-тег, синтаксис @media, типи та features, breakpoints, Mobile-first vs Desktop-first підхід, responsive images, srcset та picture.

Адаптивний дизайн. Media Queries

60% трафіку — мобільні пристрої. І що?

У 2009 році Ітан Маркотт (Ethan Marcotte) опублікував статтю "Responsive Web Design", яка змінила підхід до верстки. До цього існувало два варіанти: або окремий мобільний сайт (m.example.com), або декстопний сайт із горизонтальним скролом на телефоні. Обидва — компроміси.

Сьогодні більше 60% веб-трафіку у світі приходить із мобільних пристроїв. Це означає, що кожна сторінка, яку ви верстаєте, буде переглядатися на смартфонах, планшетах, ноутбуках, моніторах 4K і навіть розумних годинниках. Адаптивний дизайн (Responsive Web Design, RWD) — це не опція, це стандарт.

У попередній статті ми розглянули позиціонування. Тепер з'ясуємо, як зробити, щоб той самий HTML виглядав чудово на будь-якому екрані.

Loading diagram...
timeline
    title Еволюція підходів до веб-дизайну
    1990-2000 : Fixed Width
              : Ширина 640px, потім 800px, потім 1024px
    2000-2007 : Table-based layouts
              : Таблиці для верстки, фіксована ширина
    2007 : iPhone революція
         : Мобільний інтернет стає масовим
    2010 : Responsive Web Design
         : Концепція Ethan Marcotte
         : float + percent + media queries
    2015 : Flexbox & Mobile-first
         : Гнучкі макети стандартом
    2017 : CSS Grid
         : Двовимірні адаптивні сітки
    2021 : Container Queries (draft)
         : Компоненти адаптуються до контейнера
    2023 : Container Queries (all browsers)
         : @container — новий стандарт

Три кити адаптивного дизайну

Оригінальна формула Маркотта — три компоненти, які разом складають адаптивний дизайн:

Гнучкі сітки

Використовуйте відносні одиниці (%, fr, em, rem) замість фіксованих (px). Елементи масштабуються пропорційно.

Гнучкі медіа

Зображення та відео пристосовуються до контейнера через max-width: 100%, srcset, <picture>.

Media Queries

CSS-правила, що застосовуються залежно від характеристик пристрою — ширини екрана, орієнтації, роздільної здатності.

<meta name="viewport"> — обов'язковий перший крок

Перш ніж писати будь-який адаптивний CSS — ніколи не забувайте цей мета-тег у <head>:

<meta name="viewport" content="width=device-width, initial-scale=1" />

Без нього мобільні браузери використовують "емуляцію десктопу": вони відображають сторінку у віртуальному вікні шириною ~980px, а потім масштабують його (зменшують) до реальної ширини екрана. Результат — дрібний нечитабельний текст, тому що всі ваші media queries з max-width: 768px не спрацьовують — браузер "думає", що ширина вікна 980px.

З тегом браузер встановлює ширину viewport рівній реальній фізичній ширині пристрою, і ваші media queries починають коректно спрацьовувати.

Ніколи не пишітьuser-scalable=no або maximum-scale=1 у viewport meta-тегу. Це блокує масштабування сторінки, що є серйозною проблемою доступності (accessibility): люди зі слабким зором не зможуть збільшити текст. Крім того, це суперечить рекомендаціям WCAG 2.1.

Розберемо атрибут content:

  • width=device-width — встановити ширину viewport рівній ширині пристрою (в CSS-пікселях, не фізичних).
  • initial-scale=1 — початковий масштаб = 1 (без збільшення/зменшення).

Синтаксис @media — базова структура

Media query (медіа-запит) — це умова, яка визначає, коли застосовується блок CSS:

/* Базова структура */
@media тип-медіа and (умова) {
    /* CSS-правила, що діють тільки при виконанні умови */
    .element {
        color: red;
    }
}

Компоненти media query:

  1. Тип медіа (media type) — необов'язковий. Якщо опустити — застосовується до всіх.
  2. and — логічний оператор "і".
  3. Умова (media feature) у дужках.

Вкладені правила та пріоритет

Правила всередині @media мають такий самий специфічний вес, що й звичайні правила. Пріоритет визначається порядком у файлі — те, що написане пізніше, перемагає при однаковому специфічному векторі:

/* Базові стилі */
.btn {
    background: blue;
}

/* Media query — застосовується ПРИ умові */
@media (max-width: 600px) {
    .btn {
        background: red;
    } /* Перекриває blue на малих екранах */
}

Типи медіа (Media Types)

@media screen {
    /* Для екранів (монітори, телефони, планшети) */
}
@media print {
    /* Для друку — CSS друку */
}
@media all {
    /* Для всіх пристроїв (за замовчуванням) */
}

print — недооцінений тип. Він дозволяє задати стилі спеціально для друку:

@media print {
    .no-print {
        display: none;
    } /* Сховати навігацію, рекламу */
    body {
        font-size: 12pt;
    } /* Пунктовий розмір для друку */
    a::after {
        content: ' (' attr(href) ')';
    } /* Показати URL */
    @page {
        margin: 2cm;
    } /* Поля сторінки */
}

Media Features — умови медіа-запитів

min-width та max-width — найуживаніші

/* Застосувати, коли ширина viewport ≥ 768px */
@media (min-width: 768px) { ... }

/* Застосувати, коли ширина viewport ≤ 767px */
@media (max-width: 767px) { ... }

/* Діапазон: від 768px до 1199px */
@media (min-width: 768px) and (max-width: 1199px) { ... }

Новий синтаксис діапазонів (2022+)

Сучасна специфікація Media Queries Level 4 дозволяє більш зрозумілий синтаксис:

/* Замість: @media (max-width: 767px) */
@media (width <= 767px) { ... }

/* Замість: @media (min-width: 768px) and (max-width: 1199px) */
@media (768px <= width <= 1199px) { ... }

Підтримка широка (Chrome 113+, Firefox 63+, Safari 16.4+), але для сумісності зі старшими проєктами часто ще використовується класичний синтаксис.

orientation — орієнтація пристрою

@media (orientation: portrait) {
    /* Портретна орієнтація (вище, ніж ширше) */
    .sidebar {
        display: none;
    }
}

@media (orientation: landscape) {
    /* Альбомна орієнтація (ширше, ніж вище) */
    .sidebar {
        display: block;
    }
}

prefers-color-scheme — темна/світла тема

@media (prefers-color-scheme: dark) {
    :root {
        --bg: #0f172a;
        --text: #f1f5f9;
        --accent: #818cf8;
    }
}

@media (prefers-color-scheme: light) {
    :root {
        --bg: #ffffff;
        --text: #1e293b;
        --accent: #6366f1;
    }
}

prefers-reduced-motion — режим зниженого руху

@media (prefers-reduced-motion: reduce) {
    /* Вимкнути або зменшити анімації для людей із вестибулярними розладами */
    * {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}
prefers-reduced-motion — це не лише про естетику. Для деяких людей надмірні анімації викликають запаморочення та нудоту. Завжди перевіряйте, чи ваші анімації коректно поводяться з цим запитом. Детально ця тема розкрита у наступній статті про анімації.

hover та pointer — можливості пристрою вводу

/* Чи може пристрій виконати :hover? */
@media (hover: hover) {
    /* Тільки для пристроїв із мишею — показати hover-ефекти */
    .btn:hover {
        background: dark;
    }
}

/* Точність вказівника */
@media (pointer: coarse) {
    /* Сенсорний екран — збільшити кнопки для пальця */
    .btn {
        min-height: 44px;
        padding: 0 1.5rem;
    }
}

@media (pointer: fine) {
    /* Миша — стандартний розмір */
    .btn {
        min-height: 32px;
    }
}

resolution та min-resolution — DPI

/* Для Retina/HiDPI дисплеїв */
@media (min-resolution: 2dppx) {
    .logo {
        background-image: url('logo@2x.png');
    }
}

Breakpoints — точки зламу

Breakpoints (точки зламу) — це значення ширини, при яких змінюється дизайн. Немає "правильних" breakpoints з наукової точки зору — вони мають задаватися контентом, а не розмірами конкретних пристроїв (бо пристроїв безліч).

Стандартні підходи

Tailwind-like (компонентно-орієнтовані):

НазваЗначенняОрієнтир
xs0pxМобільні телефони
sm640pxВеликі телефони, малі планшети
md768pxПланшети (iPad)
lg1024pxНоутбуки
xl1280pxДесктопи
2xl1536pxВеликі монітори

Bootstrap-like (класичні):

НазваЗначення
xs< 576px
sm≥ 576px
md≥ 768px
lg≥ 992px
xl≥ 1200px
xxl≥ 1400px
Найкращий підхід — не прив'язуватися до пристроїв, а додавати breakpoints там, де контент починає "ламатися". Відкрийте браузер, поступово звужуйте вікно і помітьте, в яких точках дизайн перестає виглядати добре — ось ваші breakpoints.

CSS Custom Properties для breakpoints

/* Зберегти breakpoints як коментарі або через @custom-media (CSS Level 5) */
/* Зараз стандартний патерн: */
@media (min-width: 768px) {
    /* md */
}
@media (min-width: 1024px) {
    /* lg */
}
@media (min-width: 1280px) {
    /* xl */
}

Mobile-First vs Desktop-First

Це стратегія написання CSS. Вибір визначає, які значення ви пишете "за замовчуванням" (без media query), а які — у media query.

Базові стилі = мобільні стилі (без media query). Потім розширюєте дизайн для більших екранів через min-width:

/* За замовчуванням: мобільний стиль */
.container {
    padding: 1rem;
    flex-direction: column;
}

/* Планшет: md breakpoint */
@media (min-width: 768px) {
    .container {
        padding: 2rem;
        flex-direction: row;
    }
}

/* Десктоп: lg breakpoint */
@media (min-width: 1024px) {
    .container {
        padding: 3rem;
        max-width: 1200px;
        margin: 0 auto;
    }
}

Принцип: пишіть CSS "від простого до складного". Мобільний дизайн — найпростіший (одна колонка), десктоп — найскладніший.

Чому Mobile-First?

  1. Продуктивність: мобільні пристрої завантажують менше CSS — тільки базові стилі + потрібні breakpoints.
  2. "Progressive Enhancement": починаємо з мінімуму та додаємо можливості для потужніших пристроїв.
  3. Фокус: змушує спочатку продумати найважливіший контент, а вже потім — доповнення для великих екранів.
  4. Google: пошуковик використовує Mobile-First Indexing — індексує сторінки за їх мобільною версією.

Практика: конвертація Desktop-макету в адаптивний

Розглянемо типову трансформацію — картки в два рядки на десктопі → одна колонка на мобільному:

Preview
×
🔒localhost:3000

Зміните розмір вікна браузера (або перегляньте у DevTools у мобільному режимі) — картки автоматично перебудовуються.


Логічні оператори в media queries

and — одночасне виконання умов

@media screen and (min-width: 768px) and (orientation: landscape) {
    /* Екран, ширина ≥ 768px, альбомна орієнтація */
}

, (кома) — логічне АБО

@media (max-width: 767px), print {
    /* Мобільний АБО при друку */
    .sidebar {
        display: none;
    }
}

not — заперечення

@media not print {
    /* Все, крім друку */
    .no-print-element {
        display: block;
    }
}

only — запобігання старим браузерам

@media only screen and (min-width: 768px) {
    /* `only` ігнорується сучасними браузерами, але не дозволяє
       старим браузерам застосовувати правила без підтримки media features */
}

Адаптивні зображення

Базовий CSS: max-width: 100%

img,
video,
iframe {
    max-width: 100%; /* Ніколи не виходить за межі батька */
    height: auto; /* Зберігає пропорції */
}

Це мінімальний обов'язковий CSS для адаптивних зображень.

srcset — різна роздільна здатність

Атрибут srcset дозволяє браузеру вибрати найоптимальніше зображення залежно від ширини viewport та DPI екрана:

<img
    src="image-800.jpg"
    srcset="image-400.jpg 400w, image-800.jpg 800w, image-1600.jpg 1600w"
    sizes="
        (max-width: 600px) 100vw,
        (max-width: 1200px) 50vw,
        33vw
    "
    alt="Адаптивне зображення"
/>

Розберемо атрибути:

  • src — запасне значення для браузерів без підтримки srcset.
  • srcset — список зображень із вказанням їх реальної ширини в пікселях (w).
  • sizes — умови та розміри, в яких буде відображатися зображення в CSS (повідомляє браузеру, яке зображення завантажувати ДО рендерингу).

Браузер аналізує sizes, визначає потрібний CSS-розмір і вибирає оптимальне зображення з srcset.

<picture> — art direction

Елемент <picture> дозволяє показувати різні зображення (не просто різні розміри одного) залежно від умов:

<picture>
    <!-- Мобільне зображення (вертикальний кроп) -->
    <source media="(max-width: 767px)" srcset="hero-mobile.jpg" />
    <!-- Планшетне -->
    <source media="(max-width: 1023px)" srcset="hero-tablet.jpg" />
    <!-- За замовчуванням — десктоп -->
    <img src="hero-desktop.jpg" alt="Hero image" />
</picture>

Типовий кейс: на десктопі — широкий горизонтальний банер, на мобільному — вертикальний кроп із акцентом на головному об'єкті.

WebP та сучасні формати

<picture>
    <!-- WebP для сучасних браузерів -->
    <source type="image/webp" srcset="image.webp" />
    <!-- AVIF — ще ефективніший (Chrome 85+, Firefox 113+) -->
    <source type="image/avif" srcset="image.avif" />
    <!-- JPEG як fallback -->
    <img src="image.jpg" alt="..." />
</picture>

Браузер вибере перший підтримуваний формат зверху вниз. Цей підхід дозволяє використовувати найновіші (й найлегші) формати без ризику зламати старі браузери.


CSS-тест: вкладені media queries

Сучасні браузери підтримують CSS Nesting (нативний, без препроцесорів) — media queries можна вкладати прямо в правило:

.nav {
    flex-direction: column;
    gap: 0.5rem;

    /* Вкладений media query (CSS Nesting, 2023+) */
    @media (min-width: 768px) {
        flex-direction: row;
        gap: 1.5rem;
    }
}

Підтримка: Chrome 112+, Firefox 117+, Safari 17.2+. Якщо потрібна підтримка старших браузерів — використовуйте класичний синтаксис виключно на рівні файлу.


@media та CSS Custom Properties: темна тема

CSS Custom Properties + prefers-color-scheme = автоматична темна тема без JavaScript:

Preview
×
🔒localhost:3000

Якщо на вашому пристрої ввімкнена темна тема — блок вище відображатиметься у темних кольорах автоматично. Якщо ні — у світлих. І все це без рядка JavaScript.


Відносні одиниці для адаптивності

Медіа-запити — лише один інструмент адаптивності. Правильний вибір одиниць виміру робить елементи гнучкими без будь-яких media queries:

ОдиницяВідносноТипове застосування
%Батьківського елементаШирина колонок
emРозміру шрифту батькаВідступи, що масштабуються
remРозміру шрифту :rootБазова типографіка
vwШирини viewportFluid-елементи
vhВисоти viewportFull-screen секції
vminМеншого з vw/vhКвадратні елементи
vmaxБільшого з vw/vhФонові ефекти
chШирини символу "0"Ширина текстових колонок
svh, dvh"Safe/Dynamic" viewportiOS safari full-screen

Сучасні viewport-одиниці

Проблема vh на мобільних: адресний рядок браузера "з'їдає" частину екрана, і 100vh виходить за межі видимої зони. Вирішення — нові одиниці 2023 року:

.hero {
    /* Стара проблема */
    height: 100vh; /* Може бути більше за видиму зону на iOS Safari */

    /* Нові одиниці */
    height: 100svh; /* Small Viewport Height — без адресного рядка */
    height: 100dvh; /* Dynamic Viewport Height — оновлюється при скролі */
    height: 100lvh; /* Large Viewport Height — з адресним рядком */
}

Тестування адаптивності в Chrome DevTools

DevTools — незамінний інструмент для роботи з адаптивним дизайном. Майте на увазі, що без DevTools ви фактично розробляєте наосліп.

Відкрити режим пристроїв

Натисніть Ctrl+Shift+M (Windows/Linux) або Cmd+Shift+M (macOS), або клікніть іконку телефону у верхній частині DevTools. Браузер перейде у Device Toolbar режим.

Вибрати пристрій або ширину

У спадному меню зверху ви можете вибрати конкретний пристрій (iPhone 14, Pixel 7, iPad Air) або задати довільні розміри. Браузер симулює DPR (Device Pixel Ratio) вибраного пристрою.

Перевірити media queries через шкалу

Натисніть іконку трьох крапок → Show media queries. Над сторінкою з'явиться шкала з кольоровими смугами для ваших breakpoints — клік на смугу встановлює відповідну ширину.

Симулювати prefers-color-scheme

DevTools → Rendering (три крапки → More tools → Rendering) → Emulate CSS media feature prefers-color-scheme → dark або light.

Симулювати prefers-reduced-motion

Там же у Rendering → Emulate CSS media feature prefers-reduced-motion → reduce.

Throttling мережі у DevTools: при тестуванні адаптивних зображень увімкніть Network throttling (наприклад, "Fast 3G"), щоб перевірити, яке зображення браузер обирає для завантаження та наскільки швидко завантажується сторінка на повільному з'єднанні.

@media print — стилі для друку

Стилі для друку — недооцінена, але практично важлива частина адаптивного дизайну. Багато корпоративних застосунків, документів, рахунків мають добре виглядати при роздруковуванні.

Базова заготовка print-стилів

@media print {
    /* 1. Сховати непотрібне при друку */
    header,
    footer,
    nav,
    .sidebar,
    .advertisement,
    .cookie-banner,
    .back-to-top,
    video,
    iframe {
        display: none !important;
    }

    /* 2. Скинути фони та тіні (економія чорнила) */
    * {
        background: transparent !important;
        color: black !important;
        box-shadow: none !important;
        text-shadow: none !important;
    }

    /* 3. Встановити шрифт та розміри для друку */
    body {
        font-family: Georgia, serif;
        font-size: 12pt;
        line-height: 1.5;
        color: #000;
    }

    h1 {
        font-size: 22pt;
    }
    h2 {
        font-size: 18pt;
    }
    h3 {
        font-size: 14pt;
    }

    /* 4. Показати URL посилань */
    a[href]::after {
        content: ' (' attr(href) ')';
        font-size: 10pt;
        color: #555;
    }

    /* Не показувати для внутрішніх посилань */
    a[href^='#']::after {
        content: none;
    }

    /* 5. Контроль розривів сторінки */
    h2,
    h3 {
        page-break-after: avoid; /* Не розривати після заголовка */
    }

    img {
        max-width: 100% !important;
        page-break-inside: avoid; /* Не розривати зображення */
    }

    table {
        border-collapse: collapse;
        page-break-inside: avoid;
    }

    /* 6. Налаштування полів сторінки */
    @page {
        margin: 2cm;
        size: A4 portrait; /* або landscape */
    }

    /* Перша сторінка з більшим верхнім відступом */
    @page :first {
        margin-top: 4cm;
    }
}

Практичний приклад: адаптивний інвойс

Документи-рахунки є класичним прикладом, де @media print критично важливий:

.invoice {
    max-width: 800px;
    margin: 0 auto;
    padding: 2rem;
}

/* На екрані — красивий дизайн */
.invoice-header {
    background: linear-gradient(135deg, #6366f1, #4f46e5);
    color: white;
    padding: 2rem;
    border-radius: 12px;
    margin-bottom: 2rem;
}

/* При друці — лише рамка замість градієнта */
@media print {
    .invoice-header {
        background: none !important;
        color: black !important;
        border: 2px solid black;
        border-radius: 0;
    }

    .invoice-footer {
        position: fixed;
        bottom: 0;
        /* Підвал на кожній сторінці */
        border-top: 1px solid #ccc;
        padding-top: 0.5rem;
    }
}

Резюме частини 1

viewport meta-тег

Обов'язковий <meta name="viewport" content="width=device-width, initial-scale=1">. Без нього media queries не працюють на мобільних.

@media синтаксис

Тип медіа (screen, print) + media features (width, orientation, prefers-*). Логічні оператори: and, ,, not.

Mobile-First

Базові стилі = мобільні. Розширюємо через min-width. Менше CSS на мобільних, простіша логіка.

Breakpoints

Не прив'язувати до пристроїв — ставити там, де контент "ламається". Стандартні: 640/768/1024/1280px.

Adaptive Images

max-width: 100% — мінімум. srcset + sizes — оптимізація. <picture> — art direction та WebP/AVIF.

Custom Properties + media

CSS змінні + prefers-color-scheme = автоматична темна тема без JS.

У наступній частині ми розглянемо:

  • clamp() і fluid typography — шрифт, що масштабується плавно без breakpoints
  • Container Queries (@container) — компоненти, що реагують на контейнер, а не на viewport
  • @layer — революційний інструмент управління каскадом CSS
  • Responsive patterns: navigation, cards, tables, modals
  • Завдання трьох рівнів складності

Завдання для самоперевірки (Частина 1)


Продовження: Адаптивний дизайн. Частина 2 — clamp(), Container Queries, @layer

Copyright © 2026