vw и vh: размеры относительно экрана и проблема «прыгающих» отступов (CSS)

vw и vh — это единицы в CSS, которые считают размер от размера окна браузера.

  • 1vw = 1% от ширины окна.
  • 1vh = 1% от высоты окна.

Пример: на экране шириной 1000 px значение 50vw будет равно 500 px. На экране 400 px — 200 px.

Их используют, чтобы элементы масштабировались вместе с экраном. Но из‑за этого появляются проблемы: горизонтальный скролл, «прыгающие» отступы, ломаная верстка на мобильных. Дальше — только рабочие варианты с кодом.


Базовый пример

css
.box {
  width: 50vw;   /* 50% ширины окна */
  height: 30vh;  /* 30% высоты окна */
}

Это самое простое использование. Работает предсказуемо, если не пытаться делать элементы строго «на всю ширину/высоту» без учёта скроллбаров и мобильных панелей.


Полноэкранная секция (первый экран)

Частая задача: сделать блок ровно на всю высоту окна.

css
.hero {
  height: 100vh;   /* на всю высоту окна */
  width: 100%;     /* не 100vw — так не будет горизонтального скролла из‑за скроллбара */
}

Почему width: 100%, а не 100vw:
Когда появляется вертикальный скроллбар, он занимает место (обычно 16–20 px). 100vw всегда равен 100% ширины окна — даже с учётом этого места. В итоге блок становится шире видимой области и появляется горизонтальный скролл. 100% берёт ширину родителя и такой проблемы не создаёт.


Пропорции 16:9 (видео, карточки)

Самый стабильный способ — через aspect-ratio:

css
.video-box {
  width: 100%;
  aspect-ratio: 16 / 9;
}

Если хочется использовать vw, можно так:

css
.video-box-vw {
  width: 100vw;
  max-width: 1920px;
  aspect-ratio: 16 / 9;
}

max-width нужен, чтобы на больших мониторах блок не становился слишком широким.


Проблема «прыгающих» отступов из‑за скроллбара

Когда контента становится больше, появляется вертикальный скролл. Из‑за этого 100vw даёт горизонтальный скролл и интерфейс «дёргается».

Вариант 1: не использовать 100vw там, где не нужно

Для контейнеров и секций почти всегда лучше width: 100%:

css
.container {
  width: 100%;
}

Вариант 2: если нужен именно «на всю ширину экрана» (например, для фона)

Можно компенсировать разницу между 100vw и реальной шириной контента:

css
body {
  margin: 0;
}
 
.full-width-bg {
  width: 100vw;
  margin-left: calc(-1 * (100vw - 100%));
}

Этот код сдвигает блок влево ровно на ширину скроллбара. Работает, но выглядит громоздко — лучше сначала попробовать 100%.

Вариант 3: современный способ с ограничением

css
.section {
  width: min(100vw, 1400px);  /* не шире 1400px, на узких экранах — во всю ширину */
  margin: 0 auto;
}

Так вы избегаете и горизонтального скролла, и слишком широких блоков на больших мониторах.


Крупный заголовок, который масштабируется

Иногда делают так:

css
.big-title {
  font-size: 4vw;
}

Но тут есть проблема: на очень маленьких экранах шрифт станет слишком мелким, на очень больших — слишком крупным. Лучше ограничить диапазон:

css
.big-title {
  font-size: clamp(24px, 4vw, 48px);
}

Что это значит:

  • Минимум — 24 px (не будет слишком мелко на телефонах).
  • Максимум — 48 px (не будет гигантским на больших экранах).
  • По умолчанию — 4vw (масштабируется вместе с окном).

Частая ошибка: отступы в vw/vh

Не стоит делать отступы только в vw/vh:

css
/* Плохо: отступы «прыгают» при изменении размера окна */
.card {
  padding: 5vw;
}

На широком экране отступ станет огромным, на узком — почти незаметным. Лучше использовать фиксированные или смешанные значения:

css
/* Хорошо: минимум 16px, дальше пропорционально */
.card {
  padding: max(16px, 3vw);
}

Или проще:

css
.card {
  padding: 20px;
}

Фиксированные отступы дают стабильный, предсказуемый вид.


Итого: когда что использовать

  • vh — для секций на всю высоту экрана (height: 100vh).
  • vw — когда нужно именно пропорциональное масштабирование (заголовки, карточки, фоны), но почти всегда с ограничением (max-width, clamp, min).
  • Для ширины контейнеров — чаще 100%, а не 100vw.
  • Для отступов — чаще фиксированные значения или с минимальным порогом, а не чисто в vw.

Добавить комментарий