How to make your brand color accessible

Keep the hue people recognize; move only the lightness, until the color can carry words.

Design · 115 4 Live Demos ~8 min read Brand · WCAG · OKLCH
2.10:1
Brand gold as text on white
9.95:1
Black text on the same gold
#8F7300
The gold, dark enough for text
4.58:1
The least any color gets with black or white
01

Why brand colors fail contrast

Brand colors are chosen to be seen from across a room - on a logo, a shopping bag, a billboard. Many of the most recognizable are saturated hues at middle lightness: gold and yellow, orange, cyan, light green. Those are exactly the colors that make poor text on white, and poor backgrounds for white text.

The reason is luminance. WCAG measures contrast from relative luminance, and a saturated yellow or green is bright: most of its light sits in the green channel, which carries 71.5% of the weight. This site's gold, #D3AF37, has a relative luminance of 0.448. As text on white it scores 2.10:1 - short even of the 3:1 WCAG asks of large text. Black text on the same gold scores 9.95:1.

Color Against white Against black Readable text on it
Yellow #FFD400 1.43:1 14.66:1 Black
Gold #D3AF37 2.10:1 9.95:1 Black
Light green #7AC943 2.04:1 10.26:1 Black
Cyan #00B5E2 2.41:1 8.70:1 Black
Orange #FF7A00 2.61:1 8.03:1 Black
Red #E63946 4.16:1 5.03:1 Black (white only for large text)
Blue #1D4ED8 6.70:1 3.13:1 White

The first five fail WCAG AA as text on white, and white text on any of them fails too. Black text on all five reaches AAA. Red sits in the awkward middle; the blue behaves the other way round.

There is a hard limit here worth knowing. A color passes 4.5:1 against white only if its relative luminance is at most 0.183, and against black only if it is at least 0.175. The two ranges barely overlap, and where they meet the better of black or white reaches just 4.58:1 - the lowest score any sRGB color can get with the better of the two. So every color can carry black or white text at AA, and almost no color can carry both.

Interactive 01 · Where your color sits

Place a brand color on the luminance scale

The bar runs from black to white in even steps of perceived lightness. The green band is where a color works as text on white; the gold band is where it works with black text. Pick a brand color or try one of the hues from the table, and see where it lands and which ink it can carry.

Try a hue
Text on white (4.5:1)
Black text on it (4.5:1)
As text on white
Black text on it
White text on it
Relative luminance
OKLCH lightness
Text on white, AA
Black text on it, AA
White text on it, AA
02

Keep the hue, move the lightness

The fix that keeps a brand recognizable is to leave its hue alone and change its lightness. OKLCH makes that a one-number move. It describes a color as L (perceived lightness, 0 to 1), C (chroma, how colorful it is) and h (the hue angle). The gold is oklch(0.766 0.138 91.6).

Contrast follows lightness closely. For a neutral gray, OKLCH L is exactly the cube root of relative luminance, so WCAG's limit for text on white, a luminance of 0.183, is L 0.568 for a gray. Colored shades land near that line. Walk the gold down in steps of 0.005 at a constant hue and the first shade that reaches 4.5:1 on white is #8F7300, at L 0.566.

  1. Convert the brand color to OKLCH: L 0.766, C 0.138, h 91.6°.
  2. Lower L by 0.005, keep h, and ask for the same C.
  3. If that color falls outside sRGB, trim C until it fits - a dark yellow cannot be as vivid as a bright one. At the end of this walk the gold's chroma has trimmed to 0.116.
  4. Convert to sRGB, round to 8 bits - which can nudge the hue by a fraction of a degree - and measure the ratio against the background.
  5. Stop at the first shade that passes. For gold on white that takes 40 steps: #8F7300 at 4.54:1.

The same walk gives a shade for each job. #B49100 reaches 3.00:1 on white, enough for borders, icons and focus rings; #6B5600 reaches 7.10:1 for AAA text. The price is distance from the original. In ΔE2000, #B49100 is 8.96 away - a noticeable change - and #8F7300 is 20.11 away, a distinct one. That is expected, because text has to be far darker than a bright gold. Keeping the hue is what makes the darker shades still read as the same gold family.

Interactive 02 · OKLCH lightness walker

Find the nearest accessible shade of a brand color

Pick a brand color and a job. The walker moves OKLCH lightness away from the background in steps of 0.005, keeps the hue, trims chroma only when sRGB runs out, and stops at the first shade that passes. The strip shows the path; the cards show where it started, where it stopped and how far the color moved.

Job
Brand color
Walked shade
Start
Hex
OKLCH
Result
Hex
OKLCH
Steps of 0.005
Moved by (ΔE2000)
Shade
As text on white
As text on #121212
03

One brand, several jobs

On a screen a brand color is asked to do several different things, and each has its own contrast rule. Give each job its own shade instead of asking one hex value to do all of them.

Job What WCAG asks Gold, worked out
Large fills, illustration, hero areas Nothing for decoration; text placed on it needs 4.5:1 #D3AF37 with black text, 9.95:1
Text and links on white 4.5:1 (1.4.3) #8F7300, 4.54:1
Borders, icons and focus rings on white 3:1 against adjacent colors (1.4.11) #B49100, 3.00:1
Body text on a dark surface 4.5:1, plus APCA Lc 75 if you use it #EDC955 on #121212, 11.67:1 and Lc −75.3
Button labels 4.5:1 between label and fill Black on #D3AF37, 9.95:1

A button's edge is a subtler case. WCAG 1.4.11 covers the visual information people need to identify a control, and the W3C's guidance says a control with visible text does not need its boundary to meet 3:1. So a pale gold button on a white page is not a failure by itself. It is still a weak signal: a 3:1 edge, or a darker fill, helps everyone find the button.

Interactive 03 · A brand token set

Turn one brand color into a working set of shades

Pick a brand color. The demo derives a shade for each job with the same lightness walk, picks black or white for labels on the fill, darkens the fill in OKLCH for hover and pressed states, and shows the set at work on a light and a dark surface. The CSS at the bottom records each pairing and its ratio.

Tokens
States of the primary button
Your order is ready Pick it up today, or change the delivery address before 6 pm.
Confirm Details Focused
Your order is ready Pick it up today, or change the delivery address before 6 pm.
Confirm Details Focused
04

Never color alone

Contrast answers whether people can see a color. WCAG 1.4.1 asks a different question: whether color is the only thing carrying a meaning. A brand color that marks links, the selected tab, a required field or an error needs a second cue - an underline, an icon, a change of weight, a word.

Links are the common case. #8F7300 passes 4.5:1 as text on white, but beside body text it is just another dark color: 3.82:1 against #1A1A1A and only 2.77:1 against #333333. WCAG's technique G183 accepts a link told apart by color alone when it has 3:1 against the surrounding text and gains a non-color cue on hover and focus; next to #333333 the gold misses even that. The dependable fix is the oldest one: underline links in running text.

05

Check color vision deficiency

About 8% of men and 0.5% of women have a color vision deficiency. Contrast against black or white survives it well, because it rests on luminance: simulated with this site's color-vision model, gold on white stays between 2.02:1 and 2.25:1. The risk lies between colors. A palette that separates gold from orange by hue alone can collapse - under a deuteranopia simulation, #D3AF37 and #E8892B are only ΔE2000 3.9 apart, against 18.8 for typical vision.

Check the brand color together with everything it sits beside: the secondary color, and the success, warning and error colors. The Vision Deficiency Lab, the site's color-blindness simulator, runs the same check on whole screens, and the Accessibility Color Pair Library lists pairs already scored against WCAG, APCA and color vision deficiency.

Interactive 04 · Brand palette under color vision deficiency

Which colors in the palette collapse together?

Set the five colors of a small brand palette. Each row shows them as seen with typical vision and under three simulated deficiencies (Machado et al. 2009, full severity, applied in linear light). The note under each row names the closest pair and flags it when the ΔE2000 falls below 10 - the point where this site's tools stop calling a difference distinct.

06

Hover, focus and pressed states

Every interactive state is a color pair of its own. WCAG 2.4.7 requires a visible focus indicator, and 1.4.11 asks that indicator to reach 3:1 against the colors next to it. A gold ring on a white page, at 2.10:1, does not; the 3:1 shade #B49100 does. A two-tone ring - a dark outline around a light one - works on any background. WCAG 2.2 goes further at Level AAA with Focus Appearance, which also sets a minimum size for the indicator and a 3:1 change between the focused and unfocused states.

Hover and pressed states usually darken the fill. Doing it in OKLCH keeps the hue: gold at L − 0.05 is #C39F20 and at L − 0.10 is #B29000. With black labels those states score 8.30:1 and 6.88:1, so the label stays readable in every state. Check each state, not just the resting one - a white label would gain contrast as the fill darkens, a black label loses it.

07

Dark mode

Dark mode turns the problem around. Gold on near-black is easy for WCAG: 9.95:1 on #000000 and 8.88:1 on a #121212 surface. APCA is less generous. Gold text on #121212 is Lc −60.5, enough for 24px text but short of the Lc 75 it asks for body text. Walking the gold lighter at the same hue, #EDC955 reaches Lc −75.3 on #121212 (11.67:1), only ΔE2000 6.68 from the original. WCAG vs APCA explains why the two methods rate light text on dark surfaces so differently.

Large fields of saturated color look brighter and heavier on a dark page than on a light one, so many dark themes keep the brand color for accents, buttons and highlights, and use a lighter tint of it for text and thin lines. Dark Mode and Adaptive Color covers building the second theme as a whole.

08

Write it down as design tokens

Once the shades exist, name them by job rather than by lightness, record the pairing each was tested against, and let your build check the pairs. For the gold, worked out above:

:root {
  --brand:         #D3AF37; /* fills and large areas; pair with --on-brand */
  --on-brand:      #000000; /* 9.95:1 on --brand */
  --brand-text:    #8F7300; /* 4.54:1 on #FFFFFF: text, underlined links */
  --brand-ui:      #B49100; /* 3.00:1 on #FFFFFF: borders, icons, focus */
  --brand-hover:   #C39F20; /* --on-brand 8.30:1 */
  --brand-pressed: #B29000; /* --on-brand 6.88:1 */
}
[data-theme="dark"] {
  --brand-text:    #EDC955; /* 11.67:1 and Lc −75.3 on #121212 */
  --brand-ui:      #D3AF37; /* 8.88:1 on #121212 */
}

This site works the same way: its gold is used as it is for fills and accents, while a darker gold ink carries text in the light theme. When you need a quick answer for one pair, the Contrast Checker measures it and nudges a failing color until it passes.

Keep the hue
Move OKLCH lightness only. Hue carries recognition; lightness carries contrast.
One shade per job
Fill, text, UI, hover, pressed and dark-mode text each get a token with a tested pairing.
Ink on the fill
Black or white, whichever scores higher. Every color reaches at least 4.58:1 with one of them.
A second cue
Underlines, icons and words, so the meaning survives without color (WCAG 1.4.1).
Every state
Hover, pressed and focus are pairs too; focus indicators need 3:1.
Both themes
Re-test on the dark surface; a lighter tint usually reads better there.
09

Test your understanding

Six questions on brand colors and contrast. Instant feedback, no scores recorded; a wrong answer comes with a short explanation.

Quick check

Loading…
 
Question 1 of 6
10

Continue your journey

A brand color is a decision about identity first and about contrast second. These cover both sides: where brand colors come from, how systems of shades are built, and how contrast is measured.