Colour contrast explained: WCAG ratios, readable text and colour formats
Text is readable when it stands out from its background, and the Web Content Accessibility Guidelines (WCAG) turn that into a number: the contrast ratio. WCAG 2.2, the current version, became a W3C Recommendation on 12 December 2024. This guide explains how the ratio is calculated, the thresholds that apply to text and to controls, and how the common ways of writing a colour relate to it.
How the contrast ratio is calculated
Each colour is turned into a relative luminance between 0 for black and 1 for white. The red, green and blue values are first converted back to light intensity, because sRGB values are not proportional to light: a value at or below 0.04045 (on a scale of 0 to 1) is divided by 12.92, and higher values follow a 2.4 power curve. Then the three are weighted by how bright the eye finds them: 0.2126 for red, 0.7152 for green and 0.0722 for blue. Before May 2021 the threshold was written 0.03928; the W3C notes that the change has no practical effect.
The ratio is (L1 + 0.05) ÷ (L2 + 0.05), with L1 the lighter colour. It runs from 1:1 for two identical colours to 21:1 for black on white. It is never rounded: WCAG’s own explanation says 4.499:1 does not meet 4.5:1, which is why checkers that round to one decimal can show a pass that is not one.
The thresholds
WCAG has three levels, A, AA and AAA; AA is the level most accessibility policies and audits aim for. Three success criteria set contrast minimums:
| Success criterion | Applies to | Minimum ratio | Level |
|---|---|---|---|
| 1.4.3 Contrast (Minimum) | Normal text | 4.5:1 | AA |
| 1.4.3 Contrast (Minimum) | Large text | 3:1 | AA |
| 1.4.6 Contrast (Enhanced) | Normal text | 7:1 | AAA |
| 1.4.6 Contrast (Enhanced) | Large text | 4.5:1 | AAA |
| 1.4.11 Non-text Contrast | Controls, focus rings, icons and parts of charts | 3:1 | AA |
Large text means at least 18 points, or 14 points in bold, which the W3C puts at about 24 and 18.5 CSS pixels. Text in a logo, text that is pure decoration and the text of disabled controls have no contrast requirement. Non-text contrast covers what you need to see to use a page: the boundary of a text field, a checkbox, the focus indicator, an icon without a label, the lines of a chart.
Which colours pass on white
Ratios against white, cut to two decimals as the checker shows them:
| Text / background | Ratio | What it passes |
|---|---|---|
| #000000 / #ffffff | 21:1 | The maximum: passes everything |
| #0000ff / #ffffff | 8.59:1 | Passes AAA for all text |
| #595959 / #ffffff | 7:1 | Exactly AAA for normal text |
| #767676 / #ffffff | 4.54:1 | Passes AA for normal text |
| #777777 / #ffffff | 4.47:1 | Fails AA for normal text; large text and graphics only |
| #ff0000 / #ffffff | 3.99:1 | Large text and graphics only |
| #949494 / #ffffff | 3.03:1 | Large text and graphics only |
| #959595 / #ffffff | 2.99:1 | Fails everything, even borders and icons |
| #ffff00 / #ffffff | 1.07:1 | Almost invisible |
#777777 and #767676 look identical, yet one fails and one passes: the line is that thin. Pure red, a common choice for errors, reaches only 3.99:1 on white, enough for an icon or large text but not for an error message in normal text; a slightly darker red such as #ee0000 reaches 4.53:1.
Why 4.5:1
The W3C explains that 4.5:1 compensates for the loss of contrast sensitivity that usually comes with vision of about 20/40, which is common with age, and 7:1 for vision of about 20/80. Good contrast also helps everyone else: a phone in sunlight, a cheap screen, a projector in a bright room.
Colour formats and what they tell you about contrast
#1a73e8, rgb(26 115 232), hsl(214 82% 51%) and oklch(57.4% 0.195 257.9) are the same blue written four ways. HEX and RGB give the red, green and blue amounts directly; HEX can add a fourth pair for transparency, as in #1a73e880 for 50%. HSL describes hue, saturation and lightness, but its lightness is not what the eye sees: yellow and blue at 50% HSL lightness are 96.8% and 45.2% in OKLCH lightness, which is why blue text passes on white and yellow fails.
OKLCH, from CSS Color Level 4, is built so that equal steps in lightness look like equal steps, which makes it the most useful format for designing a palette with predictable contrast. Browsers support it from Chrome and Edge 111, Firefox 113 and Safari 15.4, and it has been Baseline widely available since November 2025. Contrast is still calculated from the sRGB colour that is actually displayed, so check the final pair with a contrast checker.
Fixing a colour that fails
- Keep the hue and change the lightness: darken the text or lighten the background until the ratio passes. The checker suggests the nearest passing colour in the same hue.
- Check every state: hover, visited links, placeholders you rely on, disabled buttons you want people to notice, and dark mode, which has the same requirements.
- Measure text over an image or a gradient against its lightest area behind the text, or put the text on a solid panel.
- Do not rely on colour alone: WCAG 2.2 success criterion 1.4.1 asks for another cue, such as an underline for links or an icon and a word for errors.
Beyond WCAG 2
Drafts of WCAG 3 have experimented with a different contrast method, often called APCA, which accounts for font size and weight and treats light text on dark backgrounds differently. It is a draft, not a standard, so audits and laws still use the WCAG 2 ratio. In the European Union, the European Accessibility Act (Directive 2019/882) has applied since 28 June 2025 to many products and services, including e-commerce.
Frequently asked questions
Is 4.47:1 close enough to 4.5:1?
No. The ratio is not rounded, so 4.47:1 fails the 4.5:1 minimum for normal text. It still meets 3:1 for large text and for graphics.
What counts as large text?
At least 18 points, about 24 CSS pixels, or 14 points in bold, about 18.5 CSS pixels.
Do borders and icons need contrast?
Yes, when they are needed to understand or use the page: 3:1 against the colours next to them. A text field’s border, a checkbox and the focus indicator are examples.
Does dark mode change the rules?
No. The same ratios apply to every colour scheme, so check the dark palette as well.
Does a higher ratio always read better?
Up to a point. Very high contrast, such as pure white on pure black, can feel harsh to some readers; anything from 7:1 up is comfortable for most text.
References
- W3C — Web Content Accessibility Guidelines (WCAG) 2.2, W3C Recommendation, 12 December 2024
- W3C WAI — Understanding Success Criterion 1.4.3: Contrast (Minimum)
- W3C WAI — Understanding Success Criterion 1.4.11: Non-text Contrast
- W3C — CSS Color Module Level 4
- Web platform features explorer — oklab() and oklch()
- Directive (EU) 2019/882 on the accessibility requirements for products and services (European Accessibility Act)
Related guides
- IP addresses explained: IPv4, IPv6 and the reserved ranges
- Subnets and CIDR explained: prefixes, masks and usable hosts
- DNS records explained: A, AAAA, CNAME, MX, TXT and NS
- Is a website down, or is it just you? How to check, step by step
- HTTP status codes and Cloudflare errors: what 403, 404, 429, 500, 503 and 521 mean
- Unix timestamps and time zones explained
- Counting dates: days between dates, leap years and ISO weeks
- Time zones and daylight saving time: meetings across cities
- Image formats explained: JPEG, PNG, WebP, AVIF and HEIC
- Image size explained: pixels, DPI, file size and quality
- Phone photos explained: HEIC, EXIF metadata and your privacy
- Password strength explained: length, entropy and passphrases
- Hash functions explained: SHA-256, checksums and password hashing
- JSON Web Tokens explained: claims, signatures and safe validation
- API keys explained: length, format, storage and rotation
- UUIDs explained: v4, v7 and choosing the right version
- QR codes explained: capacity, error correction and print size
- Percentages and VAT explained: adding, removing and stacking
- Common JSON errors and how to fix them
- CSV files explained: delimiters, quotes, encoding and Excel
- Text encodings explained: UTF-8, Base64 and URL encoding
- Regular expressions explained: classes, quantifiers and groups
- MB or MiB, Mbps or MB/s: file sizes and speeds explained
- Cron expressions explained: fields, steps and time zones
- UTM parameters explained: tagging links that analytics can read
- Break-even, margin and ROAS explained: the numbers behind a small business
- Freelance rates explained: hourly rate, day rate and billable hours
- Editing PDFs in the browser: what merging, splitting and converting keep