usability.cat
Issue Wiki

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 introduced viewport-fit=cover and safe area insets specifically for this purpose. All modern browsers on notched/island devices support them.
Safe area respected
<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>
Content behind the notch
<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>
Medium impactmobile~1 paw

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

On this page