Единица 100vw на мобильном браузере нередко оказывается шире видимой области: адресная строка и панель инструментов частично перекрывают контент, а блок с шириной 100vw провоцирует горизонтальный скролл. Именно из-за этого поведения в спецификацию CSS Values and Units Level 4 добавили динамические единицы dvw, и отличие vw от dvw стало одним из частых вопросов при адаптивной вёрстке.
Коротко: vw — это 1% от ширины исходного (наибольшего) вьюпорта, а dvw — 1% от динамического вьюпорта, который пересчитывается при появлении и скрытии элементов интерфейса браузера. Ниже разберём, как это работает на практике, где каждая единица уместна и как не сломать макет.
Что такое vw и как работает классическая единица
Единица vw (viewport width) равна одному проценту от ширины области просмотра. При ширине экрана 390 пикселей значение 1vw составит 3,9 пикселя, а 100vw — все 390. На десктопе, где размер окна меняется только вручную, это поведение предсказуемо и проблем не создаёт.
Сложности начинаются на мобильных устройствах. Во многих мобильных браузерах адресная строка и нижняя панель навигации автоматически скрываются при прокрутке страницы вниз и появляются при прокрутке вверх. Классический vw рассчитывается от размера вьюпорта в состоянии, когда интерфейс браузера скрыт, то есть от наибольшего возможного размера. Пока панели видны, реальная видимая область меньше, и элементы, привязанные к 100vw и 100vh, могут выходить за её пределы.
Типичные симптомы, с которыми сталкиваются верстальщики:
- 📱 горизонтальная полоса прокрутки на мобильном при заданной ширине
100vw; - ✂️ нижняя часть полноэкранного блока обрезана панелью браузера;
- 🔄 дёрганье кнопок и фонов при скролле, если размеры привязаны к вьюпорту;
- 📏 несовпадение расчётов в JavaScript через
window.innerWidthс CSS-единицами.
Что такое dvw и зачем понадобились новые единицы
Буква d в dvw означает dynamic — динамический. Значение 1dvw — это 1% от ширины динамического вьюпорта, то есть той области, которая реально видна пользователю прямо сейчас, с учётом открытых панелей браузера. Когда адресная строка скрывается, значение dvw пересчитывается, и элемент плавно занимает освободившееся пространство.
Помимо dvw, спецификация вводит ещё две пары единиц, и понимать их важно, чтобы осознанно выбирать инструмент:
- 📐
svw(small viewport width) — 1% от наименьшего вьюпорта, когда все панели браузера развёрнуты; - 📏
lvw(large viewport width) — 1% от наибольшего вьюпорта, когда панели скрыты; по сути соответствует классическомуvw; - 🔄
dvw— промежуточное значение, плавающее междуsvwиlvwв зависимости от состояния интерфейса.
Те же три варианта существуют и для высоты: svh, lvh, dvh, а также для меньшего и большего из двух измерений — svmin/dvmin/lvmin и svmax/dvmax/lvmax. На десктопных браузерах, где интерфейс не прячется при скролле, все три значения обычно совпадают.
Сравнительная таблица: vw, svw, lvw, dvw
Соберём ключевые различия в одну таблицу, чтобы было проще выбирать единицу под конкретную задачу.
| Единица | От чего считается | Меняется при скролле | Типичное применение |
|---|---|---|---|
vw |
Наибольший вьюпорт | Нет | Десктопные макеты, типографика |
svw |
Наименьший вьюпорт | Нет | Элементы, которые не должны обрезаться |
lvw |
Наибольший вьюпорт | Нет | Фоны, допускающие перекрытие панелями |
dvw |
Текущий видимый вьюпорт | Да | Полноэкранные секции на мобильных |
Обратите внимание: классический vw практически эквивалентен lvw, поэтому замена 100vw на 100lvw ничего не исправит — проблему перекрытия решают именно svw или dvw.
Когда какую единицу выбирать
Выбор зависит от того, что важнее в конкретном блоке: гарантированная видимость, стабильность размеров или использование всего доступного места. Универсального ответа нет, но есть рабочая логика подбора.
Используйте svw/svh, если контент обязан оставаться полностью видимым в любом состоянии браузера — например, экран с кнопкой действия или формой. Блок будет чуть меньше максимальной области, зато его нижняя часть никогда не уйдёт под панель навигации.
Берите dvw/dvh для полноэкранных секций, галерей и hero-блоков, где нужно занять всё доступное пространство. Учтите побочный эффект: при скролле размер блока меняется, и контент внутри может заметно перестраиваться. Для «тяжёлых» по компоновке блоков это иногда выглядит хуже, чем статичный svh.
Для hero-секции часто оптимален компромисс: min-height: 100svh — блок гарантированно виден целиком, а при скрытии панелей браузера просто остаётся небольшой запас, который не бросается в глаза.
Классический vw остаётся уместным для задач, не связанных с высотой экрана: отзывчивая типографика через clamp(), отступы, пропорциональные ширине, декоративные элементы. Там перекрытие панелями браузера роли не играет.
Практический пример с fallback
Хотя поддержка динамических единиц в современных браузерах уже широкая, для старых версий стоит оставить запасной вариант. CSS позволяет сделать это элегантно: просто объявите два правила подряд — браузер, не знающий dvh, проигнорирует вторую строку и применит первую.
.hero {
height: 100vh; / fallback для старых браузеров /
height: 100dvh; / динамическая высота /
}
Тот же приём работает и для ширины. Важен порядок: сначала старая единица, затем новая, иначе переопределение не сработает.
☑️ Проверка вёрстки с dvw/dvh
⚠️ Внимание: эмулятор устройств в DevTools не всегда воспроизводит автоматическое скрытие панелей мобильного браузера. Поведениеdvwиdvhобязательно проверяйте на реальном смартфоне или в браузере с имитацией динамической панели инструментов — иначе разницу сvwвы просто не увидите.
Подводные камни и ограничения
Первая ловушка — перерисовка при скролле. Каждое изменение динамического вьюпорта заставляет браузер пересчитывать размеры всех элементов, привязанных к dvw/dvh. На страницах со сложной раскладкой это может сказываться на плавности, поэтому не стоит развешивать динамические единицы на десятки элементов без необходимости.
Вторая — несовпадение с JavaScript. Значения window.innerWidth и window.innerHeight ведут себя по-разному в зависимости от браузера и не всегда синхронны с тем, что отдаёт dvh в конкретный момент. Если логика критична, сверяйте оба источника на целевых устройствах, а не полагайтесь на предположения.
⚠️ Внимание: сочетаниеwidth: 100vwс вертикальным скроллбаром на десктопе — классическая причина горизонтальной прокрутки, потому что ширина скроллбара входит вvw. Замена наdvwэту проблему не решает: вместо этого используйтеwidth: 100%для блочных контейнеров.
Почему 100vh на iOS долго был болью верстальщиков
В мобильном Safari значение 100vh исторически рассчитывалось от высоты вьюпорта без учёта нижней панели, из-за чего нижняя часть полноэкранных блоков оказывалась скрыта. Верстальщики годами обходили это скриптами с вычислением innerHeight и CSS-переменными. Появление svh и dvh дало нативное решение без JavaScript, и современные версии Safari эти единицы поддерживают.
Поддержка браузерами
Единицы svw, lvw и dvw поддерживаются актуальными версиями основных браузеров — Chrome, Safari, Firefox и Edge. Точные версии, с которых началась поддержка, различаются между движками, поэтому перед использованием в проекте с жёсткими требованиями к совместимости сверьтесь с актуальными таблицами поддержки, например на caniuse.com, по запросу «viewport unit variants».
Если аудитория проекта включает заметную долю устаревших браузеров, обязателен fallback через двойное объявление, как в примере выше. Это дешёвая страховка, не требующая ни скриптов, ни полифилов.
Главное отличие vw от dvw: vw считается от наибольшего вьюпорта и не меняется при скролле, а dvw пересчитывается под реально видимую область с учётом панелей мобильного браузера.
Частые вопросы
Чем dvw отличается от svw?
svw всегда равен наименьшему вьюпорту (панели браузера развёрнуты) и не меняется при скролле. dvw плавает между наименьшим и наибольшим значением в зависимости от текущего состояния интерфейса браузера.
Нужно ли заменять все vw на dvw в существующем проекте?
Нет. Массовая замена оправдана только там, где есть реальная проблема: обрезанные полноэкранные блоки, прыгающая вёрстка на мобильных. Для типографики, отступов и декоративных элементов классический vw работает корректно.
Почему 100dvh всё равно обрезается на моём телефоне?
Возможные причины: браузер не поддерживает динамические единицы (проверьте версию), срабатывает fallback-строка из-за опечатки, либо обрезку создаёт не панель браузера, а что-то другое — например, overflow у родителя или фиксированный элемент поверх. Проверяйте на реальном устройстве, а не только в эмуляторе.
Есть ли динамические аналоги для vmin и vmax?
Да, спецификация включает dvmin/dvmax, а также svmin/svmax и lvmin/lvmax. Они работают по тому же принципу, но от меньшего или большего из двух измерений вьюпорта.
Влияет ли dvw на производительность страницы?
Каждое изменение динамического вьюпорта вызывает пересчёт размеров привязанных элементов. Для одного-двух полноэкранных блоков это незаметно, но если привязать к dvw/dvh множество элементов со сложной раскладкой, перерисовка при скролле может сказаться на плавности. Используйте динамические единицы точечно.