Safari и тестирование

Динамические единицы viewport в CSS 2026 для статических HTML-героев: dvh, svh, lvh, мобильный Safari и QA WebKit на облачном Mac mini

MacHTML Lab2026.05.20около 28 мин

Статические лендинги по-прежнему ставят min-height: 100vh на полноэкранных героях—а Safari в iOS по-прежнему врёт о том, что такое «один viewport», когда адресная строка схлопывается. Дизайнеры видят заголовки, обрезанные на 40–120 px, демо-видео за индикатором «домой» и основные CTA, которые появляются только после случайного скролла. В 2026 году CSS добавляет динамические единицы viewportdvh, svh и lvh—они привязаны к сейчас видимому браузерному хрому, а не к максимально возможной области. Руководство для команд MPA, которым нужна воспроизводимая ветка WebKit, а не только эмуляция Chromium. Перекрёстно читайте scroll-padding для фиксированной шапки и якорей, overscroll в модалках и адаптивные изображения и LCP, чтобы политики скролла, вёрстки и медиа совпадали.

Вы уйдёте с матрицей выбора единиц, прогрессивным стеком @supports и численными ориентирами (100dvh по умолчанию для маркетинговых героев, типичный нижний safe-area около 34 px на iPhone с вырезом, 45 минут железной QA на локаль), которые дизайн-ревью могут подписать в Git.

Почему тема снова актуальна в 2026: кампании на статике выкатываются параллельно на десятки рынков, и каждая локализация меняет переносы и метрики. Герой, который «влезает» по-английски, может уехать под первый экран на финском или немецком без изменения самого viewport-бага—он просто становится заметнее. Параллельно падает терпимость к JS-хакам, которые на каждом кадре тулбара переписывают window.innerHeight: они рискуют CLS, жрут батарею и усложняют доступность.

MPA выигрывают особенно сильно, потому что критический CSS часто — рукописный файл без reconciler фреймворка: неверная единица неделями сидит в CDN-кэше. Если у вас design tokens или утилиты, явно документируйте, какие компоненты могут использовать dvh, а какие намеренно остаются на vh, чтобы джуны не смешивали resize-слушатели и CSS.

Почему 100vh ломается в мобильном Safari

Классический vh опирается на large viewport—область, когда хром браузера скрыт. Мобильный Safari анимирует верхнее поле URL и нижнюю панель при прокрутке, поэтому видимая зона отрисовки может быть сильно меньше, чем единица, от которой вы верстали. Десктопный Chrome в responsive не повторяет ту же кривую анимации; команды, тестирующие только эмуляцию, отгружают регрессии, которые видны лишь на «директорских» iPhone.

Это не «Safari неправ»—vh отвечал на вопрос layout viewport 2012 года, а продуктовый дизайн 2026 ждёт «размерить по тому, что пользователь видит сейчас». Динамические единицы закрывают разрыв без JS-listener’ов resize, которые борются с композиторным скроллом и разряжают батарею на длинных маркетинговых страницах.

Дополнительно visualViewport и уровни зума iOS по-другому влияют на воспринимаемую высоту, чем Android Chrome. Даже без запрета pinch-zoom пользователи с крупным системным шрифтом сужают полезную высоту. Поэтому min-height лучше жёсткого height: поток поглощает дрейф, пока контейнер не привязан к фантомной высоте.

Юридически значимые блоки—cookie-баннеры, медицинские предупреждения, финансовые дисклеймеры—не должны прятаться за тулбар, который сжимается только после жеста. Здесь помогает svh: он консервативно ориентируется на минимальную конфигурацию хрома и скорее даст пустоту, чем спрячет обязательный текст.

dvh, svh, lvh — матрица решений

dvh (dynamic viewport height) следует за текущей видимой высотой, пока панели появляются и исчезают. svh (small viewport height) фиксируется на минимальной конфигурации хрома—полезно, если CTA никогда не должен оказаться под адресной строкой. lvh (large viewport height) соответствует старому поведению vh. Горизонтальные пары dvw, svw, lvw важны для каруселей, которые упираются в safe area на телефонах с вырезом.

ЕдиницаЛучше всего дляРиск при ошибке
100dvhПолноэкранные герои, сплэш-экраныЛёгкие сдвиги высоты при скролле могут чуть сдвинуть фоновое видео
100svhГарантии выше первого экрана, промо-полосыЛишний воздух, когда хром скрывается
100lvhLegacy-паритет, только десктопные полосыТе же обрезки, что у классического vh на iOS
calc(100dvh - 4rem)Герой минус фиксированная навигацияЗабыть env(safe-area-inset-*) на вырезанных устройствах

По умолчанию ставьте маркетинговые герои на min-height: 100dvh, если арт-дирекшн не требует жёстко заблокированного малого viewport—например юридические баннеры, которые должны быть видны, пока URL-бар развёрнут.

Горизонтальные единицы часто недооценивают: герой с видео 16:9, 100dvw и object-fit: cover может сильнее кадрировать у выреза, чем ожидалось в макете. Зафиксируйте безопасные зоны кропа в handoff и отразите их в CSS-переменных.

Паттерны героя для статического HTML

Предпочитайте min-height жёсткому height, чтобы переведённые заголовки росли без обрезки нижних выносных. Центрируйте flexbox’ом, но оставляйте прокрутку на документе, а не внутри героя, если вы не тестировали вложенный скролл с overscroll-behavior. Когда видео под текстом, задавайте контейнер в dvh и object-fit: cover на медиа, чтобы LCP оставался честным.

В сплит-лейауте (копия слева, мок устройства справа) ограничьте мок max-height: 70dvh, чтобы ландшафт на телефоне не выталкивал CTA за экран. Добавьте clamp() для типографики, чтобы переносы укладывались в динамическую коробку без JavaScript.

Если страницы собирает Eleventy, Hugo и т.п., вынесите критические правила героя в маленький файл, одинаковый для локалей, пока меняются только строки. Подключите Stylelint, который ругается на 100vh в селекторах героя без сопутствующего @supports.

Доступность: при автоплее видео в герое элементы управления должны оставаться видимыми, даже если dvh меняется вместе с тулбаром. Фокус VoiceOver не должен попадать в визуально скрытый слой; проверяйте с включённым «уменьшить движение».

Safe areas и липкие нижние панели

Динамические единицы задают размер коробки; они не заменяют env(safe-area-inset-top) и env(safe-area-inset-bottom). Фиксированная панель покупки может выглядеть так:

.sticky-cta {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  padding-bottom: max(1rem, env(safe-area-inset-bottom));
}

На классе iPhone 15 нижний inset часто около 34 px; команды с паддингом 16 px всё ещё режут кнопки. Добавьте viewport-fit=cover в meta viewport, если намеренно рисуете под вырез—без этого переменные safe-area могут читаться как ноль.

Если одновременно есть фиксированная таб-полоса и герой на dvh, проверьте, что суммарный паддинг не даёт слишком узких тач-таргетов; Apple рекомендует минимум 44×44 pt.

Прогрессивное улучшение через @supports

.hero {
  min-height: 100vh;
}
@supports (height: 100svh) {
  .hero { min-height: 100svh; }
}
@supports (height: 100dvh) {
  .hero { min-height: 100dvh; }
}

Отдавайте каскад в этом порядке, чтобы старые сборки WebKit деградировали контролируемо. Если пайплайн инлайнит критический CSS, весь стек должен поместиться в первый gzip-бюджет 14 КБ—герои по определению above-the-fold.

Частая ошибка—защитить только внутренний селектор, пока родитель держит height: 100vh и ломает дочерний стек. Пройдите всю цепочку линтером или библиотекой компонентов.

Особенности WebKit в 2026

Safari на macOS в оконном режиме мапит динамические единицы на видимый content-rect; отличие от iOS может быть 8–12 px, когда видны вкладки и панели. Снимайте скриншоты на обеих платформах. Когда 100dvh анимируется при смене тулбара, отключайте дорогой background-attachment: fixed—параллаксы вызывают repaint на main thread и роняют плавность ниже 55 fps на базовых M-чипах под нагрузкой.

Липкие элементы внутри героя на dvh могут «подпрыгивать» при смене единицы. По возможности переносите sticky-навигацию к корню документа и оставьте dvh только для декоративного фона.

Safari Technology Preview иногда опережает Stable по семантике viewport. Для долгоживущих маркетинговых ассетов планируйте короткую регрессию раз в квартал после крупных обновлений iOS.

Чеклист QA на реальном устройстве

  1. Открыть страницу с развёрнутой адресной строкой; основной CTA виден без скролла.
  2. Прокрутить ~120 px; сворачивание тулбара не должно прятать обязательный юртекст.
  3. Повернуть в ландшафт; промо на svh должны очищать индикатор «домой».
  4. VoiceOver на липком футере; нижний inset не должен уводить фокус за экран.
  5. Сравнить filmstrip между stable Safari и STP, когда Apple меняет viewport.
  6. Архивировать до/после PNG в тикете для подписи дизайна.

Заложите 45 минут на локаль, если строки длиннее английского минимум на 30 %; немецкий и бразильский португальский часто вскрывают скрытые допущения вёрстки.

Автоматические screenshot-diff на арендованном Mac mini по SSH ускоряют регрессии, но не заменяют жест большим пальцем: физика тулбара иная, чем у колеса мыши.

FAQ

Нужно ли заменять все vh на dvh?

Нет—декоративные середины страницы могут оставить vh. В приоритете полноэкранные герои, модальные шиты и липкие CTA, которые сталкиваются с мобильным хромом.

Штрафует ли Lighthouse dvh?

Лабораторные отчёты всё ещё могут показать layout shift, если у медиа в герое нет размеров; динамические единицы не заменяют width/height.

Можно ли смешивать innerHeight в JS и CSS?

Избегайте двух истин—resize-слушатели возвращают джанк. Лучше динамические единицы CSS с фолбэком @supports.

Аренда Mac mini на Apple Silicon через MacHTML даёт тот же билд WebKit, что у стейкхолдеров в поле,—не Linux-контейнер, притворяющийся Safari. Ноды дают SSH для пайплайнов скриншот-диффов и опциональный VNC, когда дизайнеру нужно покадрово разобрать анимацию тулбара. Потребление в простое часто 6–12 Вт, поэтому двухнедельный аудит viewport дешевле, чем регрессия героя в окне релиза.

Публичные цены около 16,9 $ в сутки—выгоднее покупки ещё одной настольной машины, которая простаивает после кампании. QA закончили—остановите инстанс; стеки dvh остаются в git, а железо не амортизируется по 36 месяцам закупочных циклов.

Прогоните фиксы viewport Safari на настоящем macOS

Арендуйте облачный Mac mini, чтобы проверить героев dvh, паддинг safe-area и липкие CTA в WebKit до слияния статического CSS.

QA dvh на реальном Mac
от ~16,9 $/сутки