Адаптивность значит, что один и тот же HTML хорошо выглядит на телефоне, планшете и широком мониторе. В 2026 году для этого есть три уровня инструментов: гибкая раскладка (Flexbox, Grid, относительные единицы), медиазапросы по экрану и контейнерные запросы по размеру компонента.
Начало: meta viewport
<meta name="viewport" content="width=device-width, initial-scale=1">
Без этой строки мобильный браузер рисует страницу на виртуальном холсте шириной около 980px и уменьшает её, медиазапросы для телефона не срабатывают. Не добавляйте user-scalable=no и maximum-scale=1: они мешают людям увеличивать текст.
Единицы
| Единица | От чего считается |
|---|---|
px | фиксированный CSS-пиксель |
% | от размера containing block (для padding и margin даже по вертикали от ширины) |
em | от font-size текущего элемента (в самом font-size от родителя) |
rem | от font-size корня html |
vw, vh | 1% ширины и высоты viewport |
svh, lvh, dvh | высота viewport с учётом панелей мобильного браузера |
cqi, cqw | 1% размера контейнера (в контейнерных запросах) |
Размер шрифта задавайте в rem: если пользователь увеличил базовый шрифт в настройках браузера, всё масштабируется. em удобен для отступов внутри кнопки, которые должны расти вместе с её текстом, но вложенные em накапливаются.
100vh на мобильном равно высоте экрана при скрытой адресной строке, поэтому блок на весь экран вылезает за край. 100svh берёт маленький вариант (панели видны), 100lvh большой, 100dvh меняется на лету. Для экрана-заставки обычно берут min-height: 100svh или 100dvh.
Медиазапросы
.cards { display: grid; gap: 16px; }
@media (width >= 768px) {
.cards { grid-template-columns: 1fr 1fr; }
}
@media (width >= 1200px) {
.cards { grid-template-columns: repeat(3, 1fr); }
}
Mobile-first: базовые стили пишутся для узкого экрана, а сверху добавляются min-width (или width >=) условия. Так меньше переопределений, и телефон не грузит лишнее. Синтаксис диапазонов (width >= 768px) и (400px <= width < 800px) работает во всех основных браузерах, классический (min-width: 768px) тоже.
Полезные медиа-фичи кроме ширины:
(hover: hover)и(pointer: coarse): есть ли наведение, точный ли указатель. Ховер-эффекты лучше прятать за(hover: hover), на тач-экране они «залипают».(prefers-reduced-motion: reduce): пользователь просит меньше анимаций.(orientation: landscape).
Брейкпоинты выбирайте по контенту (где ломается вёрстка), а не по моделям устройств.
Контейнерные запросы
Медиазапрос знает ширину экрана, но не знает, где лежит компонент. Карточка в узком сайдбаре и та же карточка в широкой ленте при одном экране должны выглядеть по-разному. Для этого контейнерные запросы:
.card-slot { container-type: inline-size; }
.card { display: grid; gap: 12px; }
@container (width >= 420px) {
.card { grid-template-columns: 160px 1fr; }
}
container-type: inline-sizeобъявляет элемент контейнером по ширине. Элемент не может запросить сам себя: правила внутри@containerприменяются к его потомкам.- Контейнеру можно дать имя:
container: sidebar / inline-size;и потом@container sidebar (width > 300px). - Единицы
cqiпозволяют размерам зависеть от контейнера:font-size: clamp(1rem, 4cqi, 1.5rem).
Работает во всех основных браузерах с 2023 года. Правило: раскладка страницы на медиазапросах, внутренности переиспользуемых компонентов на контейнерных.
Плавные размеры: clamp, min, max
h1 { font-size: clamp(1.75rem, 1rem + 3vw, 3rem); }
.content { width: min(100% - 32px, 720px); margin-inline: auto; }
clamp(MIN, PREF, MAX) возвращает предпочтительное значение, но не меньше минимума и не больше максимума. Так заголовок растёт вместе с экраном без медиазапросов. Кладите в середину сумму rem + vw, а не чистый vw: иначе текст не реагирует на увеличение шрифта пользователем.
min(100% - 32px, 720px) даёт колонку до 720px с полями по 16px на телефоне.
Картинки
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
sizes="(width >= 900px) 50vw, 100vw"
width="800" height="600" alt="Кофейня изнутри" loading="lazy">
srcsetсwперечисляет файлы и их ширину,sizesсообщает, какую ширину картинка займёт на экране. Браузер сам выбирает файл с учётом плотности пикселей.<picture>с<source media>нужен для арт-дирекшна (другой кадр на телефоне) или для форматов (type="image/avif").- Атрибуты
widthиheightдают браузеру пропорцию заранее и убирают прыжки вёрстки. Для блоков без картинки то же делаетaspect-ratio: 16 / 9. - Картинка не вылезет из колонки с
max-width: 100%; height: auto.
Логические свойства
margin-inline, padding-block, inset-inline-start, inline-size вместо left/right/width. Они следуют направлению письма, и интерфейс на арабском или иврите (dir="rtl") переворачивается без отдельных стилей.
Частые ошибки
- Забыть meta viewport.
- Писать
100vhдля полноэкранного блока на мобильном. - Шрифт в
pxили чистомvw: не масштабируется настройками пользователя. - Брейкпоинты под конкретные айфоны вместо контента.
- Картинки без
width/height, отсюда сдвиги вёрстки.
Что спросят на собесе
- Что такое mobile-first и зачем meta viewport?
- Чем
emотличается отrem? - Чем контейнерные запросы отличаются от медиазапросов?
- Как сделать адаптивный размер шрифта без медиазапросов?
- Как отдать телефону картинку поменьше?