Viewport units
Viewport units (
vw,vh,vmin,vmax,svh,lvh,dvh) — единицы измерения, привязанные к размеру видимой области браузера (viewport). Позволяют создавать элементы, которые масштабируются пропорционально экрану.
Зачем нужно
Процентные единицы (%) зависят от размера родителя. Viewport units зависят от размера окна браузера, что идеально для hero-секций, полноэкранных слайдов, адаптивной типографики и элементов, которые должны занимать определённую долю экрана.
Где используется
- Hero-секции на полный экран
- Адаптивная типографика (
clampсvw) - Полноэкранные модальные окна и оверлеи
- Минимальная высота контентных областей
- Адаптивные отступы
Предпосылки
- Единицы измерения — базовые единицы
- Media queries — адаптивные стили
Классические единицы
.element {
/* 1vw = 1% ширины viewport */
width: 50vw; /* Половина ширины экрана */
/* 1vh = 1% высоты viewport */
height: 100vh; /* Полная высота экрана */
/* vmin = min(vw, vh) — меньшая сторона */
font-size: 5vmin; /* На портретном — от ширины, на ландшафтном — от высоты */
/* vmax = max(vw, vh) — большая сторона */
width: 80vmax;
}
Что такое viewport
┌─────────────────────────┐
│ Адресная строка │
├─────────────────────────┤
│ │
│ Viewport │ ← vh, vw считаются от этой области
│ │
│ │
│ │
├─────────────────────────┤
│ Панель инструментов │
└─────────────────────────┘
Проблема 100vh на мобильных
На мобильных браузерах адресная строка скрывается при скролле, изменяя высоту viewport. 100vh всегда равен максимальной высоте (с убранной адресной строкой), поэтому при первом показе страницы элемент оказывается выше видимой области.
/* ПРОБЛЕМА — на мобильном 100vh больше видимой области */
.hero {
height: 100vh; /* Часть контента обрезается */
}
Новые единицы (Small, Large, Dynamic)
svh / svw — Small Viewport
/* svh = высота viewport МИНУС адресная строка и панели */
/* Гарантированно помещается на экране */
.hero {
min-height: 100svh;
}
lvh / lvw — Large Viewport
/* lvh = высота viewport БЕЗ адресной строки (максимальная) */
/* = старый 100vh */
.hero {
min-height: 100lvh;
}
dvh / dvw — Dynamic Viewport
/* dvh = текущая высота viewport (меняется при скролле) */
/* Самый точный, но может вызывать reflow */
.hero {
min-height: 100dvh;
}
Сравнение
Адресная строка показана:
┌──────────────────────┐
│ █████ Адресная строка │
├──────────────────────┤ ← svh начинается здесь
│ │
│ svh = dvh │ ← dvh = svh (в данный момент)
│ │
│ │
│ lvh > dvh │ ← lvh всегда полная высота
│ │
└──────────────────────┘
Адресная строка скрыта (после скролла):
┌──────────────────────┐ ← lvh начинается здесь
│ │
│ dvh = lvh │ ← dvh теперь равен lvh
│ │
│ svh < dvh │
│ │
│ │
└──────────────────────┘
Рекомендации
/* Для hero-секций — dvh (лучший вариант) */
.hero {
min-height: 100dvh;
}
/* Fallback для старых браузеров */
.hero {
min-height: 100vh; /* Fallback */
min-height: 100dvh; /* Браузеры, поддерживающие dvh, применят это */
}
/* Для фиксированных оверлеев — svh (точно поместится) */
.modal-overlay {
height: 100svh;
}
Практические примеры
Hero-секция
.hero {
min-height: 100dvh;
display: grid;
place-items: center;
padding: 5vw;
}
.hero-title {
font-size: clamp(2rem, 1rem + 4vw, 5rem);
}
Полноэкранный слайд
.slide {
width: 100vw;
height: 100dvh;
scroll-snap-align: start;
}
Адаптивная типографика
h1 {
/* vw для плавного масштабирования, clamp для ограничения */
font-size: clamp(1.5rem, 1rem + 3vw, 4rem);
}
/* Только vw — ОПАСНО (может быть слишком мелким или крупным) */
h1 {
font-size: 5vw; /* На 320px = 16px, на 1920px = 96px — слишком! */
}
Адаптивные отступы
section {
padding-block: clamp(2rem, 1rem + 5vh, 6rem);
padding-inline: clamp(1rem, 2vw, 4rem);
}
Модальное окно
.modal {
position: fixed;
inset: 0;
width: 100vw;
height: 100svh; /* svh — гарантированно помещается */
display: grid;
place-items: center;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
}
.modal-content {
width: min(90vw, 600px);
max-height: 80svh;
overflow-y: auto;
padding: 32px;
background: white;
border-radius: 12px;
}
vmin и vmax
/* vmin — адаптация к меньшей стороне */
.square {
width: 50vmin;
height: 50vmin;
/* Всегда квадрат, всегда помещается */
}
/* vmax — адаптация к большей стороне */
.overlay-text {
font-size: 10vmax;
/* Всегда крупный, независимо от ориентации */
}
Частые ошибки
100vhна мобильных — используйте100dvhили100svh:/* ПРОБЛЕМА */ .hero { height: 100vh; } /* РЕШЕНИЕ */ .hero { min-height: 100dvh; }- font-size только через vw — на маленьких экранах текст слишком мелкий:
/* ОШИБКА */ body { font-size: 2vw; } /* ПРАВИЛЬНО */ body { font-size: clamp(1rem, 0.5rem + 1vw, 1.25rem); } width: 100vwвызывает горизонтальный скролл — 100vw включает scrollbar:/* ОШИБКА — с вертикальным скроллбаром появится горизонтальный */ .section { width: 100vw; } /* ПРАВИЛЬНО */ .section { width: 100%; }- Забыли fallback для
dvh/svh— старые браузеры не поддерживают
Практика
- Создать hero-секцию на
100dvhс fallback на100vh - Сделать адаптивную типографику через
clamp+vw - Создать модальное окно с
svhиmin(90vw, 600px) - Сравнить
100vh,100svh,100lvh,100dvhна мобильном - Создать квадратный элемент через
vmin
Связанные темы
- Единицы измерения — все единицы
- Media queries — адаптивные стили
- Responsive Design -- принципы — адаптивный дизайн
- min() max() clamp() — ограничение значений
- Container queries — единицы контейнера (
cqi)