Перейти к основному содержимому

3.10. Адаптивность

Разработчику Аналитику Тестировщику
Архитектору Инженеру

Адаптивность

Адаптивность в веб-разработке — это свойство пользовательского интерфейса подстраиваться под различные условия отображения: размеры экрана, разрешение, плотность пикселей, ориентацию устройства, а также особенности взаимодействия (управление сенсорным вводом, клавиатурой, указателем). Это системный подход к проектированию и реализации интерфейсов, в котором участвуют HTML, CSS, JavaScript, а также методологии проектирования и тестирования.

В основе адаптивного подхода лежит отказ от жёсткой привязки макета к конкретному разрешению или устройству. Вместо этого интерфейс строится как набор гибких, масштабируемых и перестраиваемых компонентов, поведение которых регулируется в зависимости от доступного пространства. Такой подход обеспечивает стабильность восприятия интерфейса и сохранение функциональности независимо от среды просмотра.

Исторически первоначальные веб-страницы разрабатывались исключительно для настольных экранов. С появлением смартфонов и планшетов стало очевидно, что универсальный подход к верстке недостаточен: фиксированные макеты в 960 или 1024 пикселей по ширине оказывались непригодны для экранов шириной 320–414 пикселей. Возникло два направления решения проблемы: отдельные мобильные версии сайтов (часто по адресу m.example.com) и адаптивный дизайн (Responsive Web Design, RWD), впервые систематически описанный Итаном Марком (Ethan Marcotte) в 2010 году. Второй подход быстро стал доминирующим, поскольку исключает дублирование контента, упрощает поддержку и обеспечивает единый URL для всех устройств — что важно как для пользовательского опыта, так и для поисковой оптимизации.

Современное понимание адаптивности выходит за рамки лишь визуального масштабирования. Оно включает:

  • динамическое изменение структуры и иерархии элементов (например, сворачивание навигации в гамбургер-меню);
  • адаптацию типографики (размер шрифта, межстрочный интервал, длина строки);
  • перераспределение нагрузки на интерфейс (скрытие несущественных элементов на малых экранах, замена тяжёлых визуальных компонентов на упрощённые аналоги);
  • учёт контекста использования (в том числе освещённости, скорости соединения, энергетического профиля устройства);
  • обеспечение доступности при масштабировании и изменении ориентации.

Для реализации адаптивного поведения в HTML и CSS задействуется ряд взаимосвязанных механизмов, главными из которых являются метатег viewport, медиа-запросы (@media), относительные единицы измерения (em, rem, vw, vh, %), гибкие макетные технологии (Flexbox, CSS Grid), а также современные CSS-возможности — контейнерные запросы (@container), clamp(), env() и CSS-переменные. Взаимодействие этих инструментов образует стройную систему, где каждая составляющая отвечает за конкретный аспект адаптации.

Что такое адаптивность в техническом контексте

Адаптивность — это свойство системы отвечать на изменения внешних параметров так, чтобы сохранить целостность функционального и визуального опыта. В контексте CSS под адаптивностью обычно подразумевается отзывчивый макет (responsive layout) — макет, способный плавно или дискретно изменять своё поведение в ответ на изменение ширины области просмотра (viewport). Однако следует различать термины:

  • Responsive design (отзывчивый дизайн) — подход, при котором макет изменяется непрерывно или по заданным точкам разрыва (breakpoints) в зависимости от ширины viewport. Реализуется преимущественно с помощью медиа-запросов и относительных единиц.
  • Adaptive design (адаптивный дизайн в узком смысле) — подход, при котором сервер или клиент выбирает одну из нескольких предопределённых версий интерфейса, исходя из данных об устройстве (например, по User-Agent или feature detection). Такой подход требует отдельных шаблонов под каждое «окно» разрешений.
  • Fluid design (резиновый/гибкий дизайн) — макет, построенный на относительных единицах (%, vw), который масштабируется плавно без явных точек разрыва.

Современная практика чаще всего сочетает все три подхода: плавное масштабирование базовой структуры (fluid), дискретные перестроения при переходе между ключевыми размерами (responsive), и частичную адаптацию под возможности устройства (adaptive features, например, использование prefers-reduced-motion или prefers-color-scheme).

Ключевой ошибкой при реализации адаптивности является попытка сопоставить точки разрыва с конкретными моделями устройств — например, «768px — это iPad». Подобное мышление быстро устаревает, поскольку рынок устройств динамичен: появляются складные экраны, планшеты с нестандартным соотношением сторон, ультраширокие мониторы и даже автомобильные интерфейсы. Поэтому правильнее определять breakpoints не по названию устройств, а по содержимому макета: точка разрыва возникает тогда, когда текущее расположение элементов перестаёт быть функциональным или эстетически приемлемым. Это называется content-based breakpoints.


Как происходит работа над адаптивностью

Работа над адаптивной системой начинается на этапе проектирования. Адаптивность должна быть заложена в концепцию интерфейса, а не добавлена как «последний штрих». Основные этапы:

  1. Анализ аудитории и устройств — сбор данных о том, с каких устройств и в каких условиях происходит основное взаимодействие с продуктом. Это помогает определить приоритеты (например, если 85% трафика — мобильный, то разработка ведётся по принципу mobile-first).

  2. Разработка дизайн-системы с адаптивными токенами — определение масштабируемой сетки, типографской шкалы, отступов и радиусов, которые легко адаптируются через относительные единицы или CSS-переменные.

  3. Создание wireframe’ов и прототипов в нескольких viewport’ах — проверка, как компоненты ведут себя при изменении ширины. Важно отработать горизонтальное перетекание контента: например, как таблица с 12 столбцами отображается на экране шириной 320px.

  4. Реализация базовой структуры с использованием семантического HTML и гибких макетов (CSS Grid, Flexbox) — семантическая разметка повышает доступность и упрощает последующую адаптацию через CSS без изменения структуры.

  5. Применение медиа-запросов и контекстных правил — добавление точек разрыва только там, где это действительно необходимо. Избыточное количество @media правил усложняет поддержку.

  6. Тестирование в реальных условиях — на физических устройствах, с учётом скорости сети (например, через throttling в Chrome), уровня заряда батареи, освещённости.

  7. Оптимизация производительности на маломощных устройствах — сокращение количества DOM-узлов, упрощение анимаций, исключение тяжёлых шрифтов, отложенный рендеринг изображений.

Весь этот цикл итеративен: по мере выявления проблем в одном сценарии (например, горизонтальный скролл на Android-устройстве с шириной 360px) вносятся корректировки в дизайн-систему, прототипы и код. Важно избегать «точечных» правок — каждое изменение должно согласовываться с общей адаптивной стратегией.


Мобильные устройства и планшеты

Мобильные устройства — это не просто «маленькие экраны». Это целый класс устройств с уникальными характеристиками:

  • Высокая плотность пикселей (device pixel ratio, DPR): физический пиксель на экране может состоять из нескольких аппаратных пикселей (2×, 3×, 4×). Это требует использования векторной графики или изображений в нескольких разрешениях (srcset, <picture>), но не влияет напрямую на CSS-макет, поскольку CSS-пиксель абстрагирован от аппаратного.

  • Сенсорный ввод: минимальная зона нажатия должна составлять не менее 48×48 CSS-пикселей (рекомендация WCAG), интерактивные элементы требуют увеличенных отступов, исключается ховер-состояние как основной способ взаимодействия.

  • Ограничения по ресурсам: процессоры мобильных устройств, особенно бюджетных, значительно уступают десктопным по производительности. Сложные CSS-анимации (box-shadow, filter, transform без will-change), большое количество DOM-узлов или тяжёлые JavaScript-библиотеки могут привести к подтормаживаниям, перерасходу энергии и быстрому разряду аккумулятора.

  • Особенности браузерной оболочки: на iOS Safari занимает часть вертикального пространства (адресная строка, панель закладок), которая может появляться и исчезать при прокрутке. Это приводит к изменению высоты viewport в реальном времени — vh-единицы могут «прыгать», если не учитывать svh, lvh, dvh (в современных браузерах) или использовать JavaScript-корректировку.

Планшеты находятся в промежуточной зоне: по размеру они приближаются к ноутбукам, но по способу взаимодействия — к смартфонам. Часто используется гибридный подход: на портретной ориентации планшета сохраняется мобильная навигация (гамбургер), а в альбомной — активируется двухколоночный макет с боковой панелью. Однако не стоит полагаться только на ориентацию (orientation: landscape), так как многие устройства (например, iPad Pro) используют одну и ту же ширину viewport в обеих ориентациях при определённых настройках масштаба.


Огромные мониторы

На другом полюсе находятся ультраширокие и 4K-мониторы. Ширина viewport может превышать 2560px, а иногда — и 5000px. Проблемы здесь иные:

  • Чрезмерная длина строки — при фиксированной ширине 100% текст может растягиваться на 200+ символов в строке, что резко снижает читаемость. Решение — ограничение максимальной ширины контентной области (max-width: 1200px) с выравниванием по центру (margin: 0 auto).

  • Пустое пространство по бокам — если не предусмотреть расширяемые элементы (фоновые изображения, full-width секции, анимированные декоративные компоненты), интерфейс выглядит «потерянным» на большом экране.

  • Разрыв единства восприятия — при очень широком экране пользователь вынужден двигать взгляд от левого края к правому, что увеличивает когнитивную нагрузку. В таких случаях оправдано использование многоколоночных макетов или разбиение интерфейса на зоны с фокусировкой на центральной области.

  • Сложности с масштабированием — пользователи с нарушениями зрения могут увеличивать масштаб в браузере до 200–300%. Макет должен оставаться работоспособным и при этом не допускать горизонтального скролла.


Панель инструментов устройства в браузере (DevTools)

Современные браузерные DevTools (в первую очередь — Chrome DevTools, но аналогичные функции присутствуют в Firefox, Edge и Safari) предоставляют комплекс средств для эмуляции и анализа адаптивного поведения. Однако важно понимать: эмуляция — не замена реальному тестированию. DevTools позволяют быстро итерировать и отлаживать, но финальная проверка всегда должна проводиться на физических устройствах.

Центральный инструмент — Device Mode (режим устройства), активируемый кнопкой Toggle device toolbar (значок смартфона/планшета) или сочетанием Ctrl+Shift+M / Cmd+Shift+M. В этом режиме окно просмотра становится регулируемым: его можно изменять вручную, выбирать из списка предустановленных устройств (iPhone, Pixel, iPad и др.), или задавать пользовательские размеры. При этом автоматически включается эмуляция:

  • Ширины и высоты viewport — значения, по которым срабатывают медиа-запросы.
  • Device Pixel Ratio (DPR) — эмулируется соотношение CSS-пикселя к физическому. Например, при выборе iPhone 13 (DPR = 3) браузер масштабирует отрисовку в 3 раза, что влияет на резкость изображений, но не на CSS-логику.
  • User-Agent — отправляется строка, характерная для выбранного устройства. Это важно при server-side detection, но в чистом CSS/JS не используется.
  • Touch events — курсор мыши эмулирует сенсорное касание (например, не вызывает :hover до первого клика).

Однако Device Mode не эмулирует:

  • производительность процессора и GPU;
  • задержки сети (требуется отдельный инструмент — Network Throttling);
  • особенности рендеринга на iOS Safari (WebKit имеет отличия от Blink);
  • поведение системных элементов (например, скрытия адресной строки при скролле на мобильном Safari).

Для более глубокого анализа применяются следующие панели и функции:

  • Media Query Inspector (вкладка ElementsStyles → значок «медиа» рядом с @media) — визуализирует все активные и неактивные медиа-запросы на странице, позволяет быстро переключаться между точками разрыва.

  • Rendering panel (вкладка More toolsRendering) — показывает параметры визуализации: FPS, layout shifts, paint flashing, core web vitals. Особенно полезна опция Layout Shift Regions: она подсвечивает элементы, вызывающие сдвиги при загрузке — частую проблему на мобильных устройствах из-за динамически подгружаемого контента (баннеров, шрифтов, изображений без width/height).

  • Coverage tool (вкладка More toolsCoverage или Ctrl+Shift+P → «Coverage») — анализирует, какие CSS- и JS-правила были реально использованы при текущем состоянии страницы. Позволяет выявить «мёртвый» код, относящийся к неактивным viewport’ам.

  • Device Frame и Sensors — эмуляция датчиков (гироскоп, акселерометр), цветовой схемы (prefers-color-scheme), режима энергосбережения (prefers-reduced-motion, prefers-reduced-data), уровня заряда. Последнее критично: при уровне заряда < 20% или включённом режиме энергосбережения браузер может приостанавливать анимации, откладывать фоновые задачи, ограничивать частоту обновления — поведение, которое необходимо учитывать при проектировании.

Эффективная работа с DevTools предполагает системный подход: последовательно пройти по контрольным точкам — от минимальной ширины (320px) до максимальной (2560px+), включая переходы через каждую точку разрыва, проверку в альбомной ориентации, имитацию медленного 3G-соединения, включение prefers-reduced-motion и анализ производительности на слабом CPU (через PerformanceCPU throttling).


Масштаб и разрешение

Для корректной реализации адаптивности необходимо точно различать три связанных, но независимых понятия:

  1. Физическое разрешение экрана — количество аппаратных пикселей по горизонтали и вертикали (например, 1440×3088 для Samsung Galaxy S22 Ultra). Это аппаратный параметр, недоступный напрямую через CSS.

  2. CSS-разрешение (viewport width/height) — размер области просмотра в CSS-пикселях. Именно к нему относятся медиа-запросы (max-width: 768px). Определяется как:

    CSS-ширина = физическая ширина / devicePixelRatio (DPR)

    Например, устройство с физическим разрешением 1080px и DPR = 2.5 сообщает CSS-ширину 432px (1080 / 2.5 = 432). Это значение можно прочитать в JavaScript через window.innerWidth и использовать в медиа-запросах.

  3. Масштаб (scale factor) — коэффициент увеличения/уменьшения, применяемый браузером к странице. По умолчанию равен 1.0, но может изменяться:

    • пользователем (жестом «щипок»);
    • системой (автоматическое масштабирование текста в настройках ОС);
    • разработчиком (через initial-scale, minimum-scale в метатеге viewport).

Метатег viewport управляет именно виртуальным viewport’ом — областью, в которой браузер отрисовывает макет. Без него мобильные браузеры используют layout viewport шириной ~980px, чтобы «вместить» десктопный сайт, но затем уменьшают его до физического viewport’а — отсюда и необходимость горизонтальной прокрутки и ручного масштабирования.

Ключевая директива — width=device-width. Она устанавливает ширину layout viewport равной ширине visual viewport (того, что видит пользователь в текущий момент), что приводит к синхронизации CSS-пикселей с реальными возможностями устройства. После этого медиа-запросы начинают работать ожидаемо: max-width: 768px действительно сработает на iPad и большинстве планшетов.

Важно: device-width — это не постоянная величина. Она меняется при:

  • повороте устройства (ширина и высота меняются местами);
  • скрытии/появлении системных панелей (адресная строка, клавиатура);
  • открытии in-app браузера (например, в Telegram или Instagram), где viewport может быть искусственно ограничен.

Для работы с динамическими изменениями используются:

  • window.matchMedia() в JavaScript — отслеживание активности медиа-запросов;
  • resize и orientationchange события — с осторожностью, из-за частоты вызовов и различий в поддержке;
  • современные CSS-единицы: svw/svh (small viewport), lvw/lvh (large viewport), dvh (dynamic viewport height), которые автоматически учитывают видимость системных панелей.

Энергоэффективность, упрощение и сжатие

Адаптивность — не только о внешнем виде. В условиях роста доли мобильного трафика и усиления требований к экологичности цифровых продуктов, энергоэффективность становится обязательной частью адаптивной стратегии. Исследования показывают, что до 20% энергопотребления смартфона приходится на работу браузера, и значительная часть — на рендеринг и JavaScript-исполнение.

CSS оказывает прямое влияние на энергопотребление. Следующие практики позволяют снизить нагрузку на устройство:

1. Минимизация layout thrashing и paint-операций

Каждое изменение геометрии элемента (ширина, высота, margin, padding, font-size) вызывает layout recalculation — пересчёт позиций всех элементов на странице. Это одна из самых дорогих операций. Адаптивные перестроения должны быть:

  • редкими (избегать @media на каждый пиксель);
  • предсказуемыми (использовать transform и opacity для анимаций, так как они не вызывают layout);
  • локализованными (изолировать перестраиваемые компоненты с помощью contain: layout или contain: strict).

2. Упрощение визуальных эффектов на маломощных устройствах

CSS-свойства box-shadow, filter, backdrop-filter, clip-path требуют значительных вычислений GPU. При обнаружении низкой производительности (например, через navigator.hardwareConcurrency < 4 или navigator.connection.effectiveType === 'slow-2g') можно:

  • отключать тяжёлые эффекты через медиа-запросы:
    @media (prefers-reduced-motion: reduce) {
    * { animation: none !important; }
    }
  • использовать @media (prefers-reduced-data: reduce) для упрощения графики;
  • применять @media (dynamic-range: standard) для отключения HDR-эффектов на устройствах без поддержки.

3. Оптимизация шрифтов

Шрифты — одна из главных причин задержек отрисовки и потребления памяти. Рекомендации:

  • использовать font-display: swap, чтобы текст отображался сразу, даже если шрифт ещё не загружен;
  • ограничивать количество начертаний (обычно достаточно regular + bold);
  • отдавать шрифты в формате WOFF2 с подмножествами (unicode-range);
  • избегать @font-face внутри медиа-запросов — это приводит к множественной загрузке одних и тех же файлов.

4. Сжатие и отложенная загрузка ресурсов

Хотя это относится скорее к HTML и JavaScript, CSS может способствовать оптимизации:

  • использование picture и srcset в сочетании с @media для адаптивных изображений:
    <picture>
    <source media="(max-width: 768px)" srcset="small.jpg">
    <source media="(min-width: 769px)" srcset="large.jpg">
    <img src="fallback.jpg" alt="">
    </picture>
  • применение loading="lazy" для изображений и iframe вне viewport;
  • исключение тяжёлых SVG-анимаций на мобильных устройствах через @media (max-width: 768px) { svg.animated { display: none; } }.

5. Использование CSS-переменных для централизованной адаптации

CSS Custom Properties (переменные) позволяют реализовать динамическую адаптацию без дублирования правил. Например:

:root {
--space-unit: 1rem;
--text-base: 1rem;
--border-radius: 0.375rem;
}

@media (max-width: 767px) {
:root {
--space-unit: 0.75rem;
--text-base: 0.9375rem;
--border-radius: 0.25rem;
}
}

body { font-size: var(--text-base); }
.container { padding: var(--space-unit); }
.card { border-radius: var(--border-radius); }

Такой подход:

  • исключает дублирование селекторов;
  • позволяет легко менять «масштаб интерфейса» для всего проекта;
  • поддерживает темизацию и динамическое переключение через JavaScript (document.documentElement.style.setProperty('--text-base', '1.125rem')).

Современные расширения адаптивности

Хотя медиа-запросы остаются основным инструментом, развитие CSS привело к появлению механизмов, которые позволяют адаптировать интерфейс под размер окна просмотра (viewport), и под локальный контекст компонента. Это особенно важно в эпоху компонентных архитектур (React, Vue, Web Components), где компонент должен быть самодостаточным и не зависеть от глобальных точек разрыва.

Контейнерные запросы (@container)

Контейнерные запросы — принципиально новый подход, введённый в CSS Containment Module Level 3. Вместо @media (max-width: 768px) разработчик может написать:

.card {
container-type: inline-size;
container-name: card;
}

@container card (min-width: 300px) {
.card__title { font-size: 1.25rem; }
.card__actions { display: flex; gap: 0.75rem; }
}

Здесь .card объявляется как контейнер по ширине (inline-size). Правила внутри @container применяются, когда ширина самого контейнера достигает указанного порога.

Преимущества:

  • компоненты становятся независимыми от глобального layout: карточка может перестраиваться как на мобильном экране (если помещается в две колонки), так и в узкой боковой панели десктопного интерфейса;
  • устраняется каскадная зависимость от точек разрыва: не нужно знать, при каком viewport карточка станет узкой — она реагирует на своё внутреннее состояние;
  • упрощается дизайн-система: один компонент может использоваться в разных layout’ах без модификации.

Ограничения:

  • контейнер должен иметь явно заданную ширину (или наследовать её), иначе inline-size будет 0;
  • нельзя использовать container-name в @media и наоборот — это разные системы;
  • поддержка: Chrome 105+, Firefox 110+, Safari 16.4+. Для продакшена требуется feature detection (например, через @supports (container-type: inline-size)).

Рекомендуется сочетать @container и @media: глобальные структурные изменения (например, переход от одно- к двухколоночному layout’у) управлять через медиа-запросы, а микронастройки компонентов — через контейнерные.

Функции clamp(), min(), max() как замена множеству точек разрыва

Часто адаптивность сводится к плавному изменению параметров (например, размера шрифта или отступа) в заданном диапазоне. Раньше это требовало нескольких @media, но теперь можно сделать это в одном правиле:

h1 {
font-size: clamp(1.5rem, 4vw, 3rem);
}

Здесь:

  • 1.5rem — минимальное значение (гарантированно читаемо на самых малых экранах);
  • 3rem — максимальное значение (не перегружает крупные экраны);
  • 4vw — гибкое значение, пропорциональное ширине viewport.

Результат: заголовок масштабируется плавно от 24px (на 320px) до 48px (на 1200px+), без единого медиа-запроса.

Аналогично:

  • min(100%, 80ch) — ограничивает ширину текстового блока по количеству символов в строке (рекомендовано 45–75 символов для комфортного чтения);
  • max(12px, 0.9em) — гарантирует, что шрифт не станет меньше 12px, даже если родительский font-size уменьшен.

Эти функции особенно эффективны в сочетании с CSS-переменными:

:root {
--text-scale: clamp(0.875rem, 2.5vw, 1.25rem);
--space-base: clamp(0.75rem, 4vw, 2rem);
}

Такой подход сокращает объём CSS, повышает предсказуемость и устраняет «ступенчатость» изменений.

Относительные единицы: em, rem, ch, ex, cap

Помимо vw/vh, важную роль играют типографические относительные единицы:

  • em — относительно font-size текущего элемента;
  • rem — относительно font-size корневого элемента (html);
  • ch — ширина символа «0» в текущем шрифте (идеальна для ограничения длины строки);
  • ex — высота строчной «x»;
  • cap — высота прописной буквы (например, «H»), появилась в CSS Values 4.

Пример адаптивной типографики на rem:

html {
font-size: clamp(14px, 1.8vw, 18px); /* глобальный масштаб */
}

h2 { font-size: 1.75rem; } /* = 24.5px–31.5px */
p { line-height: 1.6; }
p { max-width: 65ch; } /* ~65 символов в строке */

Это обеспечивает естественную иерархию, устойчивую к изменениям масштаба пользователя (в отличие от px).


Адаптивность вне ширины экрана

Современный CSS позволяет адаптироваться к размеру экрана и к предпочтениям и физиологическим особенностям пользователя. Эти медиа-функции работают через те же @media или @supports, но с другими условиями.

prefers-color-scheme

Позволяет переключать интерфейс между светлой и тёмной темами в соответствии с системными настройками:

@media (prefers-color-scheme: dark) {
:root {
--bg: #121212;
--text: #e0e0e0;
}
}

Важно: не следует насильно навязывать тему при prefers-color-scheme: no-preference. Лучше предложить пользователю выбор и сохранить его в localStorage.

prefers-reduced-motion

Указывает, что пользователь предпочитает минимизировать анимации — часто по медицинским причинам (например, эпилепсия, вестибулярные расстройства):

@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}

Лучше не отключать анимации полностью, а заменять их на мгновенные переходы (например, opacity вместо transform: scale()).

prefers-contrast и forced-colors

  • prefers-contrast: more — запрос на повышенный контраст (для пользователей с нарушениями зрения);
  • forced-colors: active — браузер принудительно переопределил цвета (например, в режиме Windows High Contrast).

Пример:

@media (prefers-contrast: more) {
:root {
--border: 2px solid;
--focus-outline: 3px solid Highlight;
}
}

@media (forced-colors: active) {
.custom-checkbox {
forced-color-adjust: none; /* разрешаем переопределение */
}
}

any-pointer, any-hover

Определяют типы доступных указателей:

  • @media (any-pointer: coarse) — есть сенсорный/крупный указатель (требуются увеличенные цели);
  • @media (any-hover: none) — ховер недоступен (не стоит полагаться на :hover как на основной способ взаимодействия).

Тестирование и метрики

Адаптивность — не субъективное понятие. Её можно и нужно измерять количественно. Ключевые метрики:

Core Web Vitals (Google)

  • LCP (Largest Contentful Paint) — время отрисовки крупного элемента. На мобильных устройствах из-за медленных сетей и CPU значение часто растёт. Адаптивная оптимизация (ленивая загрузка, упрощение DOM) напрямую влияет на LCP.

  • CLS (Cumulative Layout Shift) — совокупный сдвиг макета. Часто возникает при подгрузке шрифтов, изображений без width/height, рекламы. Адаптивные блоки должны иметь заранее выделенное пространство (aspect-ratio, min-height).

  • INP (Interaction to Next Paint) — замена FID, измеряет отзывчивость на взаимодействие. На слабых устройствах тяжёлые CSS-анимации или JavaScript-обработчики могут резко увеличивать INP.

Доступность (WCAG)

  • Уровень контраста текста (минимум 4.5:1 для обычного текста);
  • Размер зон нажатия (минимум 24×24 CSS-пикселей для WCAG 2.1, 44×44 для iOS Human Interface Guidelines);
  • Соответствие prefers-* настройкам.

Энергопотребление

Прямое измерение сложно, но косвенные индикаторы:

  • количество forced layers (в Rendering panel);
  • частота style recalculations и layout в Performance timeline;
  • использование will-change без необходимости.

Антисемплы

Ниже — типичные нарушения, ведущие к нестабильной адаптивности.

1. width: 100vw на мобильных устройствах

vw учитывает всю ширину viewport, включая вертикальную полосу прокрутки (если есть) и системные панели. На iOS это приводит к горизонтальному скроллу, даже если элемент один.
Решение: использовать width: 100% или width: stretch (в Flex/Grid), либо width: calc(100vw - env(safe-area-inset-left) - env(safe-area-inset-right)).

2. Отсутствие min-width: 0 в Flex/Grid-контейнерах

По умолчанию flex-элементы имеют min-width: auto, что предотвращает их сжатие меньше содержимого. На малых экранах это вызывает переполнение.
Решение:

.card { min-width: 0; } /* для flex-дочерних */
.grid-item { min-width: 0; } /* для grid-дочерних */

3. height: 100vh на мобильных Safari

Из-за динамического изменения высоты viewport (при скрытии адресной строки) 100vh фиксируется на максимальном значении, вызывая «прыгающий» контент.
Решение: использовать height: 100dvh (dynamic viewport height) или height: stretch в flex-контейнере. При отсутствии поддержки — JavaScript-коррекция.

4. Медиа-запросы без min-width в mobile-first подходе

/* Плохо: нарушает каскад */
@media (max-width: 768px) { ... }
@media (max-width: 1024px) { ... } /* перекроет предыдущий */

Решение: при mobile-first использовать min-width, идя от малого к большому:

/* Базовые стили — для мобильных */
.card { flex-direction: column; }

/* Планшеты и выше */
@media (min-width: 768px) {
.card { flex-direction: row; }
}

/* Десктопы */
@media (min-width: 1200px) {
.card { padding: 2rem; }
}

5. Жёсткая привязка к DPR (@media (-webkit-device-pixel-ratio: 2))

Плотность пикселей не коррелирует с размером экрана и быстро устаревает.
Решение: использовать image-set() в CSS или srcset в HTML — браузер сам выберет подходящий ресурс.