The crime scene
The symptom is always the same. You added viewport-fit=cover. You set your background colors. You read three blog posts and a WebKit bug thread. And iOS Safari still draws an opaque bar across the top of the screen, right where the notch lives, in a shade of white you never picked.
Here is the part nobody tells you up front: that bar contains zero of your pixels. No amount of overflow, clip, z-index or prayer will remove it, because it is Safari's own chrome, painted on top of your page. You cannot style it. You can only influence what color Safari picks for it, and whether Safari decides to show your content through it.
With iOS 26 and the Liquid Glass redesign, Apple rewrote the rules for how that color gets picked. They also forgot to write the rules down anywhere. The community reverse engineered most of it, and we verified the rest the hard way, on a real device, at 4am.
What Apple changed in iOS 26
For years the answer was a meta tag. You set theme-color, Safari painted its chrome in that color, everyone went home early. Safari 26 ended that arrangement. The tag still parses. Safari simply stopped caring about its static value.
Instead, Safari now derives the tint from your page itself, in this order: first it samples the background-color of any position: fixed or position: sticky element near the top edge of the viewport. If it finds none, it falls back to the background color of your html and body elements. If those are transparent, you get white. White like the bar you are staring at.
The sampler has opinions. It ignores absolutely positioned children. It ignores pseudo elements. It ignores anything that is in normal flow, even if it visually touches the top of the screen. It does read elements with opacity: 0 and pointer-events: none, so your hidden modal backdrop is busy tinting Safari's toolbar right now. Only display: none takes an element out of the game.
The graveyard of fixes that don't fix it
Things we tried, in roughly increasing order of desperation:
viewport-fit=cover alone. Necessary, insufficient. It extends your layout under the notch and unlocks env(safe-area-inset-top), which is great, but the tint layer sits on top of your extended layout and keeps being white.
Overflow and clipping tricks. The bar is browser chrome. Clipping your own content harder does nothing except clip your own content.
apple-mobile-web-app-status-bar-style: black-translucent. Applies to home screen web apps only. Safari the browser reads it, nods politely, and ignores it.
A static theme-color meta tag. See above. Safari 26 treats it as decorative.
Offsetting the sticky header below the safe area. This one hurt. We moved the safe area offset from the header's padding into its top and margin-top, so the sticky box never touched the screen edge. The community write-ups say the sampler only looks within a few pixels of the top. Our device said otherwise. The white bar survived. Sticky elements get sampled no matter where they stick.
The experiment that cracked it
The breakthrough came from a tiny A/B test on our own page. We wired up a script that fades the html and body backgrounds (plus the meta tag) toward our footer color as you approach the bottom of the page. Then we scrolled to the footer and looked at both ends of the screen.
Bottom of the screen: perfectly tinted in footer gray. Top of the screen: still glaring white, even though the fallback colors were now dark. Same page, same colors, two different results. The only difference between those two edges was that one of them had a sticky element parked on it. Our transparent sticky nav was feeding the sampler, the sampler was finding nothing it could use, and Safari was resolving that to opaque white.
We switched the nav to position: absolute and reloaded. Clean notch, content flowing underneath, tint following the page. Case closed. The navbar did it.
The recipe that works
Step 1: viewport-fit=cover. Still the entry ticket.
<meta name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover" />Step 2: split your backgrounds. Give html and body an explicit color and treat them as the tint layer Safari reads. Paint the actual page on your app container, so the tint layer can change color without your content noticing.
html, body {
/* the tint layer: Safari samples this as its fallback */
background-color: #fafbff;
}
#app {
/* the page itself paints here */
min-height: 100dvh;
background-color: #fafbff;
}Step 3: drive the tint from JavaScript. Update the meta tag and both root backgrounds together on scroll. Safari picks the changes up, which means the safe areas can match whatever content is currently near them. We fade to the footer color over the last viewport of scroll:
const TOP = "#fafbff"; // page background
const BOTTOM = "#1e2023"; // footer color
function applyTint(color) {
let meta = document.querySelector('meta[name="theme-color"]');
if (!meta) {
meta = document.createElement("meta");
meta.setAttribute("name", "theme-color");
document.head.appendChild(meta);
}
meta.setAttribute("content", color);
document.documentElement.style.backgroundColor = color;
document.body.style.backgroundColor = color;
}
function mix(a, b, t) {
const ch = (h, i) => parseInt(h.slice(i, i + 2), 16);
const hex = (n) => Math.round(n).toString(16).padStart(2, "0");
return "#" + hex(ch(a, 1) + (ch(b, 1) - ch(a, 1)) * t)
+ hex(ch(a, 3) + (ch(b, 3) - ch(a, 3)) * t)
+ hex(ch(a, 5) + (ch(b, 5) - ch(a, 5)) * t);
}
let raf = null;
window.addEventListener("scroll", () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = null;
const remaining = document.documentElement.scrollHeight
- window.innerHeight - window.scrollY;
const t = Math.min(1, Math.max(0, 1 - remaining / window.innerHeight));
applyTint(mix(TOP, BOTTOM, t));
});
}, { passive: true });Step 4: keep fixed and sticky elements away from the top edge. This is the step everyone skips and the reason the other steps seem broken. Any position: fixed or position: sticky element will hijack the top tint, and a transparent one hijacks it to white. An absolutely positioned nav that scrolls away with the page keeps the notch clean.
/* clean notch */
header { position: absolute; top: env(safe-area-inset-top); }
/* white bar generator */
header { position: sticky; top: 0; background: transparent; }Step 5: hide hidden overlays properly. Modal backdrops waiting in the DOM at opacity: 0 still feed the sampler. Use display: none until they actually open.
But I want my sticky navbar
We hear you. We wanted ours too. The honest answer is that on iOS 26 you are choosing between a permanently pinned position: sticky nav and a clean notch. You do not get both, because the sampler keys on the position value itself, even when the element is nowhere near the edge it tints.
If the nav matters more, keep it sticky and accept the bar. You can at least make the bar less offensive by giving the sticky element a real background color that matches your design instead of leaving it transparent, since transparent is what resolves to white.
If the notch matters more, there are two patterns that keep navigation reachable without triggering the sampler. One: a reveal-on-scroll-up nav, absolutely positioned, translated to the viewport with a transform while the user scrolls upward. Safari ignores transforms. Two: the simple version, a nav that lives at the top of the page and scrolls away, the way half the design-forward web already works. Your visitors will survive.
Testing without losing your mind
Test on a real iPhone running iOS 26. The Simulator reproduces some of the tinting behavior and quietly skips the rest, which is a fantastic way to ship a fix that does not work.
Know the two states. At scroll position zero, Safari paints the fallback color and will not composite your actual content behind the status bar. Once the page has any scroll at all, it can. If your first screen is a full-bleed image and the top still shows a flat color, that is this, and the workaround is a small scroll runway you jump past on load.
And remember the user setting. Safari has an Allow Website Tinting toggle, and when it is off, the chrome reverts to system colors no matter how clever your setup is. Design something that still looks intentional in plain white and plain black, because some fraction of your audience lives there.