Пошук уроків, статей та іншого контенту
Побудуєте адаптивні стилі за допомогою media queries для різних ширин, орієнтацій і характеристик пристрою.
Media queries — це CSS-умови, які дають змогу застосовувати стилі лише тоді, коли характеристики пристрою або вікна браузера відповідають заданим умовам.
Найчастіше media queries використовують для адаптивної верстки:
змінюють кількість колонок;
змінюють розмір шрифту;
перемикають горизонтальну та вертикальну навігацію;
змінюють відступи;
адаптують інтерфейс для портретної або альбомної орієнтації;
враховують можливості пристрою, наприклад наявність hover або тип вказівного пристрою.
Базовий синтаксис:
@media умова {
/* Стилі, які застосовуються за виконання умови */
}Наприклад:
@media (max-width: 600px) {
body {
font-size: 14px;
}
}Ці стилі застосуються, якщо ширина області перегляду не перевищує 600px.
Перед використанням media queries у HTML-документі потрібно додати meta-тег viewport:
<meta name="viewport" content="width=device-width, initial-scale=1">Він повідомляє мобільному браузеру, що ширина сторінки має відповідати ширині пристрою. Без цього мобільний браузер може використовувати віртуальну ширину сторінки, через що адаптивні умови працюватимуть неочікувано.
Найпоширеніші характеристики:
min-width — мінімальна ширина;
max-width — максимальна ширина;
width — точна ширина області перегляду.
/* Базові стилі для вузьких екранів */
.navigation {
display: flex;
flex-direction: column;
}
/* Стилі для екранів від 768 px */
@media (min-width: 768px) {
.navigation {
flex-direction: row;
}
}У цьому прикладі базовий стиль призначений для вузьких екранів, а після досягнення ширини 768px навігація стає горизонтальною.
Під час створення адаптивних стилів часто використовують підхід mobile-first:
Спочатку описують стилі для малих екранів.
За допомогою min-width поступово додають зміни для ширших екранів.
.card-list {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
@media (min-width: 600px) {
.card-list {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1000px) {
.card-list {
grid-template-columns: repeat(3, 1fr);
}
}Такий підхід має кілька переваг:
базові стилі простіше підтримувати;
на мобільні пристрої не потрібно додатково перевизначати зайві правила;
стилі поступово розширюються разом із доступним простором.
Можна застосувати стилі лише в певному діапазоні:
@media (min-width: 600px) and (max-width: 999px) {
.card-list {
grid-template-columns: repeat(2, 1fr);
}
}Умова виконується лише тоді, коли ширина становить від 600px до 999px включно.
У сучасному CSS також можна використовувати оператори порівняння:
@media (600px <= width < 1000px) {
.card-list {
grid-template-columns: repeat(2, 1fr);
}
}Запис із min-width і max-width часто легше впізнати в існуючих проєктах, тому важливо вміти читати обидва варіанти.
Умови можна комбінувати за допомогою and:
@media (min-width: 768px) and (orientation: landscape) {
.hero {
min-height: 60vh;
}
}Стилі застосуються лише одночасно за двох умов:
ширина не менша за 768px;
пристрій має альбомну орієнтацію.
Можна також перелічити альтернативні умови через кому. Кома працює як логічне «або»:
@media (max-width: 600px), (orientation: portrait) {
.sidebar {
display: none;
}
}Стилі застосуються, якщо ширина не перевищує 600px або сторінка має портретну орієнтацію.
Характеристика orientation має два значення:
portrait — висота більша за ширину;
landscape — ширина більша за висоту.
.gallery {
display: grid;
grid-template-columns: 1fr;
}
@media (orientation: landscape) and (min-width: 600px) {
.gallery {
grid-template-columns: repeat(3, 1fr);
}
}Орієнтація може змінитися не лише після повороту смартфона. Наприклад, вікно браузера на планшеті або комп’ютері також може мати портретні чи альбомні пропорції.
Media queries можуть врахувати, як користувач взаємодіє з інтерфейсом.
hoverВизначає, чи може основний вказівний пристрій наводитися на елемент:
hover: hover — наведення підтримується;
hover: none — наведення не підтримується.
.button {
transition: background-color 150ms ease;
}
@media (hover: hover) {
.button:hover {
background-color: #174ea6;
}
}На пристроях без hover не варто покладатися лише на ефект наведення для важливої інформації або дії.
pointerОписує точність основного вказівного пристрою:
pointer: fine — точний вказівний пристрій, наприклад миша;
pointer: coarse — менш точний пристрій, наприклад палець;
pointer: none — основного вказівного пристрою немає.
.button {
min-height: 40px;
padding: 8px 14px;
}
@media (pointer: coarse) {
.button {
min-height: 48px;
padding: 12px 18px;
}
}Для сенсорних пристроїв збільшення області натискання робить інтерфейс зручнішим.
Media queries можуть реагувати на системні налаштування користувача.
За допомогою prefers-color-scheme можна застосувати стилі для темної теми:
:root {
color-scheme: light;
--page-color: #ffffff;
--text-color: #1f2937;
}
@media (prefers-color-scheme: dark) {
:root {
color-scheme: dark;
--page-color: #111827;
--text-color: #f9fafb;
}
}
body {
background-color: var(--page-color);
color: var(--text-color);
}Значення:
light — світла тема;
dark — темна тема.
Користувач може в операційній системі попросити зменшити рух на екрані. Це враховується через prefers-reduced-motion:
.card {
transition: transform 200ms ease;
}
.card:hover {
transform: translateY(-4px);
}
@media (prefers-reduced-motion: reduce) {
.card {
transition: none;
}
.card:hover {
transform: none;
}
}Це не означає, що потрібно повністю вилучити всі візуальні зміни. Але варто прибрати або скоротити рухомі ефекти, які можуть заважати користувачеві.
У прикладі:
на вузькому екрані картки розташовані в один стовпчик;
від 700px з’являються два стовпчики;
від 1100px — три;
для альбомної орієнтації змінюється мінімальна висота заголовка;
для сенсорних пристроїв збільшується область кнопок;
для темної теми змінюються кольори;
для користувачів, які зменшили рух, вимикається анімація.
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Адаптивна галерея</title>
<style>
:root {
color-scheme: light;
--page-color: #f3f4f6;
--surface-color: #ffffff;
--text-color: #1f2937;
--muted-color: #6b7280;
--accent-color: #2563eb;
--accent-hover-color: #1d4ed8;
--border-color: #d1d5db;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Arial, sans-serif;
line-height: 1.5;
background-color: var(--page-color);
color: var(--text-color);
}
.container {
width: min(100% - 32px, 1200px);
margin: 0 auto;
}
.hero {
display: grid;
align-items: center;
min-height: 280px;
padding: 40px 0;
}
.hero__title {
max-width: 700px;
margin: 0;
font-size: clamp(2rem, 7vw, 4rem);
line-height: 1.1;
}
.hero__description {
max-width: 620px;
margin: 20px 0 0;
color: var(--muted-color);
}
.card-list {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
padding: 0 0 40px;
}
.card {
padding: 20px;
border: 1px solid var(--border-color);
border-radius: 12px;
background-color: var(--surface-color);
transition: transform 180ms ease, box-shadow 180ms ease;
}
.card__title {
margin: 0;
font-size: 1.25rem;
}
.card__text {
margin: 12px 0 20px;
color: var(--muted-color);
}
.button {
display: inline-block;
min-height: 40px;
padding: 9px 16px;
border: 0;
border-radius: 8px;
background-color: var(--accent-color);
color: #ffffff;
font: inherit;
cursor: pointer;
}
/* Зміни для пристроїв, на яких підтримується наведення */
@media (hover: hover) {
.card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 24px rgb(0 0 0 / 12%);
}
.button:hover {
background-color: var(--accent-hover-color);
}
}
/* Зміни для ширших екранів */
@media (min-width: 700px) {
.card-list {
grid-template-columns: repeat(2, 1fr);
}
.hero {
min-height: 360px;
}
}
/* Зміни для великих екранів */
@media (min-width: 1100px) {
.card-list {
grid-template-columns: repeat(3, 1fr);
}
}
/* Зміни для альбомної орієнтації */
@media (orientation: landscape) and (min-width: 600px) {
.hero {
min-height: 220px;
}
}
/* Збільшення області натискання на сенсорних пристроях */
@media (pointer: coarse) {
.button {
min-height: 48px;
padding: 12px 20px;
}
}
/* Темна тема користувача */
@media (prefers-color-scheme: dark) {
:root {
color-scheme: dark;
--page-color: #111827;
--surface-color: #1f2937;
--text-color: #f9fafb;
--muted-color: #d1d5db;
--accent-color: #60a5fa;
--accent-hover-color: #93c5fd;
--border-color: #4b5563;
}
.button {
color: #111827;
}
}
/* Зменшення руху за налаштуванням користувача */
@media (prefers-reduced-motion: reduce) {
.card {
transition: none;
}
.card:hover {
transform: none;
}
}
</style>
</head>
<body>
<header class="hero container">
<div>
<h1 class="hero__title">Адаптивна галерея</h1>
<p class="hero__description">
Кількість колонок і взаємодія з картками змінюються
відповідно до характеристик пристрою.
</p>
</div>
</header>
<main class="container">
<section class="card-list" aria-label="Список матеріалів">
<article class="card">
<h2 class="card__title">HTML</h2>
<p class="card__text">Структура документа та семантичні елементи.</p>
<button class="button" type="button">Відкрити</button>
</article>
<article class="card">
<h2 class="card__title">CSS</h2>
<p class="card__text">Стилі, розмітка та адаптивна верстка.</p>
<button class="button" type="button">Відкрити</button>
</article>
<article class="card">
<h2 class="card__title">JavaScript</h2>
<p class="card__text">Логіка взаємодії користувача зі сторінкою.</p>
<button class="button" type="button">Відкрити</button>
</article>
</section>
</main>
</body>
</html>Перевірити адаптивність можна в інструментах розробника браузера:
Відкрийте сторінку в браузері.
Відкрийте DevTools.
Увімкніть режим емуляції мобільного пристрою.
Змінюйте ширину та висоту області перегляду.
Перевірте портретну й альбомну орієнтації.
У налаштуваннях емуляції змініть тему, тип вказівного пристрою або параметр зменшення руху.
Тестувати потрібно не лише на умовних ширинах 320px, 768px і 1200px. Важливо перевіряти проміжні значення, на яких текст може переноситися, а елементи — втрачати достатній простір.
Media query не має автоматично вищого пріоритету за звичайне CSS-правило. Під час конфлікту важливими є:
специфічність селекторів;
порядок правил у CSS;
використання !important.
.title {
color: black;
}
@media (min-width: 700px) {
.title {
color: navy;
}
}За ширини від 700px спрацює друге правило, оскільки селектори мають однакову специфічність, а правило всередині media query записане пізніше.
Якщо правила мають однаковий селектор, пізніше правило перемагає:
.card {
padding: 16px;
}
@media (min-width: 700px) {
.card {
padding: 24px;
}
}meta viewportБез meta name="viewport" сторінка на мобільному пристрої може мати невідповідну ширину віртуального viewport.
Не потрібно створювати media query для кожної конкретної моделі телефону. Брейкпоінти краще визначати за моментом, коли макет перестає бути зручним.
/* Добре: умова відповідає потребі макета */
@media (min-width: 720px) {
.navigation {
flex-direction: row;
}
}orientation: portrait не означає, що пристрій обов’язково вузький. Широкий монітор теж може мати портретну орієнтацію. Для розміру макета зазвичай потрібен width, а orientation варто додавати лише тоді, коли орієнтація справді впливає на дизайн.
:hoverНа сенсорних пристроях наведення може бути недоступним. Кнопка або посилання мають залишатися зрозумілими та функціональними без hover-ефекту.
Якщо елемент має ширину на кшталт width: 800px, він може виходити за межі вузького екрана. Для адаптивних блоків часто використовують відносні одиниці, max-width, min(), max() або clamp().
.container {
width: min(100% - 32px, 1200px);
margin-inline: auto;
}Якщо зміна в media query не працює, перевірте:
чи виконується умова;
чи не має інше правило більшої специфічності;
чи не записане пізніше правило, яке скасовує зміну;
чи не залишився старий стиль із !important.
Media queries застосовують стилі залежно від характеристик viewport або пристрою.
Для адаптивної верстки найчастіше використовують min-width і max-width.
Mobile-first означає: спочатку стилі для вузьких екранів, потім розширення через min-width.
Умови можна комбінувати через and або об’єднувати комою як альтернативи.
orientation дає змогу реагувати на портретну й альбомну орієнтації.
hover і pointer допомагають враховувати спосіб взаємодії з пристроєм.
prefers-color-scheme враховує світлу або темну тему.
prefers-reduced-motion допомагає зменшити анімацію для користувачів, які цього потребують.
Розмір брейкпоінтів потрібно визначати за поведінкою макета, а не за конкретними моделями пристроїв.