Skip to content

Commit 94095a5

Browse files
authored
Merge pull request #50 from jdevalk/standards-scan/forced-colors-2026-06-21
content(accessibility): add Forced colours mode page
2 parents ea145e5 + e7a9876 commit 94095a5

11 files changed

Lines changed: 86 additions & 4 deletions

File tree

public/og-default.png

-728 Bytes
Loading

public/og/checklist.png

3.16 KB
Loading

public/og/spec.png

-219 Bytes
Loading

public/og/spec/accessibility.png

-369 Bytes
Loading
22.7 KB
Loading

src/components/HeadMeta.astro

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,18 @@ const {
2929
const canonicalUrl =
3030
canonical ?? new URL(Astro.url.pathname, site.url).toString();
3131
const fullTitle = title === site.name ? title : `${title} · ${site.shortName}`;
32+
// On a Cloudflare Pages preview build the production OG images don't exist yet
33+
// (they ship with the PR that's still in preview), so point the social image at
34+
// the deployment's own origin. Production (the `main` branch) keeps site.url so
35+
// the card stays on the canonical domain. Canonical itself never changes.
36+
const cfBranch = process.env.CF_PAGES_BRANCH;
37+
const ogBase =
38+
cfBranch && cfBranch !== "main"
39+
? (process.env.CF_PAGES_URL ?? site.url)
40+
: site.url;
3241
const ogImage = new URL(
3342
ogImageOverride ?? "/og-default.png",
34-
site.url,
43+
ogBase,
3544
).toString();
3645
---
3746

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: New page on forced colours mode
3+
date: "2026-06-22"
4+
type: added
5+
relatedSlugs: [forced-colors]
6+
---
7+
8+
Added a page on [forced colours mode](/spec/accessibility/forced-colors/) — the `forced-colors` media feature (CSS Media Queries Level 5) that signals when Windows High Contrast and similar palettes are active. It sits alongside [colour contrast](/spec/accessibility/color-contrast/) and [`color-scheme`](/spec/foundations/color-scheme/): use system colour keywords to repair boundaries the user's palette flattens, without overriding their choice.

src/content/spec/accessibility/color-contrast.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ summary: "Text and meaningful non-text elements must have enough contrast agains
66
status: required
77
order: 10
88
appliesTo: [all]
9-
relatedSlugs: [focus-indicators, semantic-html]
9+
relatedSlugs: [focus-indicators, semantic-html, forced-colors]
1010
updated: "2026-05-29T09:13:20.000Z"
1111
sources:
1212
- title: "WCAG 1.4.3 — Contrast (Minimum) (Level AA)"
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
title: "Forced colours mode"
3+
slug: forced-colors
4+
category: accessibility
5+
summary: "Respect forced colours mode (Windows High Contrast and similar). The `forced-colors` media feature lets you repair UI the user's palette would otherwise flatten — without overriding their choice."
6+
status: recommended
7+
order: 15
8+
appliesTo: [all]
9+
relatedSlugs: [color-contrast, color-scheme, reduced-motion]
10+
updated: "2026-06-22T00:00:00.000Z"
11+
sources:
12+
- title: "CSS Media Queries Level 5 — forced-colors"
13+
url: "https://drafts.csswg.org/mediaqueries-5/#forced-colors"
14+
publisher: "W3C"
15+
- title: "CSS Color Adjustment Module Level 1 — forced-color-adjust"
16+
url: "https://drafts.csswg.org/css-color-adjust-1/#forced"
17+
publisher: "W3C"
18+
- title: "MDN — forced-colors"
19+
url: "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/forced-colors"
20+
publisher: "MDN"
21+
---
22+
23+
## What it is
24+
25+
Some users override every site's colours with a small, high-contrast palette of their own. Windows High Contrast mode is the best-known example; the operating system or browser substitutes the user's chosen foreground, background, link, and button colours for whatever the page declared. The browser exposes that state through the `forced-colors` media feature, which is `active` when a forced palette is in effect.
26+
27+
```css
28+
@media (forced-colors: active) {
29+
.card {
30+
/* box-shadow is forced to none — restore the boundary with a border */
31+
border: 1px solid CanvasText;
32+
}
33+
}
34+
```
35+
36+
Forced colours mode works automatically for most semantic markup. The feature exists for the cases where the substitution removes information — and for the rare element that should opt out via `forced-color-adjust`.
37+
38+
## Why it matters
39+
40+
The high contrast of a reduced palette is essential for some users with low vision, light sensitivity, or cognitive needs to read a page at all. When forced colours apply, the browser drops `box-shadow`, flattens background images behind text, and recolours borders and text to system colours. UI that relied on a shadow, a background-colour swatch, or a coloured-but-borderless control can lose its visible boundary entirely.
41+
42+
Respecting the mode means two things: never fighting the user's palette, and repairing the few places where their palette erases a distinction your design carried in colour alone.
43+
44+
## How to implement
45+
46+
- **Build on semantic HTML.** Real `<button>`, `<a>`, and form controls map to system colour keywords automatically; custom `<div>` widgets do not.
47+
- **Use CSS system colours** inside the query — `CanvasText`, `Canvas`, `LinkText`, `ButtonText`, `ButtonFace`, `Highlight` — so repairs track the user's actual palette rather than hard-coded values.
48+
- **Restore lost boundaries.** Where a control or container was defined by `box-shadow` or background colour alone, add a `border` or `outline` inside `@media (forced-colors: active)`.
49+
- **Opt out sparingly.** `forced-color-adjust: none` on an element (e.g. a colour-picker swatch or a meaningful chart key) preserves its own colours. Use it only where the colour *is* the information.
50+
- **Pair with `prefers-contrast: more`** for users who asked for higher contrast without a forced palette — the two queries serve different audiences.
51+
52+
The site ships forced-colours-aware styles; see the related [colour contrast](/spec/accessibility/color-contrast/) page.
53+
54+
## Common mistakes
55+
56+
- Hard-coding colours inside the query instead of using system colour keywords, re-breaking the user's palette.
57+
- Conveying state (selected, error, disabled) through colour that forced mode discards, with no border, icon, or text fallback.
58+
- Slapping `forced-color-adjust: none` across large regions, defeating the mode for everything inside.
59+
- Using the deprecated `-ms-high-contrast` media query instead of standard `forced-colors`.
60+
61+
## Verification
62+
63+
- On Windows, enable **Settings → Accessibility → Contrast themes** and pick a theme; reload the page.
64+
- In Chrome or Edge DevTools, open the Rendering panel and set **Emulate CSS media feature forced-colors: active**.
65+
- Confirm every control and container keeps a visible boundary, and that no state is signalled by colour alone.

src/content/spec/accessibility/reduced-motion.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ summary: "Respect the user's `prefers-reduced-motion` setting. Decorative animat
66
status: required
77
order: 125
88
appliesTo: [all]
9-
relatedSlugs: [focus-indicators, semantic-html, color-contrast]
9+
relatedSlugs: [focus-indicators, semantic-html, color-contrast, forced-colors]
1010
updated: "2026-05-29T10:57:27.000Z"
1111
sources:
1212
- title: "WCAG 2.3.3 — Animation from Interactions (Level AAA)"

0 commit comments

Comments
 (0)