How to Check Color Contrast for Accessibility (WCAG)

A fanned-out colour swatch guide with shades from red, yellow and green to grey and black
Photo: “Free paint samples image” by rawpixel.com · CC0 1.0 · via Openverse (rawpixel)

Short answer

To check colour contrast, compare the relative luminance of the text colour and the background colour and work out the ratio (L1 + 0.05) ÷ (L2 + 0.05), where L1 is the lighter colour. The result runs from 1:1 (no contrast) to 21:1 (black on white). Under WCAG 2.2 level AA, normal text needs at least 4.5:1, large text needs 3:1, and icons and form borders need 3:1. Paste any two colours into the free color contrast checker to get the ratio and a pass or fail for AA and AAA instantly.

Light grey text on a white page can look elegant on a big, bright monitor, then become almost unreadable on a phone in sunlight or for someone with low vision. Contrast checking takes the guesswork out: instead of asking “does this look readable to me?”, you measure the difference in brightness between two colours and compare it with the thresholds in the Web Content Accessibility Guidelines (WCAG), the international standard published by the W3C. This guide explains the rules, the maths behind them and a quick routine for checking a whole design.

The WCAG contrast rules at a glance

WCAG 2.2 has three success criteria about contrast. Level AA is the usual target for websites and is what most accessibility laws and policies point to; level AAA is a stricter, optional goal.

What you are checkingLevel AALevel AAAWCAG criterion
Normal body text4.5:17:11.4.3 and 1.4.6
Large text (about 24 px regular, or about 18.7 px bold)3:14.5:11.4.3 and 1.4.6
Icons, chart lines, input borders, focus rings3:1no extra AAA level1.4.11
Logos, disabled controls, pure decorationexempt1.4.3 exceptions

WCAG defines large text in points: at least 18 point, or 14 point bold. On the web 1 point is 1.333 CSS pixels, which is where the 24 px and 18.7 px figures come from. If you are not sure whether text counts as large, treat it as normal text and aim for 4.5:1.

How the contrast ratio is calculated

The ratio compares relative luminance, a measure of how bright a colour looks to the human eye on a scale from 0 (black) to 1 (white). It is not the same as the lightness slider in a design app, because our eyes are far more sensitive to green than to blue. The steps are:

  1. Turn the hex code into red, green and blue values from 0 to 255, then divide each by 255. For #767676 each channel is 118 ÷ 255 = 0.4627. Our colour converter shows the RGB values for any hex code, and the guide on converting hex to RGB explains the conversion by hand.
  2. Undo the screen gamma. For each channel value c: if c is 0.04045 or less, use c ÷ 12.92; otherwise use ((c + 0.055) ÷ 1.055) raised to the power 2.4. For 0.4627 that gives about 0.1812.
  3. Weight the channels: L = 0.2126 × R + 0.7152 × G + 0.0722 × B. Grey has equal channels, so L for #767676 is 0.1812. Pure white is 1 and pure black is 0.
  4. Divide: ratio = (lighter L + 0.05) ÷ (darker L + 0.05). The 0.05 accounts for light reflecting off a real screen, and it is why the maximum is 21:1 rather than infinite.

Worked example: the famous #767676 grey

Take grey text #767676 on a white #FFFFFF background. White has L = 1 and the grey has L = 0.1812, so the ratio is (1 + 0.05) ÷ (0.1812 + 0.05) = 1.05 ÷ 0.2312 = 4.54:1. That just passes AA for normal text. Move one step lighter to #777777 and luminance rises to 0.1845, giving 1.05 ÷ 0.2345 = 4.48:1, which fails. One notch on the colour picker is the difference between pass and fail, which is why you should always measure rather than eyeball. Here are a few more common pairs, all calculated with the WCAG formula and checked in our contrast checker:

TextBackgroundRatioAA normal textAAA normal text
#000000 black#FFFFFF white21:1PassPass
#333333 dark grey#FFFFFF12.63:1PassPass
#595959 grey#FFFFFF7.00:1PassPass
#767676 grey#FFFFFF4.54:1PassFail
#999999 light grey#FFFFFF2.85:1FailFail
#FFFFFF white#0066CC blue button5.57:1PassFail
#FFFFFF white#2E7D32 green button5.13:1PassFail
#FFFFFF white#FF8800 orange button2.39:1FailFail

The orange row surprises many designers: bright orange and yellow have high luminance, so white text on them almost always fails. Dark text (for example #000000 on #FF8800) works far better on warm, bright colours.

A quick routine for checking a whole page

  1. List your colour pairs, not just your colours. Body text on the page background, link colour on the background, button text on each button colour, placeholder text in inputs, text on cards or banners, and white text on any brand colour.
  2. Check each pair in the contrast checker. It shows the ratio, the AA and AAA result for normal and large text, and suggests a nearby colour that passes when a pair fails.
  3. Check the non-text parts: input borders, checkbox outlines, icons that carry meaning, chart lines and the keyboard focus outline all need 3:1 against what is next to them.
  4. Check every state: hover, focus, visited links, error messages and dark mode each create new colour pairs.
  5. Text on images or gradients: measure against the lightest part of the image behind light text, or the darkest part behind dark text. A semi-transparent dark overlay usually fixes photo backgrounds. If you build gradient backgrounds with our CSS gradient generator (see how to make a CSS gradient), test the text against both ends.
  6. Write the passing values down in your style guide or CSS variables so the next page does not reintroduce a failing grey.

How to fix a colour that fails

The quickest fix is to keep the hue and change only the lightness: darken the text or lighten the background until the ratio clears the target. Building a palette with our colour palette generator and then testing its darkest and lightest shades against each other gives you safe text and background pairs from the start. Making text bigger or bolder can also help, because large text only needs 3:1, but do not rely on size alone for long paragraphs. Finally, never use colour as the only signal: a red error border should come with an icon or a text message, because many people have some form of colour vision deficiency and many more read screens in poor light.

Common mistakes

Contrast is one of the cheapest accessibility wins: it costs nothing, helps everyone reading on a phone outdoors, and takes a few seconds per colour pair to verify. For more web basics, see our comparison of PNG, JPG and WebP image formats.

Frequently asked questions

What contrast ratio do I need for WCAG AA?

For normal text, at least 4.5:1. For large text (about 24 px regular or 18.7 px bold) and for meaningful icons, borders and focus indicators, at least 3:1.

What is the AAA contrast requirement?

Level AAA asks for 7:1 for normal text and 4.5:1 for large text. It is an optional, stricter target; most sites aim for AA and use AAA for long-form reading where possible.

Is #767676 accessible on white?

Yes, just. Grey #767676 on white has a contrast ratio of 4.54:1, which passes AA for normal text. One step lighter, #777777, gives 4.48:1 and fails.

Does contrast apply to logos and images?

Text that is part of a logo or brand name has no contrast requirement, and neither does purely decorative content. Text placed on top of a photo does count, so measure it against the part of the image directly behind it.

Why is the highest contrast ratio 21:1?

The formula adds 0.05 to both luminance values to allow for screen glare. Black has a luminance of 0 and white of 1, so the maximum is 1.05 ÷ 0.05 = 21.

Sources

More games

All games