Accessibility & Design • 9 min read

Color Contrast Ratios: What 4.5:1 Measures and How to Pass

A contrast ratio is not an opinion about whether text is readable; it is one arithmetic expression applied to two colours, and the same answer comes out wherever you compute it. Here is that expression, the thresholds it is compared against, measured numbers for the pairs that fail most often, and what the ratio still cannot tell you.

The Ratio Is Luminance Arithmetic

WCAG 2.x compares the relative luminance of two colours. Relative luminance is not brightness as you might eyeball it: each 8-bit sRGB channel is normalised to a 0 to 1 value, then linearised out of the gamma the file stores. The rule the specification gives, and the one this checker implements, is that a channel value at or below 0.03928 divides by 12.92, and anything above it becomes ((C + 0.055) / 1.055) raised to the power 2.4.

Those three linear channels are then weighted by how sensitive the average human eye is to each wavelength in daylight: 0.2126 for red, 0.7152 for green and 0.0722 for blue. Green dominates because the photopic response curve peaks near it, which is why a saturated green and a saturated blue built from identical numbers are not equally bright.

The ratio is the lighter luminance plus 0.05, divided by the darker luminance plus 0.05. That 0.05 models ambient flare on a real display, and it is the reason pure black on pure white comes out at 21:1 rather than infinity. It also means every ratio in a conformance report is a number between 1 and 21, and a pair that fails does so by arithmetic, not by taste.

  • `#000000` on `#ffffff` is 21:1, the ceiling of the scale.
  • `#0f172a` on `#ffffff` is 17.85:1, which is why a near-black ink on white is almost always safe.
  • `#64748b` on `#ffffff` is 4.76:1, clearing the 4.5:1 bar for normal text.
  • `#94a3b8` on `#ffffff` is 2.56:1, and this is the shade most design systems use for secondary text.
  • `#7c3aed` on `#ffffff` is 5.70:1: a pass at AA for normal text and a fail at AAA, which needs 7.0:1.

Which Threshold Applies to Which Element

There is no single pass mark. WCAG sets five different ones and the one that applies depends on what the pixel is doing. Body copy is judged at 4.5:1 for Level AA and 7.0:1 for AAA. Large text is judged more leniently, at 3.0:1 and 4.5:1, because bigger glyph shapes survive a thinner stroke. Interface components and graphical objects, the category covering input borders, toggle outlines and icons that carry meaning, need 3.0:1 against whatever sits next to them.

Large text has a hard definition rather than a feel: 18 point or 24 pixels at normal weight, or 14 point or 18.66 pixels when bold. A heading at 22 pixels that is not bold is normal text for this purpose, and 4.5:1 applies even though it looks big on the page.

The five contrast thresholds in WCAG 2.1 and which elements each one governs
ElementLevel AALevel AAANotes
Normal text4.5:17.0:1Anything below 24px, or below 18.66px when bold
Large text3.0:14.5:118pt or 24px, or 14pt bold or 18.66px bold
Interface components3.0:1not definedSC 1.4.11: input borders, toggles, meaningful icons
Placeholder text4.5:17.0:1It is text; the fact that it disappears does not exempt it
Focus indicator3.0:1not definedAgainst the adjacent background it sits on

Note: The checker tests all five of these and reports them separately, because a pair that clears normal-text AA and fails large-text AA is not a thing, but a pair that clears large-text AA and fails normal-text AA is the most common finding in a real audit.

Measured Numbers for Pairs People Actually Ship

Every ratio below was computed with the same linearisation and weighting the checker uses, so they are reproducible rather than remembered. The verdict column applies Level AA, which is the level commercial accessibility obligations usually reference.

Two of these are worth staring at. `#767676` on white clears 4.5:1 at 4.54:1; `#777777` on white misses at 4.48:1. One unit of grey separates a pass from a fail, which is the clearest possible argument for measuring instead of eyeballing. `#595959` lands on exactly 7.0:1, the AAA line for normal text.

Contrast ratios for common text and background pairs, measured with the WCAG formula
ForegroundBackgroundRatioAA normal textAA large text
`#0f172a``#ffffff`17.85:1passpass
`#595959``#ffffff`7.00:1passpass
`#64748b``#ffffff`4.76:1passpass
`#1a73e8``#ffffff`4.51:1pass, barelypass
`#767676``#ffffff`4.54:1passpass
`#777777``#ffffff`4.48:1failpass
`#7c3aed``#ffffff`5.70:1passpass
`#94a3b8``#ffffff`2.56:1failfail
`#d97706``#fffbeb`3.07:1failpass
`#166534``#dcfce7`6.49:1passpass
`#94a3b8``#0f172a`6.96:1passpass

Note: The last two rows are the point about dark mode. A mid-grey that fails badly on white passes at 6.96:1 on a dark slate, and a mint chip that passes on light needs re-checking the moment the same component is rendered on a dark surface. Light and dark schemes are two sets of measurements, not one set inverted.

The Six Places Contrast Actually Fails

Audits rarely find the headline colour broken. They find one of these six, and knowing the list saves the sweep.

  • Secondary and meta text. The grey chosen for captions, timestamps and table footnotes is the most frequent failure on the modern web, because 2.5:1 looks fine next to a swatch and fails as a sentence.
  • Placeholder text inside inputs, which is judged as text and usually sits at 1.6:1 to 2.5:1 in the browser default.
  • Disabled controls. WCAG exempts inactive components, so a greyed-out button is not a violation, but the label that stays readable next to it still has to pass.
  • Icon-only buttons and borders. Anything that is the only way to find the control falls under the 3.0:1 non-text rule; an icon that is decorative next to a visible label does not.
  • Text sitting on photography or gradients. One average ratio cannot describe a two-dimensional background, so put a solid scrim or a plate behind the type and measure against the scrim.
  • Focus rings. A ring that matches its own background is invisible to keyboard users, and the revision that followed WCAG 2.1 makes that requirement explicit for the indicator and for the colours next to it.

Fixing a Pair Without Redoing the Design

The ratio is driven mostly by the difference in lightness between the two colours, so the cheapest fix keeps the hue and moves one of them along the lightness axis. Darkening a failing text colour usually buys more margin than lightening the background, because the luminance weighting is steep near the white end and shallow in the middle greys, where most failures live.

  1. Measure the pair as it ships — Take the hex values from the rendered page, not from the design file. A component that inherits a different background at one breakpoint has two answers.
  2. Identify which rule applies — Normal text is 4.5:1, large text 3.0:1, an interface component 3.0:1. Aiming at the wrong target is how a design gets reworked twice.
  3. Move one colour, keep the other — The checker's auto-fix helper adjusts one colour's lightness until the pair clears the chosen target, which gives you a defensible value instead of a guess. Change both and the brand palette drifts with every fix.
  4. Re-check the neighbours — A darker text colour also changes what the same text does against a card background, an inset panel, and the hover state. Test each surface the component can appear on.
  5. Run the colour-vision simulations before you sign off — Protanopia, deuteranopia, tritanopia and a grayscale view are available on the checker, and the ratio is recomputed on the simulated pair. If meaning survives only in red versus green, that is a second finding to fix.

Note: Do not solve a contrast failure with transparency. Text at 80 percent opacity over white is not the hex you measured, and the value a conformance tool reads is the composited result, not the token in the stylesheet.

What the Ratio Does Not Cover

A passing number is necessary and not sufficient, and the honest list of what the ratio ignores belongs on the same page as the thresholds.

The ratio says nothing about stroke weight, x-height, or how long a line is. Small thin type at 4.6:1 is technically compliant and still hard to read; the guideline is a floor for people with moderate low vision, not a definition of comfortable.

It also does not measure colour as the only signal, which is a separate success criterion. Two states distinguished purely by fill can both pass contrast and still fail the requirement, because a screen reader and a large share of users never see the difference.

WCAG's own exemptions apply here too: logotypes and text inside images that are decorative are not subject to 1.4.3, and incidental text in a disabled control is out of scope. Judging whether something is incidental is a human decision, which is why the criterion is written as prose rather than a formula.

Finally, the model itself is under revision. APCA, the perceptual contrast algorithm developed later, models text on screen differently and produces different numbers for the same pair. This checker reports the WCAG 2.x calculation, which is the one conformance statements and procurement documents still reference, so quote the model when you quote the number.

Questions About WCAG Contrast Thresholds

Is 4.5:1 required for all text?

It is the Level AA requirement for normal-sized text, which means anything under 24 pixels at regular weight or under 18.66 pixels when bold. Large text is held to 3.0:1 at AA and 4.5:1 at AAA, and interface components to 3.0:1 with no AAA equivalent defined.

What is the contrast ratio of #777777 on white?

4.48:1, which fails the 4.5:1 requirement for normal text by the narrowest possible margin. #767676 on white measures 4.54:1 and passes, so one step of grey is the difference between a finding and a clean report.

Do icons need to pass contrast?

Only the ones that carry meaning on their own. An icon that is the only indication of a control, such as a trash can with no label, falls under the non-text requirement of 3.0:1. An icon placed next to a visible text label is decorative for this purpose.

Does dark mode need separate checking?

Yes. A pair measured on a light surface tells you nothing about the same tokens on a dark one, and a mid-grey that fails at 2.56:1 on white can pass at nearly 7:1 on a dark slate. Every component should be measured against both schemes, including its hover and selected states.

Is the formula on this checker the official one?

It implements the WCAG 2.x relative luminance definition exactly: channels normalised by 255, linearised at the 0.03928 breakpoint with the 12.92 divisor or the 2.4 exponent, weighted 0.2126, 0.7152 and 0.0722, then compared as (lighter + 0.05) over (darker + 0.05). Those are the same steps the W3C text gives, so the number matches other conforming tools.

What ratio should a focus indicator meet?

WCAG 2.1 requires 3.0:1 for the visual output of a user interface component under SC 1.4.11, and the revision that followed 2.1 adds a dedicated focus-appearance criterion measuring the indicator against both the adjacent unfocused state and the surrounding background. Building for 3.0:1 minimum is the practical answer; the checker's component row shows where you stand.

Where These Numbers Come From

Keep Reading

Three guides that pick up where this one leaves off: