vw и vh — это единицы в CSS, которые считают размер от размера окна браузера.
1vw= 1% от ширины окна.1vh= 1% от высоты окна.
Пример: на экране шириной 1000 px значение 50vw будет равно 500 px. На экране 400 px — 200 px.
Их используют, чтобы элементы масштабировались вместе с экраном. Но из‑за этого появляются проблемы: горизонтальный скролл, «прыгающие» отступы, ломаная верстка на мобильных. Дальше — только рабочие варианты с кодом.
Базовый пример
.box { width: 50vw; /* 50% ширины окна */ height: 30vh; /* 30% высоты окна */ }
Это самое простое использование. Работает предсказуемо, если не пытаться делать элементы строго «на всю ширину/высоту» без учёта скроллбаров и мобильных панелей.
Полноэкранная секция (первый экран)
Частая задача: сделать блок ровно на всю высоту окна.
.hero { height: 100vh; /* на всю высоту окна */ width: 100%; /* не 100vw — так не будет горизонтального скролла из‑за скроллбара */ }
Почему width: 100%, а не 100vw:
Когда появляется вертикальный скроллбар, он занимает место (обычно 16–20 px). 100vw всегда равен 100% ширины окна — даже с учётом этого места. В итоге блок становится шире видимой области и появляется горизонтальный скролл. 100% берёт ширину родителя и такой проблемы не создаёт.
Пропорции 16:9 (видео, карточки)
Самый стабильный способ — через aspect-ratio:
.video-box { width: 100%; aspect-ratio: 16 / 9; }
Если хочется использовать vw, можно так:
.video-box-vw { width: 100vw; max-width: 1920px; aspect-ratio: 16 / 9; }
max-width нужен, чтобы на больших мониторах блок не становился слишком широким.
Проблема «прыгающих» отступов из‑за скроллбара
Когда контента становится больше, появляется вертикальный скролл. Из‑за этого 100vw даёт горизонтальный скролл и интерфейс «дёргается».
Вариант 1: не использовать 100vw там, где не нужно
Для контейнеров и секций почти всегда лучше width: 100%:
.container { width: 100%; }
Вариант 2: если нужен именно «на всю ширину экрана» (например, для фона)
Можно компенсировать разницу между 100vw и реальной шириной контента:
body { margin: 0; } .full-width-bg { width: 100vw; margin-left: calc(-1 * (100vw - 100%)); }
Этот код сдвигает блок влево ровно на ширину скроллбара. Работает, но выглядит громоздко — лучше сначала попробовать 100%.
Вариант 3: современный способ с ограничением
.section { width: min(100vw, 1400px); /* не шире 1400px, на узких экранах — во всю ширину */ margin: 0 auto; }
Так вы избегаете и горизонтального скролла, и слишком широких блоков на больших мониторах.
Крупный заголовок, который масштабируется
Иногда делают так:
.big-title { font-size: 4vw; }
Но тут есть проблема: на очень маленьких экранах шрифт станет слишком мелким, на очень больших — слишком крупным. Лучше ограничить диапазон:
.big-title { font-size: clamp(24px, 4vw, 48px); }
Что это значит:
- Минимум — 24 px (не будет слишком мелко на телефонах).
- Максимум — 48 px (не будет гигантским на больших экранах).
- По умолчанию — 4vw (масштабируется вместе с окном).
Частая ошибка: отступы в vw/vh
Не стоит делать отступы только в vw/vh:
/* Плохо: отступы «прыгают» при изменении размера окна */ .card { padding: 5vw; }
На широком экране отступ станет огромным, на узком — почти незаметным. Лучше использовать фиксированные или смешанные значения:
/* Хорошо: минимум 16px, дальше пропорционально */ .card { padding: max(16px, 3vw); }
Или проще:
.card { padding: 20px; }
Фиксированные отступы дают стабильный, предсказуемый вид.
Итого: когда что использовать
vh— для секций на всю высоту экрана (height: 100vh).vw— когда нужно именно пропорциональное масштабирование (заголовки, карточки, фоны), но почти всегда с ограничением (max-width,clamp,min).- Для ширины контейнеров — чаще
100%, а не100vw. - Для отступов — чаще фиксированные значения или с минимальным порогом, а не чисто в
vw.
