iPhone Notch, Dynamic Island und PWA-Vollbild
Seit dem iPhone X mit seiner Notch und dem iPhone 14 Pro mit dem Dynamic Island müssen Webentwickler sicherstellen, dass Inhalte nicht unter Hardware-Elementen verschwinden. CSS env() mit den safe-area-inset-* Variablen ist die standardisierte Lösung — für Browser, PWAs und native WebViews gleichermaßen.
Inhaltsverzeichnis
- 1. Warum Safe Area Insets existieren
- 2. viewport-fit=cover als Ausgangspunkt
- 3. Die CSS env()-Funktion
- 4. Die vier safe-area-inset-Richtungen
- 5. env() mit calc() kombinieren
- 6. PWA-Vollbild und standalone-Modus
- 7. Dynamic Island und neuere iPhone-Modelle
- 8. Safe Area Insets im Vergleich
- 9. Tailwind CSS Integration
- 10. Zusammenfassung
- 11. FAQ
1. Warum Safe Area Insets existieren
Mit dem iPhone X führte Apple 2017 das erste iPhone ohne Home-Button und mit gerundeten Display-Ecken ein. Das Display erstreckt sich fast über die gesamte Vorderseite des Geräts, unterbrochen nur von der Notch — dem Ausschnitt für Kamera und Face-ID-Sensoren. Diese Designentscheidung stellte Webentwickler vor eine neue Herausforderung: Inhalte, die in die Ecken oder unter die Notch ragten, wurden durch Hardware-Elemente verdeckt. Die Lösung war CSS env() mit den safe-area-inset-Variablen, die Apple zunächst als proprietäre Lösung einführte und die später in die CSS-Spezifikation aufgenommen wurde.
Das Prinzip ist einfach: Wenn eine Webseite oder PWA in den Vollbildmodus wechselt und damit den gesamten Bildschirm einschließlich der Bereiche hinter Notch und Dynamic Island nutzt, liefert das Betriebssystem Abstandswerte, die angeben, wie weit der "sichere" Bereich vom jeweiligen Bildschirmrand entfernt ist. Diese Werte sind geräteabhängig und orientierungsabhängig — im Querformat verschiebt sich die Notch auf eine Seite, was andere Inset-Werte ergibt als im Hochformat. CSS safe-area-inset-* macht diese Werte in CSS verfügbar, ohne dass JavaScript oder nativer Code benötigt wird.
2. viewport-fit=cover als Ausgangspunkt
Ohne eine spezielle Einstellung in der Viewport-Meta-Tag fügt Safari auf Geräten mit Notch automatisch Ränder ein, damit der Inhalt nicht unter Hardware-Elemente ragt. Das Standardverhalten ist praktisch, aber es bedeutet, dass die Seite weiße Ränder an den Seiten hat und den gesamten Bildschirmplatz nicht nutzt. Wer diesen Platz nutzen will, muss viewport-fit=cover zum Viewport-Meta-Tag hinzufügen. Dieses Attribut weist den Browser an, den Viewport auf den gesamten Bildschirm auszudehnen — einschließlich der Bereiche hinter Notch und Dynamic Island.
Sobald viewport-fit=cover aktiv ist, werden die safe-area-inset-* Variablen mit den korrekten Werten gefüllt. Ohne dieses Attribut sind die Inset-Werte immer 0, weil der Browser bereits eigenständig für Abstände sorgt. Es ist also wichtig: CSS env(safe-area-inset-*) funktioniert nur sinnvoll in Kombination mit viewport-fit=cover. Wer viewport-fit=cover setzt, aber die env()-Variablen vergisst, bekommt einen Layout mit Inhalte hinter Hardware-Elementen — das ist der häufigste Fehler bei der Implementierung.
/*
* Step 1: Enable viewport-fit=cover in HTML:
* <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
*
* Step 2: Use env() variables in CSS
*/
/* Basic safe area padding — all four sides */
.full-bleed-layout {
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}
/* Shorthand with logical properties */
.app-shell {
padding-block-start: env(safe-area-inset-top);
padding-block-end: env(safe-area-inset-bottom);
padding-inline-start: env(safe-area-inset-left);
padding-inline-end: env(safe-area-inset-right);
}
/* Old syntax for compatibility (iOS 11.0 - 11.1) */
.legacy-support {
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
}
3. Die CSS env()-Funktion
Die env()-Funktion in CSS funktioniert ähnlich wie var() für Custom Properties, greift aber auf vom Benutzeragenten (Browser/OS) definierte Umgebungsvariablen zu statt auf selbst deklarierte CSS-Variablen. Die Syntax ist identisch: env(variablenname, fallback). Der Fallback-Wert ist optional und wird verwendet, wenn die Umgebungsvariable nicht verfügbar ist — etwa auf Desktop-Geräten ohne Notch oder in Browsern, die env() nicht unterstützen.
Ein wichtiger Unterschied zu var(): CSS env() kann überall in einem CSS-Wert verwendet werden, auch innerhalb von calc()-Ausdrücken. Die Spezifikation definiert eine Reihe von vordefinierten Umgebungsvariablen, von denen die safe-area-inset-* Variablen die bekanntesten sind. Browser können weitere implementieren — zum Beispiel für verschiedene UI-Elemente. Die Variablen werden im Koordinatensystem des Bildschirms angegeben, nicht relativ zum Viewport-Ursprung.
4. Die vier safe-area-inset-Richtungen
Es gibt vier safe-area-inset Umgebungsvariablen: safe-area-inset-top, safe-area-inset-right, safe-area-inset-bottom, safe-area-inset-left. Im Hochformat des iPhone X beträgt safe-area-inset-top etwa 44 Pixel (die Notch-Höhe), safe-area-inset-bottom etwa 34 Pixel (der Home-Indicator-Bereich) und die Seiteninsets sind null. Im Querformat verschiebt sich die Notch auf eine Seite, sodass safe-area-inset-left oder safe-area-inset-right einen Wert erhält, während safe-area-inset-top kleiner wird.
Für Fixed-Elemente wie Navigationsbars, FABs (Floating Action Buttons) und Bottom-Navigation-Bars sind diese Werte kritisch. Ein Fixed-Header muss padding-top: env(safe-area-inset-top) haben, damit der Text nicht unter die Notch ragt. Eine Bottom-Bar muss padding-bottom: env(safe-area-inset-bottom) setzen, damit der Inhalt über dem Home-Indicator-Bereich bleibt. Ohne diese Anpassungen werden interaktive Elemente durch Hardware-Overlays unzugänglich oder visuell verdeckt.
/* Fixed header respecting notch and status bar */
.site-header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
/* Combine existing padding with safe area inset */
padding-top: calc(1rem + env(safe-area-inset-top, 0px));
padding-left: calc(1.5rem + env(safe-area-inset-left, 0px));
padding-right: calc(1.5rem + env(safe-area-inset-right, 0px));
background: white;
border-bottom: 1px solid rgb(226 232 240);
}
/* Bottom navigation bar — above home indicator */
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding-bottom: env(safe-area-inset-bottom, 0px);
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
background: white;
border-top: 1px solid rgb(226 232 240);
}
/* Floating action button — safe from all notch areas */
.fab {
position: fixed;
bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
right: calc(1.5rem + env(safe-area-inset-right, 0px));
}
5. env() mit calc() kombinieren
Die Kombination von CSS env() mit calc() ist das Herzstück einer korrekten Safe-Area-Implementierung. Selten ist es richtig, einfach padding: env(safe-area-inset-top) zu setzen — meistens braucht ein Element eigenes Padding, zu dem der Safe-Area-Inset noch addiert werden muss. Das Muster calc(1rem + env(safe-area-inset-bottom, 0px)) addiert 16 Pixel eigenes Padding zum Inset-Wert. Der Fallback-Wert 0px in env() ist dabei wichtig: Auf Geräten ohne Safe-Area-Unterstützung gibt env() ohne Fallback einen ungültigen Wert zurück, was die ganze calc()-Berechnung ungültig macht.
Ein weiteres nützliches Muster: CSS Custom Properties als Zwischenlayer für Safe-Area-Werte. Indem man die env()-Werte in Custom Properties schreibt, lassen sie sich flexibel in Komponenten nutzen ohne safe-area-inset überall direkt zu referenzieren. Dieses Muster ist besonders in Design-System-Kontexten und Tailwind-basierten Projekten hilfreich, wo man die Werte als Token verwenden möchte.
/* CSS custom properties as safe-area tokens */
:root {
--sat: env(safe-area-inset-top, 0px);
--sar: env(safe-area-inset-right, 0px);
--sab: env(safe-area-inset-bottom, 0px);
--sal: env(safe-area-inset-left, 0px);
}
/* Use tokens in components */
.page-content {
/* Content starts below header + notch */
padding-top: calc(var(--header-height, 4rem) + var(--sat));
/* Content above bottom nav + home indicator */
padding-bottom: calc(var(--bottom-nav-height, 4rem) + var(--sab));
/* Side padding respects landscape notch */
padding-left: max(1.5rem, calc(1.5rem + var(--sal)));
padding-right: max(1.5rem, calc(1.5rem + var(--sar)));
}
/* Scrollable content with safe area at bottom */
.scroll-container {
overflow-y: auto;
/* Reserve space at the bottom for safe area within scroll */
scroll-padding-bottom: var(--sab);
}
/* Safe padding shorthand using CSS logical properties */
.card-full-bleed {
padding: var(--sat) var(--sar) var(--sab) var(--sal);
}
6. PWA-Vollbild und standalone-Modus
Progressive Web Apps im standalone-Modus verhalten sich wie native Apps — sie haben keine Browser-Chrome, keine Adressleiste und nutzen den gesamten Bildschirm. In diesem Modus werden CSS safe-area-inset-* Variablen besonders wichtig, weil der Browser keinen automatischen Rand mehr einfügt. Ohne korrekte Inset-Handhabung ragt der Inhalt der PWA direkt in die Notch oder unter den Home-Indicator-Bereich.
Das Web-App-Manifest muss "display": "standalone" oder "display": "fullscreen" setzen. Im fullscreen-Modus ist viewport-fit=cover implizit aktiv, und safe-area-inset-* liefert korrekte Werte. Im standalone-Modus ist es ebenfalls aktiv, aber die Browser-Statusbar kann je nach Gerät noch sichtbar sein. Die CSS Media Query @media (display-mode: standalone) erlaubt es, Safe-Area-Styles nur im PWA-Modus anzuwenden und für Browser-Darstellung andere Werte zu verwenden.
7. Dynamic Island und neuere iPhone-Modelle
Das Dynamic Island, eingeführt mit dem iPhone 14 Pro, ist technisch gesehen eine Software-Erweiterung der physischen Hardware-Aussparung für die Frontkamera. Aus CSS-Perspektive verhält es sich ähnlich wie die Notch: safe-area-inset-top hat einen Wert, der sicherstellt, dass Inhalte nicht hinter das Dynamic Island ragen. Der konkrete Pixelwert ist auf diesen Geräten etwas größer als auf Notch-iPhones, aber das Implementierungsprinzip bleibt identisch.
Ein wichtiger Aspekt: Das Dynamic Island ist interaktiv und kann sich ausdehnen, wenn Systemfunktionen wie Timer, Anrufe oder Live Activities aktiv sind. In diesem Zustand nimmt es mehr Platz ein, und der Safe-Area-Inset-Wert wird entsprechend größer. Da CSS env() dynamisch aktualisiert wird, passt sich ein korrekt implementiertes Layout automatisch an — ohne zusätzlichen Code. Das ist ein erheblicher Vorteil gegenüber hardcodierten Pixelwerten oder JavaScript-basierter Erkennung.
8. Safe Area Insets im Vergleich
Verschiedene Ansätze zur Handhabung von Notch und Dynamic Island haben unterschiedliche Vor- und Nachteile. Die folgende Tabelle vergleicht die wichtigsten Methoden.
| Ansatz | Dynamisch | Geräteunabhängig | Empfehlung |
|---|---|---|---|
| CSS env() safe-area-inset-* | Ja | Ja | Primäre Lösung — Standard |
| Feste Pixel-Margins | Nein | Nein | Nicht empfohlen — bricht bei neuen Modellen |
| JS window.screen Detection | Begrenzt | Begrenzt | Letzter Ausweg für Legacy-Code |
| viewport-fit=auto (Standard) | – | Ja | Wenn kein Vollbild-Layout benötigt |
| Native App WebView | Ja | Ja | Wie Browser — env() funktioniert identisch |
Der Vollständigkeit halber: CSS env() ist nicht auf safe-area-inset-* beschränkt. Die Spezifikation definiert weitere Variablen wie keyboard-inset-* (für die virtuelle Tastatur), die in modernen Browsern verfügbar sind. Die Grundlage bleibt dieselbe: viewport-fit=cover aktivieren und dann mit env() und calc() arbeiten.
9. Tailwind CSS Integration
In Tailwind-basierten Projekten lassen sich CSS safe-area-inset-* Werte über Custom Theme Extensions zugänglich machen. In Tailwind CSS v4 mit dem CSS-first-Approach definiert man die Utility-Klassen direkt in CSS. Das Muster ist, env(safe-area-inset-*) als Custom Property in :root zu setzen und dann über CSS-Variablen in Tailwind-Utilities zu verwenden. Alternativ bieten viele Tailwind-Plugins wie tailwind-safe-area fertige Utility-Klassen für Safe-Area-Padding.
In Hyvä Themes-Projekten mit Tailwind CSS v4 ist der empfohlene Weg, die Safe-Area-Tokens in der globalen CSS-Datei zu deklarieren und dann im Template-Code mit Inline-Styles oder Custom-Utility-Klassen zu kombinieren. Da Hyvä Alpine.js verwendet, lassen sich die Safe-Area-Werte auch reaktiv per JavaScript lesen und als Alpine-Daten bereitstellen — was für komplexe Layout-Berechnungen hilfreich ist, aber für einfache Padding-Anwendungen unnötig komplex ist.
/* Tailwind v4 CSS-first safe area utilities */
@layer utilities {
.pt-safe {
padding-top: env(safe-area-inset-top, 0px);
}
.pr-safe {
padding-right: env(safe-area-inset-right, 0px);
}
.pb-safe {
padding-bottom: env(safe-area-inset-bottom, 0px);
}
.pl-safe {
padding-left: env(safe-area-inset-left, 0px);
}
.p-safe {
padding-top: env(safe-area-inset-top, 0px);
padding-right: env(safe-area-inset-right, 0px);
padding-bottom: env(safe-area-inset-bottom, 0px);
padding-left: env(safe-area-inset-left, 0px);
}
/* Additive: combine with existing padding */
.pb-safe-4 {
padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
}
.pb-safe-6 {
padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
}
}
/* Media query: apply only in standalone PWA mode */
@media (display-mode: standalone) {
.pwa-header {
padding-top: env(safe-area-inset-top, 0px);
}
}
Mironsoft
Mobile-first CSS, PWA-Entwicklung und iOS-Layout-Optimierung
Layouts, die auf iPhone Notch und Dynamic Island korrekt funktionieren?
Wir implementieren korrekte Safe-Area-Handhabung für Webseiten und PWAs — von viewport-fit=cover über env()-Integration bis zu Tailwind-Utility-Klassen für alle vier Inset-Richtungen.
iOS-Audit
Prüfung aller Fixed-Elemente auf korrekte Safe-Area-Behandlung auf aktuellen iPhone-Modellen
PWA-Optimierung
Vollbild-PWA mit korrekten Safe-Area-Insets im standalone- und fullscreen-Modus
CSS-System
Tailwind-Utilities und CSS-Token für Safe-Area-Werte im Design-System verankern
10. Zusammenfassung
CSS env() mit den safe-area-inset-* Umgebungsvariablen ist die standardisierte und empfohlene Methode, um Layouts auf Geräten mit Notch, Dynamic Island und gerundeten Displayecken korrekt darzustellen. Die Implementierung folgt einem klaren Schema: viewport-fit=cover im Viewport-Meta-Tag aktivieren, dann safe-area-inset-top, -right, -bottom und -left mit env() lesen und in calc()-Ausdrücken mit eigenem Padding kombinieren. Fallbacks in env(variablenname, 0px) sichern Geräte ohne Safe-Area-Unterstützung ab.
Besondere Aufmerksamkeit verdienen Fixed-Elemente wie Headers, Bottom-Navigation und Floating-Action-Buttons, da diese am direktesten von Notch und Dynamic Island betroffen sind. Für PWAs im standalone-Modus ist korrekte Safe-Area-Implementierung nicht optional, sondern notwendig für eine native App-Qualität. Die Kombination von CSS env() mit CSS Custom Properties als Zwischenlayer und optionaler Tailwind-Utility-Erweiterung ergibt ein wartbares, geräteübergreifendes System.
CSS env() und Safe Area Insets — Das Wichtigste auf einen Blick
Voraussetzung
viewport-fit=cover im Meta-Tag aktivieren. Ohne das sind alle safe-area-inset-* Werte immer 0.
Vier Richtungen
safe-area-inset-top, -right, -bottom, -left. Orientierungsabhängig — im Querformat andere Werte als im Hochformat.
calc() Kombination
calc(1rem + env(safe-area-inset-bottom, 0px)) — eigenes Padding + Inset. Fallback 0px in env() ist Pflicht.
Dynamic Island
Verhält sich wie Notch für CSS. safe-area-inset-top passt sich automatisch an, auch wenn Dynamic Island ausgedehnt ist.