# iOS status bar colour and geometry

> Reproduce how iOS 18.6.2 chooses an installed web app's status-bar colour and lays out black-translucent content with safe-area insets.

An installed web app on iOS can colour the strip behind the status icons and can extend its CSS viewport beneath that strip. On an iPhone 16 Pro running iOS 18.6.2, the page's `theme-color` meta supplied the colour when present, while `black-translucent` together with `viewport-fit=cover` exposed a full-height viewport and a top safe-area inset.

Use these steps when you need to reproduce that measured configuration or separate a colour problem from a safe-area problem. You need an HTTPS page with a web app manifest, an iPhone that can add it to the Home Screen, and Mac Safari Web Inspector for the instrumented geometry read. The numerical results below apply to the recorded iPhone 16 Pro and iOS 18.6.2 (22G100) run on 2026-10-20 ([study data package](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/), openpwa.net).

## Where it is supported

The measured result applies to Safari and an installed Home Screen web app on an iPhone 16 Pro running iOS 18.6.2. WebKit introduced `theme-color` in HTML meta tags and web manifests for Safari 15 and says it changes the status-bar and overscroll colours in Safari on iOS 15 ([New WebKit Features in Safari 15](https://webkit.org/blog/11989/new-webkit-features-in-safari-15/), webkit.org). The Web Application Manifest permits a document's `theme-color` meta to override the manifest's `theme_color`, but does not require that choice ([Web Application Manifest, `theme_color`](https://www.w3.org/TR/appmanifest/#theme_color-member), w3.org).

The precedence and dimensions in this field note are measured iOS 18.6.2 results and do not describe every iOS release. The run did not install separate apps using the `default` or `black` values, did not test landscape or Dark appearance, and tested `black-translucent` only with `viewport-fit=cover`.

## Examples

Use one colour probe and one geometry probe to keep the rendered colour separate from the viewport measurement.

### Declare both colour sources

Give the document a colour and keep the manifest colour as its default. The recorded M1 app used different values so the screenshot identified which declaration won.

```html
<head>
  <meta name="theme-color" content="#00a050">
  <link rel="manifest" href="/manifest.webmanifest">
</head>
```

```json
{
  "name": "Status bar probe",
  "start_url": "/",
  "display": "standalone",
  "theme_color": "#d00000"
}
```

Add the page from Safari, launch it from its Home Screen icon, and take a screenshot. In the recorded M1 result, all sampled points in the strip were `#00a050`; M2 used the meta value `#d00000` without a manifest colour, and M3 used the manifest value `#00a050` when the document had no meta. The result was that the document meta took precedence and the manifest value acted as the fallback on this build ([status-bar colour source](/lab/behaviour/status-bar-colour-source/)).

Detect the declarations before interpreting a visual mismatch. This check reports which source is available and gives an explicit fallback when neither exists.

```js
const meta = document.querySelector('meta[name="theme-color"]');
const manifestLink = document.querySelector('link[rel="manifest"]');

if (meta?.content) {
  console.log({ source: 'document', colour: meta.content });
} else if (manifestLink) {
  console.log({ source: 'manifest', href: manifestLink.href });
} else {
  console.log({ source: 'none', action: 'use browser default' });
}
```

For the M1 document, the command's expected output is `{ source: "document", colour: "#00a050" }`. It detects declarations only; use a screenshot or a device test to inspect the rendered strip.

:::caution
Do not infer `default` or `black` behaviour from the iOS 18.6.2 run. Those app variants were not installed, and the lab withdrew an earlier operator answer about them. The evidence for colour precedence covers the default-style cases that were recorded, while the geometry evidence covers `black-translucent` with `viewport-fit=cover` ([status-bar colour source](/lab/behaviour/status-bar-colour-source/); [black-translucent geometry](/lab/behaviour/status-bar-black-translucent-geometry/)).
:::

### Extend content under the status bar

Apple's archived meta-tag reference says `black-translucent` displays web content over the entire screen, partially obscured by the status bar, and that the setting affects a full-screen web app ([Supported Meta Tags](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html), developer.apple.com). Pair it with `viewport-fit=cover`, then use the safe-area environment variables to keep controls out of the obscured region. CSS defines the safe-area inset variables from the viewport edges, and `cover` uses the rectangle that circumscribes the screen ([CSS Environment Variables](https://drafts.csswg.org/css-env-1/#safe-area-insets), csswg.org; [CSS Round Display, `viewport-fit`](https://drafts.csswg.org/css-round-display/#viewport-fit), csswg.org).

```html
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<style>
  .app-header {
    padding-top: env(safe-area-inset-top, 0px);
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
  }
</style>
```

The fallback arguments keep the padding at `0px` when a browser does not expose an inset value. In the recorded Home Screen app, this configuration returned a 402 x 874 inner viewport, a 62 px top inset, and a 34 px bottom inset. The default-style comparison returned 402 x 812 with a zero top inset; adding `viewport-fit=cover` to that comparison changed the bottom inset to 34 px but did not move its top edge ([black-translucent geometry](/lab/behaviour/status-bar-black-translucent-geometry/)).

### Measure the active geometry

Connect Web Inspector after the installed app is visible. Create a temporary fixed element so the computed style resolves the environment variables, then print the viewport and padding.

```js
const probe = document.createElement('div');
probe.style.cssText = [
  'position:fixed',
  'padding-top:env(safe-area-inset-top, 0px)',
  'padding-bottom:env(safe-area-inset-bottom, 0px)'
].join(';');
document.body.append(probe);

const style = getComputedStyle(probe);
console.log([innerWidth, innerHeight, style.paddingTop, style.paddingBottom]);
probe.remove();
```

The archived iOS 18.6.2 app read printed `[402, 874, "62px", "34px"]`. The same URL in a Safari tab printed `[402, 678, "0px", "0px"]`. Check `matchMedia('(display-mode: standalone)').matches` or `navigator.standalone` before comparing your output; if both are false, install and launch the page from its icon, because the tab result is a different presentation context.

If the header sits below the status strip despite `black-translucent`, first inspect the parsed meta and viewport strings in the active document. If the page covers the strip but text or controls collide with status icons, keep the full-height viewport and apply `env(safe-area-inset-top)` to the content container. Record the device, OS build, orientation, meta values, viewport output, and a screenshot so the result remains tied to the tested configuration.

## See also

- [Web Application Manifest, `theme_color`](https://www.w3.org/TR/appmanifest/#theme_color-member) (w3.org)
- [Supported Meta Tags](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html) (developer.apple.com)
- [Status-bar colour source in iOS Home Screen apps](/lab/behaviour/status-bar-colour-source/)
- [black-translucent viewport geometry on iOS](/lab/behaviour/status-bar-black-translucent-geometry/)
- [`theme_color` and `background_color`](/reference/manifest/theme-background-color/)