Skip to main content

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

FeatureChromeFirefoxSafariEdge
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

VariableValueUse For
env(safe-area-inset-top)Notch/Dynamic Island heightFixed nav top padding
env(safe-area-inset-right)Landscape right notchPadding on right side
env(safe-area-inset-bottom)Home indicator heightFixed tab bar, footer
env(safe-area-inset-left)Landscape left notchPadding on left side
Fallback without viewport-fitAlways 0pxDesktop/non-notch devices