Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified public/og-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/checklist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/spec.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/spec/accessibility.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/og/spec/accessibility/contrast-color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/content/changelog/2026-07-04-contrast-color.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: New page on automatic contrasting colour
date: "2026-07-04"
type: added
relatedSlugs: [contrast-color]
---

Added a page on [automatic contrasting colour](/spec/accessibility/contrast-color/) — the CSS `contrast-color()` function that returns a legible black or white foreground for any background, so a dynamic or user-picked colour keeps readable text without hard-coded colour pairs or luminance maths in JavaScript. Documented as `recommended`: it became newly available across major browsers in April 2026 and degrades safely, but a site works fine computing contrast by hand, so it is not `required`.
2 changes: 1 addition & 1 deletion src/content/spec/accessibility/color-contrast.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: "Text and meaningful non-text elements must have enough contrast agains
status: required
order: 10
appliesTo: [all]
relatedSlugs: [focus-indicators, semantic-html, forced-colors]
relatedSlugs: [focus-indicators, semantic-html, forced-colors, contrast-color]
updated: "2026-05-29T09:13:20.000Z"
sources:
- title: "WCAG 1.4.3 — Contrast (Minimum) (Level AA)"
Expand Down
75 changes: 75 additions & 0 deletions src/content/spec/accessibility/contrast-color.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: "Automatic contrasting colour"
slug: contrast-color
category: accessibility
summary: "Let the browser pick a legible black or white foreground for a dynamic background with the CSS contrast-color() function, instead of hard-coding colour pairs or computing luminance in JavaScript."
status: recommended
order: 12
appliesTo: [all]
relatedSlugs: [color-contrast, color-scheme, forced-colors]
updated: "2026-07-04T00:00:00.000Z"
sources:
- title: "CSS Color Module Level 5 — contrast-color()"
url: "https://drafts.csswg.org/css-color-5/#contrast-color"
publisher: "W3C CSS Working Group"
- title: "WCAG 1.4.3 — Contrast (Minimum) (Level AA)"
url: "https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html"
publisher: "W3C"
- title: "MDN — contrast-color()"
url: "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/contrast-color"
publisher: "MDN"
- title: "How to have the browser pick a contrasting color in CSS"
url: "https://webkit.org/blog/16929/contrast-color/"
publisher: "WebKit"
---

## What it is

`contrast-color()` is a CSS function that takes a `<color>` and returns whichever of `black` or `white` contrasts more strongly with it. You pass it the background (or the text colour) and the browser hands back a legible foreground, so the pairing is never hard-coded.

```css
button {
background-color: var(--accent);
color: contrast-color(var(--accent));
}
```

It is defined in CSS Color Module Level 5. The function commonly targets the WCAG AA minimum of 4.5:1, and browsers are free to use a more perceptually accurate algorithm to choose between black and white.

## Why it matters

- **One source of truth for colour.** When a background is dynamic — a user-chosen accent, a brand colour set in a CMS, a value that flips with `prefers-color-scheme` — you cannot know the right foreground ahead of time. `contrast-color()` computes it at render, so text stays readable whatever the background becomes.
- **No JavaScript.** It replaces the familiar helper that parses a colour, computes relative luminance, and picks black or white — one declaration instead of a script that has to run on every theme change.
- **It degrades safely.** This is progressive enhancement: browsers that do not understand it ignore the declaration, so pair it with a sensible fallback rather than relying on it.

## How to implement

Feed the same custom property to both the background and `contrast-color()`, and provide a hand-picked fallback colour first so unsupporting browsers still get legible text:

```css
button {
background-color: var(--accent);
color: #fff; /* fallback for older browsers */
}

@supports (color: contrast-color(red)) {
button {
color: contrast-color(var(--accent));
}
}
```

Because the result is only ever black or white, reserve it for backgrounds that are clearly light or clearly dark, where one of the two is a strong match.

## Common mistakes

- **Mid-tone backgrounds.** Against a mid-tone such as a royal blue (`#2277d3`), neither black nor white reliably clears AA for small text. The function still returns one of them; it does not guarantee a readable pair. Keep input colours light or dark, or verify the result.
- **Expecting a brand colour back.** It returns `black` or `white` only — never a tint of your palette.
- **Shipping it with no fallback.** Without a plain `color` declaration first, older browsers fall back to the default text colour, which may be illegible on your background.

## Verification

- Feature-query it: `@supports (color: contrast-color(red))` tells you whether the browser will honour it.
- Inspect the computed `color` in DevTools and confirm the resulting pair meets 4.5:1 against the actual background values you ship, using a contrast checker.
- Toggle dark mode or change the dynamic colour and confirm the text stays legible either way.
- Baseline: `contrast-color()` became newly available across major browsers in April 2026 (Safari 26, Firefox 146, Chrome and Edge 147). Treat it as an enhancement for everyone else.
2 changes: 1 addition & 1 deletion src/content/spec/accessibility/forced-colors.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: "Respect forced colours mode (Windows High Contrast and similar). The `
status: recommended
order: 15
appliesTo: [all]
relatedSlugs: [color-contrast, color-scheme, reduced-motion]
relatedSlugs: [color-contrast, color-scheme, reduced-motion, contrast-color]
updated: "2026-06-22T00:00:00.000Z"
sources:
- title: "CSS Media Queries Level 5 — forced-colors"
Expand Down
2 changes: 1 addition & 1 deletion src/content/spec/foundations/color-scheme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: "Tells the browser which colour schemes your page is designed for. Prev
status: recommended
order: 95
appliesTo: [all]
relatedSlugs: [theme-color, favicons, pwa-manifest, forced-colors, text-wrap]
relatedSlugs: [theme-color, favicons, pwa-manifest, forced-colors, text-wrap, contrast-color]
updated: "2026-06-30T00:00:00.000Z"
sources:
- title: "HTML Living Standard — Standard metadata names: color-scheme"
Expand Down
Loading