Що таке адаптивний веб-дизайн
Адаптивний веб-дизайн (responsive web design, RWD) - підхід, при якому сайт автоматично підлаштовує розмітку і контент під розмір екрана: від 320px мобільного до 2560px монітора.
Теорія
TL;DR
- Три складові RWD: рідинні сітки (%), гнучкі зображення (max-width: 100%), медіа-запити (@media)
- Фіксована розмітка в пікселях ламається на мобільному; RWD перебудовується без горизонтального скролу
- Мета-тег viewport обов'язковий: без нього мобільний браузер припускає ширину 980px
- Mobile-first: базовий CSS для маленьких екранів, а
@media (min-width)додає стилі для більших - RWD за замовчуванням для будь-якого сайту; фіксована ширина виправдана хіба що для кіоск-застосунку
Швидкий приклад
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
/* Мобільний: блок займає 90% екрана */
.box { width: 90%; margin: 20px auto; }
img { max-width: 100%; height: auto; }
/* Планшет і більше: 50% */
@media (min-width: 768px) {
.box { width: 50%; }
}
</style>
</head>
<body>
<div class="box">Контент перебудовується під кожен екран.</div>
</body>
</html>На телефоні блок займає ~90% viewport. На планшеті звужується до 50%. Зображення ніколи не виходить за межі контейнера.
Головна відмінність
Фіксований макет задає ширину в пікселях. На телефоні з 375px екраном колонка width: 960px виходить за межі viewport і з'являється горизонтальний скрол. RWD використовує %, vw і fr, тому елементи займають рівно стільки місця, скільки є. Браузер перераховує модель блоку при кожній зміні розміру і перебудовує контент.
Mobile-first проти desktop-first
Mobile-first означає: базові стилі для найменшого екрана, а min-width брейкпоінти додають ускладнення для більших. Desktop-first робить навпаки через max-width. Mobile-first краще: телефон отримує менше CSS, не завантажує десктопні стилі на повільному з'єднанні, і підхід змушує думати про контент з самого початку.
/* Mobile-first: одна колонка за замовчуванням */
.card-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }
/* Планшет: дві колонки */
@media (min-width: 768px) {
.card-grid { grid-template-columns: repeat(2, 1fr); }
}
/* Десктоп: чотири колонки */
@media (min-width: 1200px) {
.card-grid { grid-template-columns: repeat(4, 1fr); }
}Коли застосовувати
- Новий сайт або редизайн: RWD за замовчуванням
- Документаційний сайт із великою кількістю контенту: RWD з mobile-first медіа-запитами
- Кіоск-застосунок для одного пристрою: фіксована ширина прийнятна
- Швидкий фікс для legacy-сайту: додати медіа-запити поверх існуючого CSS
- Сторінка з вимогами до продуктивності на слабких пристроях: RWD з ледачим завантаженням зображень
Як браузер це обробляє
Браузер парсить HTML і CSS у дерево рендерингу. CSSOM застосовує медіа-запити на етапі розрахунку стилів, а Blink (рушій Chrome) перераховує ширину, висоту і відступи з відносними одиницями. Мета-тег viewport каже браузеру використовувати реальну ширину пристрою замість стандартних 980px.
Типові помилки
Відсутній мета-тег viewport
<!-- Неправильно: мобільний браузер масштабує сторінку як 980px десктоп -->
<div style="width: 960px;">Контент виходить за межі</div>Додай <meta name="viewport" content="width=device-width, initial-scale=1"> на кожну HTML-сторінку. Без нього медіа-запити на мобільних не спрацюють, бо браузер вважає ширину viewport рівною 980px. Це перше, що перевіряють, коли мобільні стилі зненацька перестають працювати.
Фіксована висота в сітці на відносних одиницях
/* Неправильно: ламається при повороті або великому контенті */
.row { height: 500px; }
/* Правильно */
.row { min-height: 100vh; }Відсоткова висота вимагає визначеної висоти батька. На телефоні після повороту height: 500px обрізає контент. Використовуй min-height або flexbox з align-items: stretch.
Desktop-first медіа-запити з важкими ресурсами
/* Неправильно: телефон завантажує зображення навіть якщо sidebar прихований */
.sidebar { background: url('large-image.jpg'); }
@media (max-width: 768px) { .sidebar { display: none; } }Телефон все одно завантажує large-image.jpg. Переверни логіку: базовий стан для мобільного, додаткові стилі через min-width.
Зображення без max-width
/* Неправильно: зображення 800px виходить за межі 375px екрана */
img { width: 800px; }
/* Правильно */
img { max-width: 100%; height: auto; }nav шириною 100vw
/* Неправильно: vw включає ширину смуги прокрутки у старих Chrome */
nav { width: 100vw; }
/* Правильно */
nav { width: 100%; }Смуга прокрутки зміщує розмітку. Саме цей vw-баг частіше за інші провокує зсуви в продакшені. width: 100% - безпечніший варіант.
Де зустрічається в реальних проектах
- Bootstrap 5:
container-fluidз адаптивною сіткою, використовується приблизно на 40% топових сайтів - Tailwind CSS: класи
sm:,md:,lg:автоматично додають медіа-запити - CSS Grid:
repeat(auto-fit, minmax(250px, 1fr))для колонок без медіа-запитів - WordPress Gutenberg: container queries для попереднього перегляду в редакторі блоків
- GitHub і Netflix: карткові сітки з переходом від 1 до 4 колонок на тих самих брейкпоінтах
Питання на співбесіді
Q: Яка різниця між media queries і container queries?
A: Media queries перевіряють розмір viewport. Container queries перевіряють розмір батьківського елемента. Container queries зручніші для повторно використовуваних компонентів, наприклад карток, що з'являються в різних контекстах.
Q: Як працює мета-тег viewport?
A: Він каже браузеру рендерити сторінку в реальній ширині пристрою, а не в стандартних 980px. Без нього @media (max-width: 768px) на більшості телефонів не спрацює.
Q: Які одиниці краще для адаптивних макетів?
A: % і fr для колонок сітки, rem для розмірів шрифтів, vw/vh для повноекранних секцій. Уникай px для ширин у рідинних макетах.
Q: Як тестувати адаптивний дизайн?
A: DevTools Chrome з емуляцією пристроїв для швидких перевірок. Для продакшену - реальні пристрої. Lighthouse покаже проблеми з продуктивністю через неоптимізовані зображення.
Q (senior): Компонент картки використовується в 3-колонковій сітці і у вузькому сайдбарі. Чому container queries вирішують тут проблему, яку media queries не можуть?
A: Media query спрацьовує при фіксованій ширині viewport незалежно від того, де знаходиться картка. Container query спрацьовує залежно від ширини батьківського контейнера. Одна і та сама картка отримає горизонтальний макет у широкій сітці і вертикальний у вузькому сайдбарі без додаткового CSS або JavaScript.
Приклади
Базовий: адаптивна карткова сітка
/* Мобільний: одна колонка */
.card-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
padding: 1rem;
}
/* Планшет: дві колонки */
@media (min-width: 768px) {
.card-grid { grid-template-columns: repeat(2, 1fr); }
}
/* Десктоп: чотири колонки */
@media (min-width: 1200px) {
.card-grid { grid-template-columns: repeat(4, 1fr); }
}
.card { border: 1px solid #ddd; padding: 1rem; }На телефоні одна картка в рядку, на планшеті дві, на десктопі чотири. Два брейкпоінти, ніякого JavaScript. Саме такий патерн використовує GitHub для карток репозиторіїв.
Середній рівень: автоматичне перебудування без медіа-запитів
.grid {
display: grid;
/* Стільки колонок, скільки вміщає контейнер, кожна мінімум 250px */
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
}auto-fit створює стільки колонок, скільки вміщає контейнер. Коли viewport звужується нижче ~500px, сітка автоматично переходить на одну колонку. Медіа-запити не потрібні. Такий підхід використовується в прикладах MDN і більшості сучасних бібліотек компонентів.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.