Mobile Viewport-Einheiten und der iOS-100vh-Bug
Der berüchtigte iOS-Safari-Bug mit 100vh hat Entwickler jahrelang beschäftigt. Die modernen CSS-Viewport-Einheiten dvh, svh und lvh lösen das Problem dauerhaft — ohne JavaScript, ohne Resize-Events und ohne fragile Workarounds. Dieser Artikel erklärt, wie Dynamic, Small und Large Viewport Units funktionieren und wann man welche Einheit wirklich braucht.
Inhaltsverzeichnis
- 1. Das 100vh-Problem auf mobilen Browsern
- 2. svh — Small Viewport Height
- 3. lvh — Large Viewport Height
- 4. dvh — Dynamic Viewport Height
- 5. Viewport-Breiten: svw, lvw, dvw
- 6. Praxisbeispiele: Hero-Sections und Modals
- 7. Fallback-Strategien und Progressive Enhancement
- 8. Viewport-Einheiten im direkten Vergleich
- 9. Performance und Layout-Stabilität
- 10. Zusammenfassung
- 11. FAQ
1. Das 100vh-Problem auf mobilen Browsern
Wer je eine Vollbild-Hero-Section oder ein mobiles Overlay mit height: 100vh umgesetzt hat, kennt das Problem: Auf iOS Safari und älteren Android-Browsern wird die Höhe falsch berechnet. Der Browser misst den Viewport ohne seine eigene UI-Chrome — Adressleiste, Tab-Leiste, untere Navigation — was dazu führt, dass 100vh größer ist als der tatsächlich sichtbare Bereich. Das untere Ende des Elements verschwindet hinter der Browser-UI. Dieses Problem ist kein Safari-Bug im klassischen Sinne, sondern ein Designentscheid: Apple wollte beim Scrollen eine flüssige UI-Animation ermöglichen, bei der die Browser-Chrome ein- und ausfährt. Die daraus folgende Diskrepanz zwischen CSS-Viewport-Höhe und sichtbarem Bereich hat Entwickler seit iOS 8 begleitet.
Der klassische Workaround war JavaScript: Ein resize-Event-Listener setzt eine CSS-Custom-Property mit window.innerHeight, die dann statt 100vh verwendet wird. Das Muster ist bekannt, aber anfällig. Es erfordert JavaScript beim ersten Paint, erzeugt ein Layout-Reflow beim Auslösen des Events und funktioniert nicht, wenn JavaScript geblockt oder verzögert ist. Die modernen CSS dvh-, svh- und lvh-Einheiten bieten eine rein CSS-basierte Lösung, die alle diese Nachteile beseitigt. Sie wurden 2022 in der CSS-Spezifikation standardisiert und sind seit Chromium 108, Safari 15.4 und Firefox 101 breit verfügbar.
2. svh — Small Viewport Height
svh (Small Viewport Height) entspricht der Höhe des Viewports, wenn die Browser-UI vollständig ausgefahren ist — also wenn alle Leisten sichtbar sind und der verfügbare Bereich am kleinsten ist. Auf einem iPhone mit Safari in der Standard-Position zeigt 100svh genau die Höhe, die dem Nutzer tatsächlich zur Verfügung steht, wenn die Adressleiste vollständig zu sehen ist. svh ist damit die konservativste Variante: Ein Element mit height: 100svh passt immer in den Viewport, egal in welchem Zustand sich die Browser-UI befindet.
Die Einheit eignet sich hervorragend für Elemente, die garantiert vollständig sichtbar sein müssen — unabhängig davon, ob die Browser-Chrome gerade ein- oder ausgefahren ist. Typische Anwendungsfälle sind Dialoge, Modale und Overlays, bei denen es kritisch ist, dass kein Inhalt hinter der Browser-UI verschwindet. CSS svh ist die sichere Wahl, wenn Vollständigkeit der Anzeige Vorrang vor maximaler Ausnutzung des verfügbaren Platzes hat. Ein Nachteil: Beim Ein- und Ausfahren der Browser-Chrome entsteht ein visuelles Springen, weil 100svh dann kleiner ist als der tatsächlich verfügbare Bereich.
/* Small Viewport Height — conservative: always fully visible */
.modal-overlay {
/* Height based on smallest possible viewport (UI fully visible) */
height: 100svh;
overflow-y: auto;
}
.sticky-footer-nav {
/* Position relative to small viewport bottom */
position: fixed;
bottom: 0;
left: 0;
right: 0;
/* Ensure content above nav is visible within small viewport */
padding-bottom: env(safe-area-inset-bottom, 0px);
}
/* Minimum height that works in all browser UI states */
.hero-safe {
min-height: 100svh;
display: flex;
align-items: center;
}
/* Container that must not be clipped by browser chrome */
.fullscreen-dialog {
width: 100svw;
height: 100svh;
position: fixed;
inset: 0;
}
Ein wichtiger Unterschied zu 100vh: svh ist ein statischer Wert, der sich beim Scrollen nicht ändert. Der Browser berechnet ihn einmalig basierend auf dem kleinsten möglichen Viewport-Zustand und hält diesen Wert. Das verhindert Layout-Reflows beim Scrollen, was CSS svh aus Performance-Sicht attraktiver macht als dvh, wenn keine dynamische Anpassung benötigt wird.
3. lvh — Large Viewport Height
lvh (Large Viewport Height) ist das Gegenteil von svh: Es entspricht der Höhe des Viewports, wenn die Browser-UI vollständig eingefahren ist — also wenn der maximale Platz für Inhalte zur Verfügung steht. Das ist der Zustand, den viele Nutzer beim Scrollen durch eine Seite sehen: Die Adressleiste ist verschwunden, der untere Tab-Bar hat sich zurückgezogen, und der Inhalt füllt den gesamten Bildschirm. 100lvh entspricht damit dem, was 100vh auf Desktop-Browsern ohne dynamische Chrome bedeutet.
Der Einsatzbereich von CSS lvh ist enger als der von svh oder dvh. Es eignet sich für dekorative Elemente wie Hintergrundbilder oder -videos, bei denen ein leichtes Abschneiden am Rand kein Problem darstellt, und wo man die maximale Bildfläche ausnutzen möchte. Kritisch: Bei initialer Seitenanzeige, wenn die Browser-Chrome noch sichtbar ist, kann ein Element mit height: 100lvh über den sichtbaren Bereich hinausragen. Das führt zu unerwünschtem Scroll-Verhalten oder abgeschnittenem Inhalt. lvh ist daher selten die erste Wahl für interaktive oder inhaltstragende Elemente.
4. dvh — Dynamic Viewport Height
dvh (Dynamic Viewport Height) ist die intelligenteste der drei Einheiten. Sie passt sich dynamisch an den aktuellen Zustand der Browser-UI an: Wenn die Adressleiste sichtbar ist, entspricht 100dvh 100svh; wenn sie eingefahren ist, entspricht es 100lvh. Das klingt nach der idealen Lösung — und für viele Anwendungsfälle ist es das auch. Die Einheit verhält sich so, wie Entwickler intuitiv erwarten, dass 100vh auf Mobilgeräten funktioniert.
Der Preis für diese Flexibilität ist ein möglicher Layout-Reflow während des Scrollens. Wenn der Nutzer scrollt und die Browser-Chrome ein- oder ausfährt, ändert sich der berechnete Wert von dvh. Elemente, die diesen Wert für ihre Höhe verwenden, werden neu berechnet und möglicherweise neu gerendert. Bei einfachen Containern ist das unproblematisch. Bei komplexen Layouts mit vielen abhängigen Größen kann das zu sichtbarem Flackern oder Springen führen. Für Hero-Sections und Fullscreen-Elemente, bei denen die Anpassung an den aktuellen Viewport-Zustand wichtiger ist als Layout-Stabilität, bleibt CSS dvh die empfohlene Wahl.
/* Dynamic Viewport Height — adapts to current browser UI state */
.hero-section {
/* Fills exactly the visible area, regardless of browser chrome state */
min-height: 100dvh;
display: grid;
place-items: center;
}
/* Fullscreen mobile menu */
.mobile-nav-overlay {
position: fixed;
inset: 0;
/* Dynamic: correct height when menu opens mid-scroll */
height: 100dvh;
overflow-y: auto;
overscroll-behavior: contain;
}
/* Large Viewport for decorative backgrounds */
.bg-video-container {
/* Use lvh for decorative elements where overflow is acceptable */
min-height: 100lvh;
position: relative;
overflow: hidden;
}
/* Progressive enhancement: cascade from old to new */
.fullscreen-element {
height: 100vh; /* Fallback for old browsers */
height: 100dvh; /* Dynamic viewport — modern browsers */
}
/* Fluid typography scaled to viewport height */
.hero-headline {
font-size: clamp(2rem, 8dvh, 5rem);
}
5. Viewport-Breiten: svw, lvw, dvw
Die gleiche Dreiteilung gibt es auch für die Breite: svw, lvw und dvw entsprechen den gleichen Konzepten auf der horizontalen Achse. In der Praxis ist das Unterschied zwischen den drei Breiten-Varianten auf den meisten Geräten weniger spürbar, da Browser ihre horizontale Chrome selten dynamisch ein- und ausfahren. Die größte Ausnahme sind Browser mit seitlichen Panelen oder bestimmte PWA-Modi. Dennoch gibt es das vollständige Set: svw, lvw, dvw sowie die Inline- und Block-Varianten svi, lvi, dvi, svb, lvb, dvb.
Besonders relevant für moderne Layouts ist die Kombination aus dvh und dvw für wirklich vollbildfüllende Elemente. Mit width: 100dvw; height: 100dvh; und position: fixed; inset: 0; entsteht ein Element, das den sichtbaren Bereich exakt abdeckt — zu jedem Zeitpunkt und in jedem Browser-UI-Zustand. Die neuen Einheiten ergänzen außerdem die existierenden Varianten vmin und vmax, für die es jetzt auch svmin, lvmin, dvmin sowie svmax, lvmax und dvmax gibt.
6. Praxisbeispiele: Hero-Sections und Modals
Die häufigsten Einsatzfälle für CSS dvh, svh und lvh sind Vollbild-Hero-Sections, mobile Navigations-Overlays und Modale. Für Hero-Sections ist min-height: 100dvh die empfohlene Wahl: Das Element füllt den sichtbaren Bereich in jedem Zustand, wächst aber bei Bedarf, wenn der Inhalt mehr Platz benötigt. Für Modale, die unbedingt vollständig sichtbar sein müssen, ist height: 100svh die sicherste Wahl, da sie auch dann korrekt ist, wenn die Browser-Chrome sichtbar ist.
Ein weiterer wichtiger Anwendungsfall ist die Berechnung von Sticky-Elementen und Scroll-Snap-Containern. Mit CSS dvh lassen sich Scroll-Snap-Sections erstellen, die immer exakt den sichtbaren Bereich einnehmen — unabhängig davon, ob die Adressleiste gerade sichtbar ist oder nicht. Das führt zu einem deutlich konsistenteren Scroll-Erlebnis auf Mobilgeräten als der JavaScript-basierte Ansatz.
/* Scroll-snap fullscreen sections using dvh */
.snap-container {
height: 100dvh;
overflow-y: scroll;
scroll-snap-type: y mandatory;
overscroll-behavior-y: contain;
}
.snap-section {
height: 100dvh; /* Each section fills exactly the visible viewport */
scroll-snap-align: start;
display: flex;
flex-direction: column;
justify-content: center;
}
/* Modal: always fully visible, even when browser chrome is showing */
.modal-wrapper {
position: fixed;
inset: 0;
height: 100svh; /* svh: conservative, never clipped by browser UI */
display: grid;
place-items: center;
background-color: rgb(0 0 0 / 0.6);
}
.modal-content {
max-height: calc(100svh - 4rem); /* Leave breathing room inside safe viewport */
overflow-y: auto;
border-radius: 1rem;
}
/* Sticky sidebar that respects dynamic viewport */
.sidebar {
position: sticky;
top: 0;
height: 100dvh;
overflow-y: auto;
}
7. Fallback-Strategien und Progressive Enhancement
Obwohl CSS dvh, svh und lvh mittlerweile in allen modernen Browsern unterstützt werden, ist eine Fallback-Strategie für ältere Browser sinnvoll. Das einfachste Muster ist die Kaskade: Zuerst die alte Einheit deklarieren, direkt danach die neue. Browser, die die neue Einheit nicht kennen, ignorieren sie einfach und nutzen den Fallback. Browser mit Unterstützung überschreiben den Wert. Dieses Muster funktioniert ohne Feature-Detection oder JavaScript.
Für Projekte, die noch ältere Browser unterstützen müssen, gibt es den bewährten CSS-Custom-Property-Trick als zusätzliche Absicherung. Die CSS-Custom-Property --vh wird per JavaScript auf window.innerHeight * 0.01 gesetzt und dann als calc(var(--vh, 1vh) * 100) verwendet. Dieser Ansatz liefert korrekte Werte auf allen Geräten, hat aber den Nachteil des JavaScript-Dependencies. Mit CSS dvh als primärer Deklaration und 100vh als Fallback entfällt diese Notwendigkeit für die meisten aktuellen Projektanforderungen vollständig.
8. Viewport-Einheiten im direkten Vergleich
Die Wahl der richtigen CSS Viewport-Einheit hängt vom konkreten Anwendungsfall ab. Die folgende Tabelle fasst die wesentlichen Unterschiede zusammen und gibt Empfehlungen für typische Szenarien.
| Einheit | Basis | Layout-Reflow | Bester Einsatz |
|---|---|---|---|
100vh |
UA-abhängig (oft ohne Chrome) | Nein | Desktop, Fallback für alte Browser |
100svh |
Kleinster Viewport (UI sichtbar) | Nein | Modale, Dialoge, kritische Overlays |
100lvh |
Größter Viewport (UI versteckt) | Nein | Dekorative Hintergründe, Bilder |
100dvh |
Aktueller Viewport (dynamisch) | Beim Scrollen möglich | Hero-Sections, Scroll-Snap, Sidebars |
JS --vh |
window.innerHeight |
Bei Resize-Event | Legacy-Browser als letzter Ausweg |
Für die meisten modernen Projekte ist min-height: 100dvh die empfohlene Standardlösung für Fullscreen-Elemente auf Mobilgeräten. CSS svh kommt dazu, wenn garantierte Vollsichtbarkeit wichtiger ist als exakte Ausnutzung des verfügbaren Platzes. lvh bleibt ein Spezialfall für dekorative Elemente, bei denen minimales Überlaufen akzeptabel ist.
9. Performance und Layout-Stabilität
Aus Performance-Sicht ist CSS dvh die einzige der neuen Einheiten, die beim Scrollen zu Neuberechnungen führen kann. Wenn die Browser-Chrome ein- oder ausfährt, müssen alle Elemente, die dvh-basierte Werte verwenden, neu berechnet werden. Auf modernen Geräten und Browsern ist dieser Overhead minimal und in der Praxis kaum messbar. Dennoch gilt: Wer Layout-Instabilität vollständig vermeiden möchte, sollte svh oder lvh bevorzugen, je nachdem welcher Viewport-Zustand die Grundlage sein soll.
Im Kontext der Core Web Vitals ist besonders der Cumulative Layout Shift (CLS) relevant. Elemente, deren Höhe durch dvh gesteuert wird und die während der initialen Ladephase noch keine stabile Größe haben, können zum CLS beitragen. Die Lösung ist, den initialen Wert mit svh zu setzen und dvh nur für Zustandsänderungen nach dem ersten Paint zu verwenden — zum Beispiel über eine CSS-Klasse, die nach dem initialen Load gesetzt wird. Für die meisten Hero-Sections ist dieser Aufwand nicht notwendig, da min-height: 100dvh ohne harte Größenfixierung CLS-neutral ist.
Mironsoft
Mobile-first CSS, Responsive Design und Performance-Optimierung
Mobile Layouts, die auf jedem Gerät korrekt aussehen?
Wir analysieren bestehende Layouts auf mobile Viewport-Probleme, ersetzen fragile Workarounds durch moderne CSS-Lösungen und sorgen dafür, dass Hero-Sections, Modale und Fullscreen-Elemente auf iOS Safari, Android Chrome und allen modernen Browsern korrekt dargestellt werden.
Viewport-Audit
Analyse aller vh-Einsätze und Identifikation von iOS-Safari-Problemen im Bestandscode
CSS-Migration
Ersetzen von JS-Workarounds durch dvh, svh und lvh mit korrekten Fallbacks
CLS-Optimierung
Layout-Shift durch korrekte Viewport-Einheiten und stabile initiale Layouts reduzieren
10. Zusammenfassung
Die drei modernen CSS Viewport-Einheiten dvh, svh und lvh lösen das jahrelange Problem mit 100vh auf mobilen Browsern dauerhaft und ohne JavaScript. dvh passt sich dynamisch an den aktuellen Viewport-Zustand an und ist die beste Wahl für Hero-Sections und Scroll-Snap-Layouts. svh basiert auf dem kleinsten möglichen Viewport und garantiert, dass Elemente immer vollständig sichtbar sind — ideal für Modale und kritische Overlays. lvh nutzt den größten Viewport und ist für dekorative Hintergrundelemente geeignet, bei denen minimales Überlaufen akzeptabel ist.
Die empfohlene Fallback-Strategie ist einfach: Erst 100vh deklarieren, dann in der nächsten Zeile 100dvh. Ältere Browser ignorieren die unbekannte Einheit; moderne Browser überschreiben den Wert. Für die meisten modernen Projekte ist min-height: 100dvh die einzig nötige Änderung, um iOS-Safari-100vh-Probleme zu beseitigen — eine einzelne CSS-Zeile ersetzt komplexen JavaScript-Code.
CSS dvh, svh, lvh — Das Wichtigste auf einen Blick
dvh — Dynamic Viewport
Passt sich an Browser-Chrome-Zustand an. Beste Wahl für Hero-Sections und Scroll-Snap. Möglicher Reflow beim Scrollen.
svh — Small Viewport
Basiert auf kleinstem Viewport (Chrome sichtbar). Garantiert vollständige Sichtbarkeit. Ideal für Modale und Overlays.
lvh — Large Viewport
Basiert auf größtem Viewport (Chrome versteckt). Für dekorative Hintergründe geeignet. Kann über sichtbaren Bereich hinausgehen.
Fallback-Pattern
height: 100vh; height: 100dvh; — Kaskade reicht aus. Kein JavaScript nötig für moderne Browser-Unterstützung.