bug: dark-mode @media block in tokens.css does not apply when loaded via @import in iOS Safari #4

Open
opened 2026-05-15 03:10:53 +00:00 by brendan · 0 comments
Owner

Symptom

After adopting @bchen/ui in buchinese, the hamburger menu panel (background: var(--bg-elevated)) still renders white in iOS Safari dark mode. The light-mode value (var(--gray-50) = #fafafa) is being applied, which means the light-mode ":root" block from tokens.css" IS loading correctly — but the @media (prefers-color-scheme: dark)` block inside the same file is not overriding it.

Root cause hypothesis

The current dist/tokens.css puts both light and dark declarations in a single file:

:root { --bg-elevated: var(--gray-50); }

@media (prefers-color-scheme: dark) {
  :root { --bg-elevated: #1a1d23; }
}

Consuming projects load it via CSS @import:

@import "/vendor/bchen-ui/tokens.css";

iOS Safari has historically been inconsistent about applying @media blocks that live inside @imported stylesheets, especially when the import path is a vendor/static asset URL rather than a same-directory relative path. The light-mode :root block applies (it has no condition), but the conditional dark-mode block does not.

The more reliable approach is to move the media condition to the @import call itself rather than inside the imported file, which is fully specified behaviour and has broader engine support:

/* tokens-dark.css — dark overrides only */
:root {
  --bg-elevated: #1a1d23;
  /* ... rest of dark values ... */
}
/* consuming stylesheet */
@import "/vendor/bchen-ui/tokens.css";
@import "/vendor/bchen-ui/tokens-dark.css" (prefers-color-scheme: dark);

Proposed fix

Split dist/tokens.css into two files:

  • dist/tokens.css — light-mode :root {} block only (no @media)
  • dist/tokens-dark.css — dark-mode :root {} values only (no @media wrapper — the condition goes on the @import)

Add "./tokens-dark.css" to the exports map in package.json.

Consuming projects update their import:

@import "/vendor/bchen-ui/tokens.css";
@import "/vendor/bchen-ui/tokens-dark.css" (prefers-color-scheme: dark);

This shifts the media condition from inside the file to the @import call, which is the spec-correct and engine-consistent way to conditionally apply an imported stylesheet.

Files to touch

  • dist/tokens.css — remove @media (prefers-color-scheme: dark) block
  • dist/tokens-dark.css — new file, dark-mode :root {} only
  • package.json — add "./tokens-dark.css" export
  • tests/tokens.test.ts — update / add tests for both files
## Symptom After adopting `@bchen/ui` in buchinese, the hamburger menu panel (`background: var(--bg-elevated)`) still renders white in iOS Safari dark mode. The light-mode value (`var(--gray-50)` = `#fafafa`) is being applied, which means the light-mode ":root" block from `tokens.css" IS loading correctly — but the `@media (prefers-color-scheme: dark)` block inside the same file is not overriding it. ## Root cause hypothesis The current `dist/tokens.css` puts both light and dark declarations in a single file: ```css :root { --bg-elevated: var(--gray-50); } @media (prefers-color-scheme: dark) { :root { --bg-elevated: #1a1d23; } } ``` Consuming projects load it via CSS `@import`: ```css @import "/vendor/bchen-ui/tokens.css"; ``` iOS Safari has historically been inconsistent about applying `@media` blocks that live inside `@import`ed stylesheets, especially when the import path is a vendor/static asset URL rather than a same-directory relative path. The light-mode `:root` block applies (it has no condition), but the conditional dark-mode block does not. The more reliable approach is to move the media condition to the `@import` call itself rather than inside the imported file, which is fully specified behaviour and has broader engine support: ```css /* tokens-dark.css — dark overrides only */ :root { --bg-elevated: #1a1d23; /* ... rest of dark values ... */ } ``` ```css /* consuming stylesheet */ @import "/vendor/bchen-ui/tokens.css"; @import "/vendor/bchen-ui/tokens-dark.css" (prefers-color-scheme: dark); ``` ## Proposed fix Split `dist/tokens.css` into two files: - `dist/tokens.css` — light-mode `:root {}` block only (no `@media`) - `dist/tokens-dark.css` — dark-mode `:root {}` values only (no `@media` wrapper — the condition goes on the `@import`) Add `"./tokens-dark.css"` to the `exports` map in `package.json`. Consuming projects update their import: ```css @import "/vendor/bchen-ui/tokens.css"; @import "/vendor/bchen-ui/tokens-dark.css" (prefers-color-scheme: dark); ``` This shifts the media condition from inside the file to the `@import` call, which is the spec-correct and engine-consistent way to conditionally apply an imported stylesheet. ## Files to touch - `dist/tokens.css` — remove `@media (prefers-color-scheme: dark)` block - `dist/tokens-dark.css` — new file, dark-mode `:root {}` only - `package.json` — add `"./tokens-dark.css"` export - `tests/tokens.test.ts` — update / add tests for both files
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: brendan/bchen-ui#4