~ 3 min read

CSS env() Function: Real-World Use Cases for Modern Devices


The CSS env() function lets you access browser-defined environment variables in your stylesheets. Here are the real-world problems it solves.

<!-- 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

VariableChromium-basedSafariFirefox
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)

Resources


Headshot of Nam Le

Hi, I'm Nam Le. I'm a software engineer based in HCM city, Vietnam. You can follow me on Twitter, see some of my work on GitHub, or connect with me on LinkedIn.