WCAG 2.2 contrast on a gradient

Text and gradients Every point, not the two ends

Text on a gradient can pass at both ends and fail in the middle, where a light stop sits or two hues blend into something duller. Paste a CSS gradient, put text on it or fill text with it, and every point the text covers is measured, with the weak stretches marked and fixes worked out.

What you get

  1. The weakest point Where along the gradient the text is hardest to read, and its color.
  2. Every weak stretch A chart of the contrast from one end to the other, failures in red.
  3. Fixes that keep the look A nearby text color, a light layer, moved stops or another color space.
  4. Gradient text too Text filled with a gradient is measured against its background the same way.

The workbench

Measure text and a gradient

Paste any linear-gradient() from your CSS, or open an example, then move the text, change it and try a fix. Every change is measured again at once.

The workbench needs JavaScript. The worked examples below read without it.

Dark text on a pink-to-blue banner

Text on a gradient 1200 × 400 px

Drag the dashed frame to move the text, or its corner to resize it. With the frame focused, the arrow keys move it and Shift with an arrow key resizes it. The red line marks the weakest point.

Contrast with the text along the whole gradient. The thick line is the stretch the text covers; red is where it falls short.

Result

Text on a gradient

4.15:1 lowest contrast

Fails

Normal text needs 4.5:1 AA

Where the text starts
4.89:1
Where the text ends
4.73:1
Weakest point
#9564C6 49%
Stretch that passes
28%

Both ends pass, so checking only the ends would have missed this.

Weak stretches, along the gradient

  • 19%–85%

Nearest text color that passes everywhere

Working it out…

Plain text colors

  • White — Fails
  • Black — Fails

Lightest even layer over the gradient

Working it out…

The stops, moved until it passes

The same stops, blended in another color space

  • srgb — Fails
  • oklab — Fails
  • oklch — Fails

CSS for this result

The numbers along the stretch
Contrast at eleven points across the stretch the text covers
Along the gradientColorContrastVerdict

The gradient

Any linear-gradient(): an angle or a side, stops with positions and hints, transparency, and in srgb, oklab, oklch or hsl.

What shows through where the gradient is see-through.

Text
Text frame

Percentages of the box.

Layer over the gradient
Measure

Worked examples

Four gradients, measured

Each example is measured at level AA in a box 1200 by 400 pixels, over the stretch its text covers, on a white page. Open one in the workbench to change anything.

Four gradients: the contrast at the ends of the text against the weakest point, and what fixes it
GradientTextNeedsAt the endsLowestWhereThe same stops in oklabA fixWorkbench
Pink to blue, dark text #111827 18 px Regular 4.5:1 4.89:1 / 4.73:1 4.15:1 49% 4.81:1 Text #080E1C
A light stop in the middle #FFFFFF 36 px Bold 3:1 8.53:1 / 7.27:1 2.14:1 50% 2.14:1 A black layer 16%
A fade to transparent #FFFFFF 16 px Regular 4.5:1 10.36:1 / 3.64:1 3.64:1 44% 3.64:1 A black layer 12%
Gradient text on white Background #FFFFFF 48 px Bold 3:1 6.28:1 / 2.14:1 2.14:1 100% 2.14:1 Last stop #CE8400
  • Both ends can pass while the middle fails. Pink to blue measures 4.89:1 / 4.73:1 at the ends of the text but 4.15:1 in the middle, because blending in sRGB dims the middle of two hues. The same two stops blended in oklab pass, with no color changed.
  • A light stop sinks white text. The amber stop between two dark ones is the weakest point, and no color space helps, because the stop itself is too light; a faint black layer fixes it.
  • A fade is measured on the page behind it. Where a fade turns transparent the white page shows through, so white text weakens all the way down, and the weakest point is the bottom of the text.
  • Gradient text fails at its lightest stop. On white, the amber end is too light for its size; darkening that one stop fixes it and keeps the other two.

Method

How it measures

  1. The gradient is read the way CSS reads it: an angle or a side or corner, stops with one or two positions in percent or pixels, transition hints, and the rules that fix up missing or out-of-order positions.
  2. The text's frame is projected onto the gradient line, which runs through the middle of the box at the gradient's angle, so the stretch measured is exactly the one behind the text. For gradient text, the gradient runs across the text's own box.
  3. Colors are blended in the gradient's color space, premultiplied by alpha: sRGB when every color is a hex, rgb(), hsl() or a name and no space is given, oklab otherwise, as CSS Color 4 says. A result outside sRGB is clipped, and each channel is rounded to a whole number, as a screen shows it.
  4. Where the gradient is see-through, the page color behind it is blended in, and a layer over the gradient is blended on top.
  5. The stretch is sampled at twice the box's pixel density along the gradient line, and each sample is compared with the text by WCAG 2's contrast formula. The lowest of them is the result.
  6. The nearest text color keeps its hue and chroma and moves only its lightness in OKLCH; the moved stops do the same, each one away from the text, until the whole blended stretch passes.

The worked examples are recomputed by an automated test from the same code, so a figure on this page cannot drift from what the workbench measures.

Found a wrong number? Tell us.

Limits

What a measurement cannot tell you

  • WCAG does not say how to measure a gradient. Its ratio compares two flat colors. Holding text to the weakest point behind it is the strict reading. A CSS gradient is a background image, and W3C lists a background image without enough contrast with the text as a failure of 1.4.3 and 1.4.6 (failure F83).
  • Only linear gradients are read. For a radial or conic gradient, or several layered together, take a screenshot and measure it with Text on an image.
  • Browsers may dither. To hide banding, a browser can nudge a pixel of a gradient by one step; that moves a ratio in its third decimal place, not across a threshold.
  • Wide-gamut colors are clipped. A stop given in display-p3 or a blend that leaves sRGB is measured as sRGB shows it, which may not be what a wide-gamut screen paints.
  • The frame is a rectangle. Every point inside it counts, including space between words; for gradient text, the gradient's ends may sit beyond the last letter. That is the strict reading: if the frame passes, every letter does.
  • Layouts change the stretch. A gradient sized to its box moves under the text when the box changes width, so measure at each width your design uses.
  • Gradient text needs a fallback. Where background-clip: text is not supported the text takes its own color, so the CSS here gives it one that passes too.

In practice

Making text on a gradient readable

  1. Blend in oklab. Two stops blended in sRGB can dip in the middle; in oklab, lightness changes evenly, and the colors stay the ones you chose.
  2. Keep the text off the light stop. Move the frame to the part of the gradient that suits the text, or move the stop away from the text.
  3. Darken or lighten the weak stop, not the whole gradient. The moved stops change lightness only, so each stop keeps its hue.
  4. Lay a faint layer over the gradient. A few percent of black under light text, or white under dark text, is often enough, and it holds wherever the text moves.
  5. Choose the text color for the weakest point. A text color that passes the weakest point passes everywhere along the stretch.

The rules: 1.4.3 Contrast (Minimum) and 1.4.6 Contrast (Enhanced).

Where next

Check the rest of the page

From one gradient to every pair on a page.