diff --git a/web/src/app/globals.css b/web/src/app/globals.css index ff94aa9d2..efe1870e4 100644 --- a/web/src/app/globals.css +++ b/web/src/app/globals.css @@ -1081,6 +1081,9 @@ align-items: flex-start; gap: 14px; } + /* The language a page is not in: 5.0:1 on the cream, 5.8:1 on the white + panel, and 3.2:1 from the current one in --ink. --ink-faint was 2.3:1 + and 2.6:1. */ .journal-lang-switch { position: fixed; top: 28px; @@ -1092,7 +1095,7 @@ font-size: var(--pf-fs-mono); letter-spacing: 0.08em; text-transform: uppercase; - color: var(--ink-faint); + color: var(--ink-muted); } .journal-lang-switch a { color: inherit; @@ -1285,7 +1288,7 @@ } .journal-archive-label { margin-bottom: 16px; - color: var(--ink-faint); + color: var(--ink-muted); } .journal-post-list { list-style: none; diff --git a/web/src/components/journal/journalCss.test.ts b/web/src/components/journal/journalCss.test.ts index 68df2697a..a06149853 100644 --- a/web/src/components/journal/journalCss.test.ts +++ b/web/src/components/journal/journalCss.test.ts @@ -60,3 +60,57 @@ describe("journal archive dates", () => { expect(own.some((r) => declaration(r.body, "white-space") === "nowrap")).toBe(true); }); }); + +// The language a page is not in and the index's "Archive" label were +// --ink-faint (#A69F90): 2.29:1 on the cream behind a post's switch and +// 2.63:1 on the index's white panel. axe flagged them on all 76 journal pages. + +/** The sRGB contrast ratio WCAG 2 defines, for two "#rrggbb" colours. */ +function contrast(a: string, b: string) { + const luminance = (hex: string) => { + const [r, g, bl] = [1, 3, 5].map((i) => { + const c = parseInt(hex.slice(i, i + 2), 16) / 255; + return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4; + }); + return 0.2126 * r + 0.7152 * g + 0.0722 * bl; + }; + const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x); + return (hi + 0.05) / (lo + 0.05); +} + +describe("journal faint text", () => { + const all = rules(css); + const root = all.find((r) => r.selectors.includes(":root") && declaration(r.body, "--cream")); + const resolve = (value: string | undefined) => { + const token = value?.match(/^var\((--[\w-]+)\)$/)?.[1]; + const hex = token ? declaration(root?.body ?? "", token) : value; + expect(hex, `${value} is not a #rrggbb colour`).toMatch(/^#[0-9a-f]{6}$/i); + return hex!; + }; + const own = (selector: string, property: string) => + all + .filter((r) => r.selectors.includes(selector)) + .map((r) => declaration(r.body, property)) + .filter(Boolean) + .at(-1); + + const cream = resolve(own(".journal-shell", "background")); + const panel = resolve(own(".journal-panel", "background")); + + it("shows the other language at 4.5:1 on the cream and on the panel", () => { + const other = resolve(own(".journal-lang-switch", "color")); + expect(contrast(other, cream)).toBeGreaterThanOrEqual(4.5); + expect(contrast(other, panel)).toBeGreaterThanOrEqual(4.5); + }); + + it("keeps the current language 3:1 apart from the other", () => { + const other = resolve(own(".journal-lang-switch", "color")); + const current = resolve(own(".journal-lang-switch a.active", "color")); + expect(contrast(current, other)).toBeGreaterThanOrEqual(3); + }); + + it("shows the Archive label at 4.5:1 on the panel", () => { + const label = resolve(own(".journal-archive-label", "color")); + expect(contrast(label, panel)).toBeGreaterThanOrEqual(4.5); + }); +});