Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке vh, vw, vmin та vmax у CSS». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Viewport одиниці CSS** (`vh`, `vw`, `vmin`, `vmax`) - кожна дорівнює 1% відповідного розміру вікна браузера: висота, ширина, менша або більша сторона. ```css .hero { height: 100vh; } /* повна висота екрана */ .card { width: 40vmin; } /* 40% меншої сторони */ ``` **Головне:** `100vh` на мобільному Safari виходить за межі видимої області на ~80px. Використовуй `100dvh` в Chrome 108+ і iOS 15.4+.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`vh`, `vw`, `vmin` та `vmax`** - це CSS viewport-одиниці, де 1 одиниця дорівнює 1% відповідного розміру вікна браузера: `vh` - висота, `vw` - ширина, `vmin` - менша сторона, `vmax` - більша. ## Теорія ### TL;DR - `100vh` заповнює екран зверху донизу, `100vw` - зліва направо - `vmin` прив'язується до коротшої сторони вікна, `vmax` - до довшої. Обидві автоматично перераховуються при повороті пристрою - На відміну від `px`, всі чотири одиниці оновлюються при кожному ресайзі та зміні орієнтації - Viewport-одиниці - для контейнерів і hero-секцій, `rem` - для тексту - Підводний камінь: `100vh` на iOS Safari виходить за межі видимої області на ~80px через адресний рядок ### Швидкий приклад ```css .hero { height: 100vh; /* займає повну висоту вікна */ width: 100vw; /* займає повну ширину вікна */ } .card { width: 40vmin; /* 40% від коротшої сторони, зберігає пропорції при повороті */ height: 40vmin; background: #4a90e2; } ``` На десктопі 1200x800: `1vh = 8px`, `1vw = 12px`, `1vmin = 8px`. Поверни телефон - і `vmin` сам переключиться на коротшу сторону. Жодного JavaScript. ### Ключова різниця від інших одиниць Viewport-одиниці завжди відраховуються від вікна браузера, а не від батьківського елемента. `50vw` на глибоко вкладеному елементі означає рівно половину екрана. А `50%` - половину батьківського контейнера. Це важливо: viewport-одиниці добре підходять для секцій на весь екран, але не для компонентів, що мають масштабуватися відносно свого контейнера. ### Коли використовувати - Повноекранні hero-секції: `height: 100vh` - Квадратні елементи, які не ламаються при повороті: `width: 40vmin; height: 40vmin` - Модалки, що поміщаються під браузерним chrome: `max-height: 90vh` - Банери, які розтягуються по максимальній стороні: `vmax` - Текст у контенті: `rem`, не viewport-одиниці ### Таблиця порівняння | Одиниця | Основа | Portrait 390x844 | Landscape 844x390 | Використання | |---------|--------|------------------|-------------------|--------------| | `vh` | Висота вікна | `1vh = 8.44px` | `1vh = 3.9px` | Повноекранні секції | | `vw` | Ширина вікна | `1vw = 3.9px` | `1vw = 8.44px` | Горизонтальні блоки | | `vmin` | Менша сторона | `1vmin = 3.9px` | `1vmin = 3.9px` | Квадратні елементи | | `vmax` | Більша сторона | `1vmax = 8.44px` | `1vmax = 8.44px` | Розтягнуті банери | | `px` | Фіксований | Завжди 1px | Завжди 1px | Точні розміри | ### Як браузер обчислює ці одиниці Браузер вимірює початковий контейнер (прямокутник вікна без смуг прокрутки), ділить на 100 і множить на твоє число. Перерахунок відбувається при кожній зміні розміру вікна або орієнтації пристрою. Складнощі починаються на мобільних: iOS Safari включав адресний рядок у розрахунок `vh`, тому `100vh` виявлявся вищим за видиму область приблизно на 80px. Chrome 108 і iOS 15.4 додали `dvh` (dynamic viewport height) для вирішення цієї проблеми. ### Типові помилки **`height: 100vh` для повноекранного мобільного layout:** ```css /* Неправильно: iOS Safari обрізає ~80px під адресним рядком */ .app { height: 100vh; } /* Правильно */ .app { height: 100vh; /* fallback для старіших браузерів */ height: 100dvh; /* Chrome 108+, iOS 15.4+ - перекриває vh якщо підтримується */ } ``` Саме ця помилка ламала bottom-навігацію в кількох продакшн-застосунках на Next.js, які я бачив. Два рядки коду повністю її виправляють. **`width: 100vw` для nav-бару:** ```css /* Неправильно: додає ширину смуги прокрутки (~15px), з'являється горизонтальний скрол */ nav { width: 100vw; } /* Правильно */ nav { width: 100%; } ``` **Відсутність fallback для старих браузерів:** ```css .box { width: 30%; } /* fallback */ .box { width: 30vmin; } /* сучасні браузери перекривають */ ``` IE 9-11 частково підтримував `vh` і `vw`, але `vmin` і `vmax` не розумів. Відсотки як fallback вирішують це. ### Де зустрічається - Tailwind CSS: `h-screen` компілюється в `height: 100vh` - Bootstrap 5: `--bs-full-height: 100vh` в offcanvas і модальних компонентах - shadcn/ui: повноекранні лоадери використовують `height: 100vh` - Three.js: `width: 100vw; height: 100vh` для canvas-елементів - Next.js landing pages: hero-секції і backdrop модальних вікон ### Питання на співбесіді **Q:** Яка різниця між `100vh` і `height: 100%`? **A:** `100vh` завжди дорівнює висоті вікна браузера. `height: 100%` потребує, щоб кожен батьківський елемент аж до `<html>` мав явно задану висоту, інакше елемент стискається до нуля. **Q:** Чому `100vh` не працює правильно в мобільному Safari? **A:** Safari включав адресний рядок у розрахунок `vh`, тому `100vh` виявлявся більшим за видиму частину екрана. Для iOS 15.4+ і Chrome 108+ використовуй `100dvh`. Для старих браузерів досі актуальний JS-хак із CSS-змінною. **Q:** Коли вибрати `vmin` замість `vw`? **A:** Коли елемент має бути видимим в обох орієнтаціях. `vmin` завжди прив'язаний до коротшої сторони, тому `40vmin` після повороту не вийде за межі екрана. **Q:** Що таке `dvh`, `svh` і `lvh`? **A:** Нові одиниці з CSS Viewport Units Level 4. `dvh` - динамічна висота (змінюється зі зміною адресного рядка). `svh` - мінімальна висота (рядок видно). `lvh` - максимальна (рядок прихований). Всі основні браузери підтримують їх з 2023 року. ## Приклади ### Повноекранна hero-секція ```css .hero { width: 100vw; height: 100vh; /* базовий варіант для всіх браузерів */ height: 100dvh; /* динамічна висота для сучасних мобільних */ display: flex; align-items: center; justify-content: center; background: #1a1a2e; } ``` Стандартний паттерн для landing-сторінок. Друге оголошення `height` перекриває перше в браузерах з підтримкою `dvh`, тому окремий media query не потрібен. ### Адаптивне модальне вікно ```css .modal { width: clamp(300px, 80vw, 800px); height: clamp(200px, 70vh, 600px); max-width: 90vmin; margin: auto; background: white; border-radius: 8px; overflow: auto; } ``` На десктопі 1920x1080 modal займе 800x600px. На портретному телефоні стисниться до приблизно 310x480px. Обмеження `90vmin` запобігає overflow в обох орієнтаціях без додаткових media queries.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.