Missing Safe Area Insets
Hanging a painting behind a pillar — that's what happens when your content hides behind the iPhone notch and Dynamic Island.
What is this?
Imagine carefully hanging a beautiful painting on a wall, only to realize there is a pillar right in front of it blocking the view. That is what happens when your website content gets hidden behind the iPhone notch, Dynamic Island, home indicator bar, or the rounded corners on modern phones. These physical features eat into your screen real estate, and if you do not account for them, your content (buttons, text, navigation) disappears behind them.
Why it matters
- For your visitors: A button hidden behind the home indicator bar is a button that cannot be tapped. Text behind the notch is text that cannot be read. On full-screen web apps (added to the home screen or running in standalone mode), this is especially bad — there is no browser chrome to push content into the safe area automatically. Visitors see a broken, unprofessional experience.
- For your business: iPhones account for a significant share of mobile web traffic (over 50% in many markets). If your page looks broken on every iPhone made since 2017, you are alienating a huge chunk of your audience. This is especially critical for sticky headers, fixed bottom bars, and full-width layouts.
- The standard: Use
env(safe-area-inset-*)CSS environment variables to pad content away from device hardware features. Apple introducedviewport-fit=coverand safe area insets specifically for this purpose. All modern browsers on notched/island devices support them.
<meta name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover" />
<style>
body {
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);
}
</style><meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- No safe area handling — content goes behind notch and home bar -->
<style>
.fixed-header { position: fixed; top: 0; }
.fixed-footer { position: fixed; bottom: 0; }
</style>How to fix it
React / Next.js
First, add viewport-fit=cover to your viewport configuration so your app extends edge-to-edge. Then use safe area insets to keep content visible.
// src/app/layout.tsx
import type { Viewport } from "next";
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
viewportFit: "cover", // enables safe area insets
};Then apply safe area padding in your global styles or on fixed elements:
/* globals.css — pad the body for safe areas */
body {
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom)
env(safe-area-inset-left);
}
/* Fixed header: account for the notch/Dynamic Island */
.site-header {
position: fixed;
top: 0;
left: 0;
right: 0;
padding-top: env(safe-area-inset-top);
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
/* Fixed bottom bar: account for home indicator */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding-bottom: env(safe-area-inset-bottom);
}With Tailwind CSS, you can use arbitrary values:
function BottomNav() {
return (
<nav className="fixed bottom-0 left-0 right-0 bg-neutral-950 pb-[env(safe-area-inset-bottom)] pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]">
<div className="flex justify-around p-2">
<a href="/">Home</a>
<a href="/search">Search</a>
<a href="/profile">Profile</a>
</div>
</nav>
);
}Plain HTML
Add viewport-fit=cover to your viewport tag and use CSS environment variables.
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<style>
/* Use safe area insets with fallbacks for older browsers */
.page-wrapper {
padding-top: max(1rem, env(safe-area-inset-top));
padding-bottom: max(1rem, env(safe-area-inset-bottom));
padding-left: max(1rem, env(safe-area-inset-left));
padding-right: max(1rem, env(safe-area-inset-right));
}
/* Fixed elements need their own safe area handling */
.sticky-cta {
position: fixed;
bottom: 0;
width: 100%;
padding: 16px;
padding-bottom: calc(16px + env(safe-area-inset-bottom));
}
</style>If you have fixed headers, footers, or full-screen layouts, safe area insets are essential. The cat does not appreciate its content being covered up by hardware.
How the cat scores this
The scanner checks pages with fixed or sticky positioned elements (headers, footers, bottom bars) and verifies whether safe area inset values are applied. It looks for viewport-fit=cover in the viewport meta tag and env(safe-area-inset-*) in the CSS. Pages without fixed elements are not penalized — safe area insets only matter when content is positioned near the screen edges. The severity is higher for fixed bottom bars (home indicator overlap) than top elements.
Further reading
- WebKit: Designing for iPhone X — Apple's original guide to safe areas
- MDN: env() CSS function — reference for safe area environment variables
- web.dev: CSS env() — practical guide to CSS environment variables