WCAG Color Contrast Ratio Calculator

Enter a foreground and a background colour and this calculator returns the WCAG contrast ratio between them, the relative luminance of each, and a pass or fail against every contrast success criterion in WCAG 2.2 — 1.4.3 Contrast (Minimum) at Level AA, 1.4.6 Contrast (Enhanced) at Level AAA, and 1.4.11 Non-text Contrast for interface components and graphics. When a pair falls short it also proposes the nearest lighter or darker version of your foreground that clears the threshold, so you can fix the problem without abandoning the colour.

Calculator

This calculator runs in your browser. Enable JavaScript for live results — the inputs, formula and worked example below remain fully readable without it.

Inputs this calculator takes, with typical values
InputWhat to enterExample
Foreground colourThe text or icon colour, as three or six hex digits with or without a leading hash.#767676
Background colourThe colour directly behind the foreground, after any overlay or gradient is flattened.#FFFFFF
What is being colouredWCAG applies a different threshold to each: the size cut-off is 18 point / 14 point bold, which is 24 px / 18.66 px.Normal text — under 24 px, or under 18.66 px bold
Conformance level you are aiming forSets the target the suggested replacement colour has to reach. Most legal and procurement requirements cite AA.Level AA

It returns

  • Contrast ratio — Ranges from 1:1 for identical colours to 21:1 for black against white.
  • Level AA result — Against the threshold for the content type you selected.
  • Level AAA result
  • Ratio required at your chosen level
  • Nearest passing foreground — Your foreground pushed toward white or black until it clears the target, keeping the background fixed.
  • Foreground relative luminance
  • Background relative luminance

The formula

C=L1+0.05L2+0.05
L=0.2126Rlin+0.7152Glin+0.0722Blin

In plain text: contrast = (L_lighter + 0.05) / (L_darker + 0.05)

  • CContrast ratio, between 1 and 21 (:1)
  • L₁Relative luminance of the lighter colour (0–1)
  • L₂Relative luminance of the darker colour (0–1)
  • 0.05Ambient flare term, standing in for light reflected off the screen surface (luminance)

Relative luminance is computed on linearised sRGB channels: c ≤ 0.03928 ? c/12.92 : ((c + 0.055)/1.055)^2.4, then weighted 0.2126 red, 0.7152 green, 0.0722 blue.

Updated Category Digital Media, Display & Color Verified against published test cases Reading time 11 min

What the WCAG contrast ratio measures

The contrast ratio compares how much light two colours emit, on a scale that runs from 1:1 for two identical colours to 21:1 for black against white. It is the quantity the Web Content Accessibility Guidelines use to decide whether text is readable, and it is written into procurement rules and accessibility law in many jurisdictions through WCAG conformance requirements.

The ratio deliberately ignores hue. Two colours can be violently different — bright red and bright green, say — and still fail, because what matters for reading is the difference in luminance, not in colour. Red at #FF0000 and green at #00FF00 differ by every hue measure you could name, yet their contrast ratio is only 2.91:1, which fails for body text. That is also why contrast-based design serves people with colour vision deficiencies: a luminance difference survives any colour-blindness simulation, while a hue difference may not.

Three success criteria use the ratio. SC 1.4.3 Contrast (Minimum), Level AA, requires 4.5:1 for normal text and 3:1 for large text. SC 1.4.6 Contrast (Enhanced), Level AAA, raises those to 7:1 and 4.5:1. SC 1.4.11 Non-text Contrast, Level AA, requires 3:1 for the visual information needed to identify user interface components and states, and for graphics needed to understand content. All three carry exemptions: incidental text, text in a logotype, inactive controls and purely decorative graphics are out of scope.

“Large text” has a precise definition: at least 18 point, or at least 14 point if bold. At the standard 96 dpi mapping that is 24 CSS pixels, or 18.66 CSS pixels bold.

The formula and the two things people get wrong in it

The ratio itself is simple: C = (L₁ + 0.05) / (L₂ + 0.05), where L₁ is the larger of the two relative luminances and L₂ the smaller. Because the larger always goes on top, the ratio is symmetric — swapping foreground and background changes nothing.

The first thing people get wrong is skipping the linearisation. Screen colour values are gamma-encoded, so #808080 is not half as bright as white; it is about 21.6% as bright. Before weighting the channels you must undo that encoding: c_lin = c/12.92 when the normalised channel is at or below 0.03928, and ((c + 0.055)/1.055)^2.4 otherwise. Then relative luminance is L = 0.2126·R + 0.7152·G + 0.0722·B on the linearised values. Those weights are the sRGB luminance coefficients, and they are why green dominates: green light contributes more than seven times what an equal amount of blue does.

The second is forgetting the 0.05. It is added to both luminances and it is not a fudge factor — it stands in for ambient light reflecting off the screen surface, which never lets a real black be truly black. It also keeps the formula from dividing by zero when one colour is pure black, and it is why the maximum possible ratio is 21 rather than infinity: (1 + 0.05) ÷ (0 + 0.05) = 21.

One consequence worth internalising: the 0.05 compresses contrast at the dark end. Moving a dark grey a little darker buys much more ratio than moving a light grey a little lighter, because the denominator is small. That is why dark themes are harder to get right — small luminance changes swing the ratio a long way.

Worked example: is #767676 grey readable on white?

Grey #767676 on a white #FFFFFF background is the classic borderline case, so it is worth working through by hand.

  1. Read the channels. 0x76 = 7×16 + 6 = 118, so the foreground is rgb(118, 118, 118). The background is rgb(255, 255, 255).
  2. Normalise the foreground. 118 ÷ 255 = 0.462745 on all three channels.
  3. Linearise. 0.462745 is above 0.03928, so use the power branch: (0.462745 + 0.055) ÷ 1.055 = 0.490754, and 0.4907542.4 = 0.181240.
  4. Weight the channels. All three are equal, and 0.2126 + 0.7152 + 0.0722 = 1, so the foreground luminance is just 0.18124.
  5. Background luminance. Each channel normalises to 1.0, linearises to 1.0, so L = 1.0000.
  6. Add the flare term. Lighter: 1.0000 + 0.05 = 1.05. Darker: 0.18124 + 0.05 = 0.23124.
  7. Divide. 1.05 ÷ 0.23124 = 4.54:1.

4.54 clears the 4.5:1 required by SC 1.4.3 for normal text, with 0.04 to spare — which is why #767676 is the lightest neutral grey that passes on white, and why #777777 (4.48:1) does not. It fails SC 1.4.6 at Level AAA, which wants 7:1. Nudging the foreground to #595959 gives 7.00:1 and clears AAA for normal text.

Compare a mid grey, #808080: 128 ÷ 255 = 0.501961, linearised 0.215861, so the ratio against white is 1.05 ÷ 0.265861 = 3.95:1. That passes SC 1.4.3 for large text and for UI components, and fails it for body copy — a single colour landing on both sides of the line depending on where you use it.

How to read the result

Compare against the threshold that matches the element, not against a single number you remember. Body text needs 4.5:1. A 24-pixel heading needs 3:1. The border of a text input, the fill of a checked checkbox, the line in a chart that carries meaning: all 3:1 under SC 1.4.11. Placeholder text is still text and still needs 4.5:1, which is where a great many designs fail.

Treat the thresholds as floors rather than targets. 4.5:1 was chosen to approximate the readability that a person with 20/40 vision gets from a 7:1 contrast at normal acuity, so a pair that lands at 4.51:1 is genuinely marginal for a reader with low vision, on a dim laptop screen, in sunlight. Where you have room, aim higher — especially for long-form reading.

Do not read the ratio as a perceptual scale. The gap between 3:1 and 4.5:1 looks larger to a reader than the gap between 15:1 and 21:1, because the flare term compresses the top of the range. A design that moves from 12:1 to 18:1 has gained almost nothing anyone will notice; one that moves from 2.5:1 to 4.5:1 has changed the page.

Watch for the two situations the ratio cannot see. First, semi-transparent colours: a foreground at 60% opacity has to be composited against whatever is actually behind it before the contrast is meaningful, so flatten the stack and enter the resulting colour. Second, gradients and images behind text: the correct approach is to test the worst point, not an average, because a reader encounters the whole area. Neither case is a defect in the formula — it is a reminder that contrast is a property of the rendered pixels.

WCAG contrast thresholds and what they apply to

Every contrast requirement in WCAG 2.2, with the ratio each demands.
Success criterionLevelApplies toRequired ratio
1.4.3 Contrast (Minimum)AANormal text and images of text4.5:1
1.4.3 Contrast (Minimum)AALarge text: 18 pt / 24 px, or 14 pt / 18.66 px bold3:1
1.4.6 Contrast (Enhanced)AAANormal text and images of text7:1
1.4.6 Contrast (Enhanced)AAALarge text4.5:1
1.4.11 Non-text ContrastAAUI component states and boundaries3:1
1.4.11 Non-text ContrastAAGraphics required to understand content3:1

Exemptions: incidental text, text in a logotype or brand name, inactive user interface components, and purely decorative graphics. Both 1.4.3 and 1.4.6 also exempt text that is part of a picture containing significant other visual content.

Neutral greys on white, and where each one stops passing

Contrast ratio against #FFFFFF for a range of neutral greys, computed with the formula above.
GreyChannel valueRelative luminanceRatio on whiteHighest criterion it meets
#00000000.000021.00:1AAA normal text
#404040640.051310.37:1AAA normal text
#595959890.10007.00:1AAA normal text
#6B6B6B1070.14725.33:1AA normal text
#7676761180.18124.54:1AA normal text
#8080801280.21593.95:1AA large text and UI
#9494941480.29613.03:1AA large text and UI
#9999991530.31852.85:1None
#CCCCCC2040.60381.61:1None

#767676 is the lightest grey that reaches 4.5:1 on white, and #949494 the lightest that reaches 3:1. One step lighter in each case drops below the line.

Mistakes that produce a false pass

  • Testing against the page background instead of the actual background. A card, a hover state or a translucent overlay changes the colour behind the text. Flatten what is really rendered and test that.
  • Ignoring placeholder and helper text. Both are text under SC 1.4.3 and both need 4.5:1. Light-grey placeholders are one of the most common failures in shipped forms.
  • Forgetting the focus indicator and the component border. SC 1.4.11 covers the boundary that identifies a control and the visual state that shows it is checked or selected, at 3:1 against the adjacent colour.
  • Assuming a hue change is enough. Red on green fails at 2.91:1 despite being maximally different in hue, because contrast is a luminance comparison.
  • Rounding up to a pass. 4.49:1 is a fail. Tools that display one decimal place can hide the difference, so read at least two.
  • Testing only the light theme. The flare term compresses ratios at the dark end, so a palette that works on white often fails when inverted. Test every theme independently.
  • Treating contrast as the whole of readability. Font size, weight, line length, letter spacing and the background texture all matter. A 21:1 hairline typeface at 10 px is still hard to read.

Contrast is the last step of a colour workflow and the first step of an accessibility audit. If your palette is defined in HSL or HSV, convert it first — the HEX, RGB and HSL converter also reports the same relative luminance value this page uses, so you can carry it straight across. Nothing about lightness in HSL predicts contrast: hsl(60, 100%, 50%) and hsl(240, 100%, 50%) both claim 50% lightness while differing by a factor of nearly thirteen in luminance.

If text sits over an image or a letterboxed video, the bar colour and the picture edge both matter — the aspect ratio calculator tells you exactly where the bars fall, so you know which region the text will actually land on. And on a very high-density panel, thin type at small sizes renders with fewer effective luminance levels per stem; the pixel density calculator gives the density figure that decides how much antialiasing a glyph edge gets.

Use something other than this ratio when the question is about non-standard rendering. WCAG's formula assumes sRGB and a self-luminous display; it is not calibrated for print, for e-ink, or for wide-gamut content that has not been converted. The W3C is also developing a perceptually weighted successor algorithm intended to model dark themes and thin fonts better than the current ratio does, but as of WCAG 2.2 the formula on this page is the normative one, and it is what conformance is measured against.

Frequently asked questions

What contrast ratio do I need to pass WCAG?

4.5:1 for normal-size text and 3:1 for large text at Level AA, which is what almost every legal and procurement requirement cites. Level AAA raises those to 7:1 and 4.5:1. User interface components and meaningful graphics need 3:1 at Level AA under SC 1.4.11. Large text means 18 point or larger, or 14 point bold or larger — 24 px and 18.66 px in CSS.

Why is my bright red on bright green failing?

Because contrast measures luminance, not hue. Pure red has a relative luminance of 0.2126 and pure green 0.7152, giving (0.7152 + 0.05) ÷ (0.2126 + 0.05) = 2.91:1 — well under the 4.5:1 needed for body text. Two colours can be as different in hue as it is possible to be and still be nearly identical in brightness, which is exactly the situation a reader with a colour vision deficiency experiences all the time.

What is relative luminance?

It is the brightness of a colour on a 0-to-1 scale, computed by undoing the screen's gamma encoding on each channel and then weighting them 0.2126 red, 0.7152 green and 0.0722 blue. Black is 0 and white is 1. It is not the same as HSL lightness: #808080 has 50% HSL lightness but a relative luminance of only 0.216.

Why is 0.05 added to both luminances?

It models ambient light reflecting off the screen surface, which means no real display ever shows a perfectly black pixel. Adding it to both terms also caps the maximum ratio at 21:1 rather than infinity, and prevents a division by zero when one colour is pure black. Remove it and black on white would be undefined.

Does the order of the two colours matter?

No. The formula always puts the lighter luminance on top, so swapping foreground and background gives exactly the same ratio. What does change is the fix: to raise contrast you move the lighter colour toward white or the darker one toward black, and the calculator picks the direction that applies to your foreground.

How do I handle text over an image or a gradient?

Test the worst point, not an average. Sample the lightest pixel under light text or the darkest pixel under dark text and use that as the background colour. In practice most designs solve this with a solid scrim or a heavy blur behind the text, which turns the problem back into a two-colour comparison you can actually verify.

What about semi-transparent colours?

Flatten them first. A foreground at rgba(0, 0, 0, 0.6) over white renders as a specific opaque colour, and that composited value is what a reader sees and what you should enter. Contrast is a property of the pixels on screen, so any opacity, blend mode or backdrop filter has to be resolved before the ratio means anything.

Is a higher ratio always better?

Not automatically. Meeting the threshold is the requirement; going far beyond it has diminishing returns because the flare term compresses the top of the scale, and some readers with dyslexia or light sensitivity find pure black on pure white uncomfortable at 21:1. A common compromise is a very dark grey on an off-white, which lands comfortably above 12:1 while softening the glare.

Do disabled buttons need to meet the contrast requirement?

No. SC 1.4.3 exempts text that is part of an inactive user interface component, and SC 1.4.11 likewise does not apply to inactive components. That is a conformance exemption rather than a design recommendation — a disabled control that nobody can read is still confusing, so keeping it legible is good practice even where it is not required.

References