From 7b054166d2c74623ae74422a7ed70c8ea9071be6 Mon Sep 17 00:00:00 2001 From: Hunter Garrett Date: Wed, 26 Aug 2026 09:44:41 -0400 Subject: [PATCH 1/2] fix: derive bone colors from the text color instead of the OS scheme (BON-13) A dark-mode OS over a page that keeps a light canvas painted white bones on white: the prefers-color-scheme media query assumed the page follows the scheme. --bone-base and --bone-highlight now default to the inherited text color at 12% and 6% opacity, so bones contrast with whatever the page's own text contrasts with, and the media query is gone. The subtlety: bones hide their content through the color property, so a plain color-mix(currentColor) reads transparent at every bone. Content is now hidden by zeroing only the alpha (rgb(from currentColor r g b / 0)) so the channels survive into the derivation. The measured overlay's no-stylesheet fallbacks derive the same way. Requires relative color syntax, Baseline 2024. Co-Authored-By: Claude Fable 5 --- .changeset/adaptive-bone-colors.md | 5 ++ apps/docs/content/docs/styling.mdx | 28 ++++---- packages/bones/sandbox/auto.html | 6 ++ packages/bones/sandbox/boundary.html | 5 +- packages/bones/src/css/auto.css | 4 +- packages/bones/src/css/bones.css | 21 +++--- packages/bones/src/element/overlay.ts | 10 +-- .../tests/browser/adaptive-colors.test.ts | 68 +++++++++++++++++++ packages/bones/tests/browser/expect-color.ts | 20 ++++++ .../tests/browser/overlay-fallback.test.ts | 30 ++++++++ 10 files changed, 164 insertions(+), 33 deletions(-) create mode 100644 .changeset/adaptive-bone-colors.md create mode 100644 packages/bones/tests/browser/adaptive-colors.test.ts create mode 100644 packages/bones/tests/browser/expect-color.ts create mode 100644 packages/bones/tests/browser/overlay-fallback.test.ts diff --git a/.changeset/adaptive-bone-colors.md b/.changeset/adaptive-bone-colors.md new file mode 100644 index 0000000..a6223ef --- /dev/null +++ b/.changeset/adaptive-bone-colors.md @@ -0,0 +1,5 @@ +--- +"@camp.dev/bones": minor +--- + +Bone colors derive from the inherited text color instead of the OS color scheme. `--bone-base` defaults to the text color at 12% opacity and `--bone-highlight` at 6%, and the `prefers-color-scheme` media query is gone. Bones are now visible on any background the surrounding text is readable on. Before this, a dark-mode OS over a page that kept a light canvas painted white bones on white (BON-13). Overriding the custom properties works unchanged. Internally, bones hide their content by zeroing the alpha of `color` so the channels survive into the derivation, and the measured overlay's no-stylesheet fallbacks derive the same way. The stylesheets now use relative color syntax, which is Baseline 2024 (Chrome 119, Safari 18, Firefox 128). diff --git a/apps/docs/content/docs/styling.mdx b/apps/docs/content/docs/styling.mdx index b9ff02f..5728df5 100644 --- a/apps/docs/content/docs/styling.mdx +++ b/apps/docs/content/docs/styling.mdx @@ -7,12 +7,14 @@ All skeleton visuals are controlled by CSS custom properties. Override them glob ## CSS custom properties -| Property | Default (light) | Default (dark) | Description | -| ------------------ | --------------------- | --------------------------- | ------------------------------ | -| `--bone-base` | `rgba(0, 0, 0, 0.12)` | `rgba(255, 255, 255, 0.12)` | Skeleton background color | -| `--bone-highlight` | `rgba(0, 0, 0, 0.06)` | `rgba(255, 255, 255, 0.06)` | Highlight color (for shimmer) | -| `--bone-radius` | `4px` | `4px` | Border radius of skeleton bars | -| `--bone-duration` | `1.5s` | `1.5s` | Animation duration | +| Property | Default | Description | +| ------------------ | ----------------------------- | ------------------------------ | +| `--bone-base` | the text color at 12% opacity | Skeleton background color | +| `--bone-highlight` | the text color at 6% opacity | Highlight color (for shimmer) | +| `--bone-radius` | `4px` | Border radius of skeleton bars | +| `--bone-duration` | `1.5s` | Animation duration | + +The color defaults derive from the text color in effect at the skeleton, so bones contrast with whatever background the text around them is readable on. A `#333`-on-white article gets translucent dark bars. The same markup inside a dark card with light text gets translucent light bars. ## Theming @@ -41,18 +43,18 @@ Or use a CSS class: ## Dark mode -Dark mode works via `prefers-color-scheme`: +Dark mode needs no configuration. Because bones derive from the text color, a dark theme's light text produces light bones, whether the theme comes from `prefers-color-scheme` or a class-based toggle. + +To give dark mode different bones anyway, override the properties in your dark styles: ```css -@media (prefers-color-scheme: dark) { - :root { - --bone-base: rgba(255, 255, 255, 0.12); - --bone-highlight: rgba(255, 255, 255, 0.06); - } +.dark { + --bone-base: rgba(255, 255, 255, 0.2); + --bone-highlight: rgba(255, 255, 255, 0.1); } ``` -Override these in your own dark mode styles if your app uses a class-based dark mode toggle. +One case needs a manual override: text that depends on its background for contrast, such as white text over a hero image. If the image is part of what loads, the derived white bone can vanish against the page behind it. Set `--bone-base` on that section to a color that works without the image. ## Animations diff --git a/packages/bones/sandbox/auto.html b/packages/bones/sandbox/auto.html index c469a37..15d89c6 100644 --- a/packages/bones/sandbox/auto.html +++ b/packages/bones/sandbox/auto.html @@ -6,6 +6,12 @@ bones auto.css sandbox