CSS Environment Variables: env() for Device-Safe Layouts
env() gives you access to environment-defined values set by the browser or operating system — most importantly, the safe area insets that account for device notches, home indicators, and rounded screen corners on modern phones.
1. What env() Is
/* env(variable-name, fallback) */
/* Similar to var() but reads BROWSER/OS values, not CSS custom properties */
padding-bottom: env(safe-area-inset-bottom, 20px);
/* → On iPhone with home indicator: real safe area value (often 34px)
→ On desktop/Android: 20px fallback */
env() vs var():
var(--my-property) → CSS custom property you define in :root
env(safe-area-inset-*) → Browser defines this based on device hardware
2. The Safe Area Insets
These are the most important env() variables — essential for mobile web apps:
/* The four safe area insets */
env(safe-area-inset-top) /* Notch/Dynamic Island area */
env(safe-area-inset-right) /* Right edge (landscape notch) */
env(safe-area-inset-bottom) /* Home indicator (iPhone X+) */
env(safe-area-inset-left) /* Left edge (landscape notch) */
iPhone 15 Pro in portrait:
inset-top: 59px (Dynamic Island)
inset-right: 0px
inset-bottom: 34px (Home indicator swipe area)
inset-left: 0px
iPhone 15 Pro in landscape:
inset-top: 0px
inset-right: 59px (Notch side)
inset-bottom: 21px
inset-left: 0px (or 59px on the other side)
3. Enabling Safe Area Support
Critical step: you must add viewport-fit=cover to your viewport meta tag to access env() safe areas:
<!-- Required: viewport-fit=cover enables edge-to-edge + env() values -->
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<!-- Without viewport-fit=cover: browser automatically avoids the notch -->
<!-- (env() values will be 0 — device handles it for you) -->
<!-- With viewport-fit=cover: YOUR CSS must handle the notch/home indicator -->
4. Practical Implementation
Fixed Navigation Bar
/* Navigation that avoids the notch and Dynamic Island */
.c-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: var(--z-nav);
/* Add safe area to the nav's own height */
padding-top: env(safe-area-inset-top, 0px);
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
height: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
}
Bottom Tab Bar (Mobile App Style)
/* Mobile bottom navigation — common in PWAs */
.c-tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
/* Add inset-bottom so bar doesn't hide behind home indicator */
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: var(--color-surface);
border-top: 1px solid var(--color-border);
}
Full-Screen Hero (PWA / Web App)
/* Hero that fills the entire screen including notch area */
.c-hero-fullscreen {
min-height: 100dvh;
/* Content padding respects safe areas */
padding-top: max(2rem, env(safe-area-inset-top));
padding-bottom: max(2rem, env(safe-area-inset-bottom));
padding-left: max(1rem, env(safe-area-inset-left));
padding-right: max(1rem, env(safe-area-inset-right));
}
Using max() with env()
/* max(minimum-padding, safe-area-value) */
/* Ensures: at least 1rem of padding, more if safe area requires it */
.c-main-content {
padding-inline: max(1.5rem, env(safe-area-inset-left),
env(safe-area-inset-right));
padding-bottom: max(2rem, env(safe-area-inset-bottom));
}
5. env() in WordPress
/* child theme style.css — safe area support for mobile */
/* Sticky header */
.site-header {
position: sticky;
top: 0;
/* If using viewport-fit=cover on mobile: */
padding-top: env(safe-area-inset-top, 0);
}
/* Footer — above home indicator */
.site-footer {
padding-bottom: max(2rem, calc(env(safe-area-inset-bottom, 0px) + 1rem));
}
/* Full-width page: prevent content hiding behind notch */
.entry-content {
padding-inline: max(1.5rem, env(safe-area-inset-left, 0px));
}
6. Other env() Variables
Beyond safe areas, there are additional environment variables:
/* Keyboard-visible height (experimental — CSS Viewport level 4) */
height: env(keyboard-inset-height, 0px);
/* Adjusts layout when the virtual keyboard is visible */
/* titlebar-area: for installed PWAs / desktop apps */
.c-titlebar {
position: fixed;
top: env(titlebar-area-y, 0);
left: env(titlebar-area-x, 0);
width: env(titlebar-area-width, 100%);
height: env(titlebar-area-height, 0);
}
/* Note: titlebar-* vars are only available when the app is installed as PWA */
7. Browser Support
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
env() basic | ✅ 69+ | ✅ 65+ | ✅ 11.1+ | ✅ 79+ |
| safe-area-inset-* | ✅ 69+ | ✅ 65+ | ✅ 11.1+ | ✅ 79+ |
| keyboard-inset-* | ⚠ Partial | ❌ | ❌ | ⚠ |
8. Debugging Safe Areas
/* Debug mode: make safe areas visible */
:root {
--debug-safe-top: env(safe-area-inset-top, 0px);
--debug-safe-bottom: env(safe-area-inset-bottom, 0px);
}
body::before {
content: 'safe-top: ' var(--debug-safe-top) ' | safe-bottom: ' var(--debug-safe-bottom);
/* Note: content can't read CSS variables for display — use JS for debugging */
}
/* JS debug alternative: */
/* const style = getComputedStyle(document.documentElement);
console.log(style.getPropertyValue('--debug-safe-top')); */
Chrome DevTools — simulating safe areas:
1. DevTools → Toggle Device Toolbar (Ctrl+Shift+M)
2. Select iPhone 14 Pro or similar
3. Open "…" menu → Select "Show device frame"
4. Rotate to landscape to see inset-left values
5. Or: DevTools → Console → type:
document.documentElement.style.setProperty('--sat', '59px')
9. Quick Reference
| Variable | Value | Use For |
|---|---|---|
env(safe-area-inset-top) | Notch/Dynamic Island height | Fixed nav top padding |
env(safe-area-inset-right) | Landscape right notch | Padding on right side |
env(safe-area-inset-bottom) | Home indicator height | Fixed tab bar, footer |
env(safe-area-inset-left) | Landscape left notch | Padding on left side |
Fallback without viewport-fit | Always 0px | Desktop/non-notch devices |