Skip to content
1440px

Safe Areas in Practice

Two lines of CSS and one meta tag. The failures all come from skipping the meta tag or hard-coding the number.

Short answer
env() + viewport-fit

Add viewport-fit=cover to the viewport meta tag, then pad with env(safe-area-inset-*). Without the meta tag the env() values are all zero and nothing happens — that is the bug people spend an afternoon on.

The whole mechanism
<!-- Without this, every env() value below is 0 -->
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
Padding that adapts to the device
.app {
  padding-top:    env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left:   env(safe-area-inset-left);
  padding-right:  env(safe-area-inset-right);
}

/* Keep your own spacing AND clear the system UI */
.toolbar {
  padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
}

The second argument to env() is a fallback for browsers that do not know the variable. Use it — env(safe-area-inset-bottom, 0px) inside a calc() is the difference between working everywhere and collapsing to nothing on a desktop browser.

The values, and why you should not type them

The insets below are real and stable per display geometry. They are here so you can sanity-check a layout, not so you can paste 34px into a stylesheet — a device released next year with a different notch will make that number wrong, silently.

Portrait safe-area insets by display geometry
TopBottomGeometryDevicesExamples
62 px34 pxDynamic Island, iPhone Air1iPhone Air
62 px34 pxDynamic Island, 6.9″ class2iPhone 17 Pro Max, iPhone 16 Pro Max
62 px34 pxDynamic Island, 6.3″ class3iPhone 17 Pro, iPhone 17, iPhone 16 Pro
59 px34 pxDynamic Island8iPhone 16 Plus, iPhone 16, iPhone 15 Pro Max
48 px34 pxNotch4iPhone 11 Pro Max, iPhone 11, iPhone XR
47 px34 pxNotch10iPhone 17e, iPhone 16e, iPhone 14 Plus
44 px34 pxNotch5iPhone 13 mini, iPhone 12 mini, iPhone 11 Pro
24 px20 pxiPad Pro 13″, home indicator2iPad Pro 13″ (M5), iPad Pro 13″ (M4)
24 px20 pxiPad Pro 11″, home indicator6iPad Pro 11″ (M5), iPad Pro 11″ (M4), iPad Pro 11″ (4th gen)
24 px20 pxiPad 13″, home indicator7iPad Air 13″ (M4), iPad Air 13″ (M3), iPad Air 13″ (M2)
24 px20 pxiPad, home indicator7iPad Air 11″ (M4), iPad Air 11″ (M3), iPad Air 11″ (M2)
24 px20 pxiPad mini, home indicator2iPad mini (7th gen), iPad mini (6th gen)
20 px0 pxHome button, status bar only16iPhone SE (3rd gen), iPhone SE (2nd gen), iPhone SE (1st gen)

The four failures

1. Forgetting viewport-fit=cover

Without it the browser lays out inside the safe area already, all four env() values report 0, and your carefully written padding does nothing. This is the most common cause of "env() does not work".

2. Hard-coding 44px or 34px

Those numbers are correct for one class of device. They are wrong on a home-button iPhone (0 at the bottom), wrong on an iPad (20), and wrong on desktop (0), where you have just added dead space for no reason.

3. Ignoring landscape

In landscape the notch moves to a side, so safe-area-inset-left or -right becomes non-zero — typically 44–48px — while the top inset drops. A layout that only pads top and bottom puts content underneath the notch as soon as the phone is rotated. Pad all four sides, always.

4. Using 100vh for a full-height layout

100vh on mobile is the height with the browser chrome hidden, so a full-height element is taller than the visible area until the user scrolls. The viewport units that fix it:

Mobile viewport height units
UnitMeansUse for
svhSmall viewport height — chrome fully shownAnything that must be fully visible on load. The safe default.
lvhLarge viewport height — chrome fully hiddenRarely what you want. Equivalent to the old vh behaviour.
dvhDynamic — follows the chrome as it movesFull-screen app shells. Note it reflows as the user scrolls, which can look restless.

Combine them with the insets rather than choosing between them: min-height: 100svh for the shell, env() padding for the system UI inside it.

Questions

Do safe areas apply on Android?

Yes. Chrome on Android supports env(safe-area-inset-*) and returns non-zero values on devices with cutouts and gesture bars. The values differ from iOS, which is precisely the argument for using the variables instead of typing numbers.

What is the difference between the safe area and the status bar?

The status bar is one thing that occupies the top inset. The safe area is the union of everything the system reserves — status bar, notch or Dynamic Island, home indicator, rounded corners, and in landscape the camera housing.

Does env() work in a PWA installed to the home screen?

Yes, and it matters more there: a standalone PWA has no browser chrome to protect it, so the home indicator will sit on top of your bottom navigation unless you pad for it.

Can I read the safe area in JavaScript?

Not directly. Assign it to a custom property in CSS (--sat: env(safe-area-inset-top)) and read that with getComputedStyle.

Related

More guides

Written by the 1440px editorial team, last reviewed 7 August 2026. Numbers in the tables are computed from the device and framework data this site maintains, so a correction there propagates here. See methodology.