Skip to main content
Mohammad Shehadeh — home (MSH monogram, letter M filled with the Palestinian flag)

Understanding env() Safe Area Insets in CSS

Published on
10 min read

Modern devices have notches, rounded corners, home indicators, and dynamic islands that can hide your content. The CSS env() function with safe area insets makes your layouts adapt to these hardware features automatically.

The Problem: Hardware Intrusions

The iPhone X introduced the notch in 2017, creating a new challenge for web developers. Content that looked perfect on rectangular screens suddenly hid behind hardware features. Today, this problem covers:

  • Notches and Dynamic Islands (iPhone, many Android devices)
  • Rounded display corners (most modern smartphones)
  • Home indicators (gesture-based navigation bars)
  • Camera punch-holes (Samsung, Google Pixel)
Why This Matters

Without safe area handling, fixed headers hide behind notches and bottom navigation conflicts with home indicators, making parts of your app unusable.

Enabling Safe Area Insets

By default, browsers letterbox your content to avoid hardware intrusions. To use the full screen and handle safe areas yourself, add the viewport-fit meta tag:

index.html
1<meta
2  name="viewport"
3  content="width=device-width, initial-scale=1, viewport-fit=cover"
4/>

The viewport-fit property accepts three values:

ValueBehavior
autoDefault letterboxing, content stays in safe area
containSame as auto, explicit safe area containment
coverContent extends to full screen, you handle safe areas
Important

Setting viewport-fit=cover without handling safe areas hides content behind hardware features. Always combine it with env() insets.

The env() Function

The env() function reads environment variables set by the user agent. For safe areas, browsers provide four variables:

style.css
1/* Safe area environment variables */
2env(safe-area-inset-top)    /* Top edge (notch, status bar) */
3env(safe-area-inset-right)  /* Right edge (curved corners) */
4env(safe-area-inset-bottom) /* Bottom edge (home indicator) */
5env(safe-area-inset-left)   /* Left edge (curved corners) */

These values are dynamic and change based on:

  • Device orientation (portrait vs landscape)
  • Device hardware (notch position, corner radius)
  • Browser chrome visibility (address bar, toolbars)

Practical Examples

Fixed Header with Safe Area

A common pattern is a fixed header that accounts for the top safe area.

header.css
1.header {
2  position: fixed;
3  top: 0;
4  left: 0;
5  right: 0;
6
7  /* Add safe area to existing padding */
8  padding-top: calc(1rem + env(safe-area-inset-top));
9  padding-left: calc(1rem + env(safe-area-inset-left));
10  padding-right: calc(1rem + env(safe-area-inset-right));
11
12  background: white;
13}

Try It: Fixed Header

This sandbox simulates a device with a notch using CSS custom properties. Toggle the "notch" to see how env() adapts the layout.

Preview

Bottom Navigation Bar

For bottom-fixed navigation, account for the home indicator.

nav.css
1.bottom-nav {
2  position: fixed;
3  bottom: 0;
4  left: 0;
5  right: 0;
6
7  /* Ensure nav clears the home indicator */
8  padding-bottom: env(safe-area-inset-bottom);
9  padding-left: env(safe-area-inset-left);
10  padding-right: env(safe-area-inset-right);
11
12  background: white;
13}

Try It: Bottom Navigation

See how the bottom navigation adapts when the home indicator is present.

Preview

Full-Screen Hero Section

For immersive hero sections that extend edge-to-edge.

hero.css
1.hero {
2  min-height: 100vh;
3  min-height: 100dvh; /* Dynamic viewport height */
4
5  /* Content padding respects all safe areas */
6  padding:
7      calc(2rem + env(safe-area-inset-top))
8      calc(1.5rem + env(safe-area-inset-right))
9      calc(2rem + env(safe-area-inset-bottom))
10      calc(1.5rem + env(safe-area-inset-left));
11}

Try It: Complete App Layout

A full example combining header, content, and bottom navigation with all safe area insets.

Preview

Fallback Values

The env() function takes a fallback value for browsers that don't support safe area insets or devices without hardware intrusions.

fallback.css
1.element {
2  /* Fallback to 0px if env() is not supported */
3  padding-top: env(safe-area-inset-top, 0px);
4
5  /* Fallback to a default value */
6  padding-bottom: env(safe-area-inset-bottom, 1rem);
7
8  /* Use in calculations */
9  margin-top: calc(20px + env(safe-area-inset-top, 0px));
10}
Note

On devices without notches, or when viewport-fit isn't set to cover, safe area inset values resolve to 0px.

Using with CSS Custom Properties

Combine env() with CSS custom properties for more maintainable code.

variables.css
1:root {
2  --safe-top: env(safe-area-inset-top, 0px);
3  --safe-right: env(safe-area-inset-right, 0px);
4  --safe-bottom: env(safe-area-inset-bottom, 0px);
5  --safe-left: env(safe-area-inset-left, 0px);
6
7  --header-height: calc(60px + var(--safe-top));
8  --nav-height: calc(56px + var(--safe-bottom));
9}
10
11.header {
12  height: var(--header-height);
13  padding-top: var(--safe-top);
14}
15
16.main {
17  padding-top: var(--header-height);
18  padding-bottom: var(--nav-height);
19}
20
21.bottom-nav {
22  height: var(--nav-height);
23  padding-bottom: var(--safe-bottom);
24}

Tailwind CSS Integration

If you use Tailwind CSS, extend your config to add safe area utilities.

tailwind.config.js
1export default {
2  theme: {
3      extend: {
4          padding: {
5              'safe-top': 'env(safe-area-inset-top)',
6              'safe-right': 'env(safe-area-inset-right)',
7              'safe-bottom': 'env(safe-area-inset-bottom)',
8              'safe-left': 'env(safe-area-inset-left)',
9          },
10          margin: {
11              'safe-top': 'env(safe-area-inset-top)',
12              'safe-bottom': 'env(safe-area-inset-bottom)',
13          },
14      },
15  },
16};

Then use them in your markup.

component.html
1<header class="fixed top-0 inset-x-0 pt-safe-top px-safe-left">
2  <!-- Header content -->
3</header>
4
5<nav class="fixed bottom-0 inset-x-0 pb-safe-bottom">
6  <!-- Navigation content -->
7</nav>

Landscape Orientation

Safe area insets matter most in landscape mode, where notches appear on the left or right side.

landscape.css
1/* Handle landscape orientation */
2@media (orientation: landscape) {
3  .sidebar {
4      /* Account for notch on left side */
5      padding-left: calc(1rem + env(safe-area-inset-left));
6  }
7
8  .content {
9      /* Account for potential notch on right */
10      padding-right: calc(1rem + env(safe-area-inset-right));
11  }
12}

Try It: Landscape Orientation

In landscape mode, the notch shifts to the side. Toggle to see the difference.

Preview

Browser Support

The env() function and safe area insets have excellent browser support.

BrowserSupport
Chrome69+
Firefox65+
Safari11.1+
Edge79+
iOS Safari11.2+
Chrome Android69+
Good News

All modern browsers support env() and safe area insets. Just provide fallback values for older browsers or non-notched devices.

Common Pitfalls

Forgetting viewport-fit

Safe area insets only work when viewport-fit=cover is set.

index.html
1<!-- This won't work - missing viewport-fit -->
2<meta name="viewport" content="width=device-width, initial-scale=1">
3
4<!-- This works -->
5<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">

Using env() in Unsupported Contexts

The env() function works in property values but not in media queries.

example.css
1/* This works */
2.element {
3  padding-top: env(safe-area-inset-top);
4}
5
6/* This does NOT work */
7@media (min-height: env(safe-area-inset-top)) {
8  /* Media queries don't support env() */
9}

Doubling Up Safe Areas

When nesting elements, don't apply safe area padding more than once.

nesting.css
1/* Parent already has safe area padding */
2.app-shell {
3  padding-top: env(safe-area-inset-top);
4}
5
6/* Don't add it again to children */
7.header {
8  /* This would double the spacing */
9  /* padding-top: env(safe-area-inset-top); */
10
11  /* Just use regular padding */
12  padding-top: 1rem;
13}

Summary

The env() function with safe area insets is essential for modern mobile web development:

  1. Enable full-screen mode with viewport-fit=cover
  2. Use env() variables for top, right, bottom, and left insets
  3. Provide fallbacks for older browsers and standard displays
  4. Combine with calc() to add safe areas to existing spacing
  5. Test in landscape where notches shift position

Handle safe areas well, and your web apps will feel native and professional across all modern devices.

References

Related Articles

GET IN TOUCH

Let's work together

I build fast, accessible, and delightful digital experiences for the web. Whether you have a project in mind or just want to connect, I'd love to hear from you.

Get in touch

or reach out directly at hello@mohammadshehadeh.com