The CSS env() function lets you access browser-defined environment variables in your stylesheets. Here are the real-world problems it solves.
Responsive Safe Footer (iPhone Notch & Home Indicator)
<!-- Enable safe area support -->
<meta name="viewport" content="viewport-fit=cover" />
.footer {
position: fixed;
bottom: 0;
width: 100%;
/* Base padding */
padding: 16px;
/* Add safe area when needed */
padding-bottom: calc(16px + env(safe-area-inset-bottom, 0));
/* Add keyboard space on mobile */
transform: translateY(calc(-1 * env(keyboard-inset-bottom, 0)));
}
Full-Screen Modal
.modal {
position: fixed;
inset: 0;
/* Respect all safe areas */
padding: env(safe-area-inset-top, 0) env(safe-area-inset-right, 0) env(safe-area-inset-bottom, 0)
env(safe-area-inset-left, 0);
}
PWA App Bar (Desktop Title Bar)
// manifest.json - Enable Window Controls Overlay
{
"display_override": ["window-controls-overlay"]
}
.app-bar {
position: fixed;
top: 0;
/* Desktop: use title bar area */
left: env(titlebar-area-x, 0);
width: env(titlebar-area-width, 100%);
height: env(titlebar-area-height, 64px);
/* Mobile: respect notch */
padding-top: env(safe-area-inset-top, 0);
}
main {
/* Avoid overlap with title bar */
margin-top: env(titlebar-area-height, 64px);
}
Foldable-Aware Grid (Surface Duo, Galaxy Fold)
Viewport segment indices:
Horizontal layout:
[0 0] [1 0]
Vertical layout:
[0 0]
[0 1]
.grid {
display: grid;
/* Default: single column for all standard devices */
grid-template-columns: 1fr;
}
/* Other media queries for large screens go here */
/* Detect dual-screen foldable devices and use both segments */
@media (horizontal-viewport-segments: 2) {
.grid {
grid-template-columns:
env(viewport-segment-width 0 0)
env(viewport-segment-width 1 0);
}
/* Avoid placing important content in the hinge area */
.important-content {
margin-left: env(viewport-segment-width 0 0);
width: env(viewport-segment-width 1 0);
}
}
Chat App with Virtual Keyboard
.chat-container {
display: grid;
grid-template-rows: 1fr auto env(keyboard-inset-bottom, 0);
height: 100dvh;
}
.message-list {
overflow-y: auto;
}
.input-area {
height: var(--input-area-height);
}
Gotchas & Best Practices
1. Variable Names Are Case-Sensitive
/* ✅ Correct */
padding-left: env(safe-area-inset-left);
/* ❌ Wrong - won't work! */
padding-left: env(SAFE-AREA-INSET-LEFT);
2. Always Provide Fallbacks
For browsers that don’t support the variable
/* ✅ Good - works everywhere */
padding-top: env(safe-area-inset-top, 20px);
/* ⚠️ Risky - no padding on unsupported browsers */
padding-top: env(safe-area-inset-top);
3. Use calc() for Combinations
/* Combine with existing values */
height: calc(100vh - 60px - env(keyboard-inset-height, 0));
padding-bottom: calc(1em + env(safe-area-inset-bottom, 0));
4. CSS Custom Properties Bridge
:root {
--safe-bottom: env(safe-area-inset-bottom, 0);
}
/* Use throughout your CSS */
.element {
margin-bottom: var(--safe-bottom);
}
5. Feature Detection (unnecessary since it’s widely supported)
@supports (padding: env(safe-area-inset-top)) {
/* Styles for browsers that support env() */
body {
padding-top: env(safe-area-inset-top);
}
}
Browser Support Summary For env() Variables
| Variable | Chromium-based | Safari | Firefox |
|---|---|---|---|
safe-area-inset-* | ✅ | 11+ | 65+ |
keyboard-inset-* | ✅ | ❌ | ❌ |
titlebar-area-* | ✅ | ❌ | ❌ |
viewport-segment-* | ✅ | ❌ | ❌ |
When Should You Use env()?
Use env() when:
- Building mobile-first web apps
- Creating PWAs for desktop
- Supporting notched devices (iPhone X+)
- Building apps for foldable devices
- Dealing with virtual keyboards
Don’t use env() for:
- User preferences, theme values (use CSS custom properties)
- Responsive breakpoints (use media queries)