Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке адаптивний веб-дизайн». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Адаптивний веб-дизайн (RWD)** - підхід, при якому сайт підлаштовує розмітку під розмір екрана за допомогою рідинних сіток, гнучких зображень і медіа-запитів. ```css img { max-width: 100%; height: auto; } @media (min-width: 768px) { .sidebar { display: block; } } ``` **Головне:** без `<meta name="viewport" content="width=device-width, initial-scale=1">` медіа-запити на мобільних не спрацюють.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Адаптивний веб-дизайн (responsive web design, RWD)** - підхід, при якому сайт автоматично підлаштовує розмітку і контент під розмір екрана: від 320px мобільного до 2560px монітора. ## Теорія ### TL;DR - Три складові RWD: рідинні сітки (%), гнучкі зображення (max-width: 100%), медіа-запити (@media) - Фіксована розмітка в пікселях ламається на мобільному; RWD перебудовується без горизонтального скролу - Мета-тег viewport обов'язковий: без нього мобільний браузер припускає ширину 980px - Mobile-first: базовий CSS для маленьких екранів, а `@media (min-width)` додає стилі для більших - RWD за замовчуванням для будь-якого сайту; фіксована ширина виправдана хіба що для кіоск-застосунку ### Швидкий приклад ```html <!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, не завантажує десктопні стилі на повільному з'єднанні, і підхід змушує думати про контент з самого початку. ```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** ```html <!-- Неправильно: мобільний браузер масштабує сторінку як 980px десктоп --> <div style="width: 960px;">Контент виходить за межі</div> ``` Додай `<meta name="viewport" content="width=device-width, initial-scale=1">` на кожну HTML-сторінку. Без нього медіа-запити на мобільних не спрацюють, бо браузер вважає ширину viewport рівною 980px. Це перше, що перевіряють, коли мобільні стилі зненацька перестають працювати. **Фіксована висота в сітці на відносних одиницях** ```css /* Неправильно: ламається при повороті або великому контенті */ .row { height: 500px; } /* Правильно */ .row { min-height: 100vh; } ``` Відсоткова висота вимагає визначеної висоти батька. На телефоні після повороту `height: 500px` обрізає контент. Використовуй `min-height` або flexbox з `align-items: stretch`. **Desktop-first медіа-запити з важкими ресурсами** ```css /* Неправильно: телефон завантажує зображення навіть якщо sidebar прихований */ .sidebar { background: url('large-image.jpg'); } @media (max-width: 768px) { .sidebar { display: none; } } ``` Телефон все одно завантажує `large-image.jpg`. Переверни логіку: базовий стан для мобільного, додаткові стилі через `min-width`. **Зображення без max-width** ```css /* Неправильно: зображення 800px виходить за межі 375px екрана */ img { width: 800px; } /* Правильно */ img { max-width: 100%; height: auto; } ``` **nav шириною 100vw** ```css /* Неправильно: 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. ## Приклади ### Базовий: адаптивна карткова сітка ```css /* Мобільний: одна колонка */ .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 для карток репозиторіїв. ### Середній рівень: автоматичне перебудування без медіа-запитів ```css .grid { display: grid; /* Стільки колонок, скільки вміщає контейнер, кожна мінімум 250px */ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; } ``` `auto-fit` створює стільки колонок, скільки вміщає контейнер. Коли viewport звужується нижче ~500px, сітка автоматично переходить на одну колонку. Медіа-запити не потрібні. Такий підхід використовується в прикладах MDN і більшості сучасних бібліотек компонентів.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.