# Respect Safe Area Insets on Fixed Elements

**MUST** · **ID:** `layout-ibelick-safe-areas` · **Category:** layout
**Source:** [@Ibelick](https://www.ui-skills.com/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/layout-ibelick-safe-areas

> MUST: Respect safe-area-inset for fixed/sticky elements on notched devices. Use pb-safe, pt-safe or env(safe-area-inset-*) to prevent content obscuring.

Pad fixed elements with env(safe-area-inset-*) so they clear the notch and the home indicator

The scope is FIXED elements, and that is the whole point of the rule: normal document flow already stops short of the unsafe regions, so a paragraph does not need this. A `position: fixed` header, bottom bar, FAB or drawer is positioned against the viewport, which extends underneath the notch and the home indicator — so it, and only it, lands in hardware. Requires `viewport-fit=cover` in the viewport meta tag; without it the env() values all resolve to 0 and the rule silently does nothing. Write the padding as `padding-bottom: env(safe-area-inset-bottom)` (or, keeping the element's own padding, `calc(0.75rem + env(safe-area-inset-bottom))`), and note that `pb-safe` / `pt-safe` are NOT core Tailwind — they come from the tailwindcss-safe-area plugin or a hand-written `@utility`, and they do not exist in this project, so writing them here produces no CSS at all.

## Bad — do not do this

`layout-ibelick-safe-areas-bad`

```tsx
export function IbelickSafeAreasBad() {
  return (
    <div className="space-y-4">
      <div className="relative border rounded-[2rem] overflow-hidden bg-background" style={{ height: '280px' }}>
        {/* Simulated iPhone with notch */}
        <div className="absolute top-0 left-1/2 -translate-x-1/2 w-24 h-6 bg-black rounded-b-xl" />

        <div className="h-full flex flex-col">
          {/* Header behind notch */}
          <div className="bg-primary text-primary-foreground px-4 py-3 text-center">
            <span className="font-medium">App Header</span>
          </div>

          <div className="flex-1 p-4 text-sm text-muted-foreground">
            Content area...
          </div>

          {/* Footer behind home indicator */}
          <div className="bg-muted px-4 py-3 flex justify-around">
            <button className="text-xs">Home</button>
            <button className="text-xs">Search</button>
            <button className="text-xs">Profile</button>
          </div>
        </div>

        {/* Home indicator */}
        <div className="absolute bottom-1 left-1/2 -translate-x-1/2 w-24 h-1 bg-black rounded-full" />
      </div>
      <p className="text-xs text-destructive">
        Header text hidden behind notch, footer buttons behind home indicator
      </p>
    </div>
  );
}
```

## Good — do this

`layout-ibelick-safe-areas-good`

```tsx
export function IbelickSafeAreasGood() {
  return (
    <div className="space-y-4">
      <div className="relative border rounded-[2rem] overflow-hidden bg-background" style={{ height: '280px' }}>
        {/* Simulated iPhone with notch */}
        <div className="absolute top-0 left-1/2 -translate-x-1/2 w-24 h-6 bg-black rounded-b-xl z-10" />

        <div className="h-full flex flex-col">
          {/* Header with safe area padding */}
          <div className="bg-primary text-primary-foreground px-4 pt-8 pb-3 text-center">
            <span className="font-medium">App Header</span>
          </div>

          <div className="flex-1 p-4 text-sm text-muted-foreground">
            Content area...
          </div>

          {/* Footer with safe area padding */}
          <div className="bg-muted px-4 pt-3 pb-6 flex justify-around">
            <button className="text-xs">Home</button>
            <button className="text-xs">Search</button>
            <button className="text-xs">Profile</button>
          </div>
        </div>

        {/* Home indicator */}
        <div className="absolute bottom-1 left-1/2 -translate-x-1/2 w-24 h-1 bg-black rounded-full" />
      </div>
      <p className="text-xs text-success">
        Fixed chrome pads itself out of the hardware: <code>padding-top: env(safe-area-inset-top)</code> on the header, <code>padding-bottom: env(safe-area-inset-bottom)</code> on the bar — so the title clears the notch and the buttons clear the home indicator.
      </p>
      <p className="text-xs text-muted-foreground">
        The padding above is simulated, because a desktop viewport reports insets of 0. In a real app this needs <code>viewport-fit=cover</code> in the viewport meta tag, or every <code>env(safe-area-inset-*)</code> resolves to 0 and does nothing. Note <code>pt-safe</code> / <code>pb-safe</code> are not core Tailwind utilities — they require a plugin or a custom <code>@utility</code>.
      </p>
    </div>
  );
}
```

## References

- [ibelick — baseline-ui SKILL.md](https://github.com/ibelick/ui-skills/blob/main/skills/baseline-ui/SKILL.md)
- [MDN — env()](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/env)
- [Designing for Notches](https://webkit.org/blog/7929/designing-websites-for-iphone-x/)
