Menu

CSS Color Contrast Text Generator

Pick a background color and get a readable text color that passes WCAG 2.2 AA or AAA, with CSS, relative color syntax, contrast-color() and JavaScript ready to copy.

Readable headline text

This is body copy at 16px. The generated text color keeps long paragraphs easy to read for everyone.

Small caption text at 13px is the first thing to fail on weak contrast.

0:1
WCAG 2 contrast ratio
0 Lc
APCA lightness contrast
#FFFFFF
Generated text color

        

Batch mode: text colors for a whole palette

✓ Copied!

What is a CSS color contrast text generator?

Last updated October 2026 · Reviewed against WCAG 2.2 and CSS Color Module Levels 4 and 5

Short answer: A CSS color contrast text generator takes a background color and returns a text color that meets a chosen contrast target, usually WCAG 2.2 AA (4.5:1 for normal text, 3:1 for large text) or AAA (7:1). It calculates the relative luminance of both colors, compares them with the WCAG formula and outputs CSS you can paste straight into your stylesheet.

Every interface has the same recurring problem: you know the background, and you need a foreground color that people can actually read. Brand blues, warm oranges, pastel cards and dark dashboards all need different text colors, and guessing rarely works. A color contrast text generator replaces guessing with arithmetic. You enter the background, the tool tests candidate text colors, and it keeps the one that passes your accessibility target.

The generator above goes further than a simple black-or-white switch. It can pick dark or light text from your own palette, build a tinted text color that keeps the hue of the background, or take your preferred text color and nudge its lightness until it passes. It reports the WCAG contrast ratio and the APCA Lc score, and it exports plain CSS, modern relative color syntax with contrast-color(), and a JavaScript helper. Batch mode produces text colors for a whole palette in one step.

In this guide

  1. Why text contrast matters
  2. How the WCAG contrast ratio works
  3. Contrast thresholds at a glance
  4. How to choose text color automatically
  5. CSS techniques for automatic text color
  6. APCA and the future of contrast
  7. Dark mode and light-dark()
  8. Common contrast mistakes
  9. Text over images and gradients
  10. Color blindness and low vision
  11. A testing workflow for teams
  12. Frequently asked questions
  13. Glossary

Why text contrast matters for readability, accessibility and conversions

Contrast is the difference in brightness between text and the surface behind it. When it is too low, letters blur into the background, reading slows down and errors increase. This affects far more people than most teams expect. Beyond people with low vision or color vision deficiency, it hits anyone using a phone in sunlight, an old laptop screen, a dimmed display to save battery, or simply tired eyes at the end of the day.

Low contrast is also one of the most common accessibility failures on the web. WebAIM's annual Million report, which scans the home pages of the top one million sites, has consistently found low-contrast text on roughly four out of five of them. That makes it the most frequently detected issue in automated audits, and also one of the cheapest to fix.

Business and legal reasons to care

  • Usability and conversion: readable calls to action, form labels and prices reduce friction. A pale button label that nobody notices costs clicks.
  • SEO and quality signals: accessible, readable pages tend to have better engagement, lower bounce and fewer usability complaints, which support organic performance indirectly.
  • Compliance: Section 508 in the United States, the European Accessibility Act (in application since June 2025) with EN 301 549, and many national laws reference WCAG, normally at level AA. In the United States, accessibility lawsuits under the ADA commonly cite WCAG AA as the yardstick.
  • Brand trust: an interface that is comfortable to read feels more professional and more inclusive.

The good news is that contrast is deterministic. Unlike many design questions, there is a formula, a clear threshold and a repeatable fix. That is exactly what a text color generator automates.

How the WCAG contrast ratio works

The Web Content Accessibility Guidelines (WCAG) define contrast through a ratio between the relative luminance of two colors. The result ranges from 1:1 (identical colors, no contrast) to 21:1 (pure black on pure white).

Step 1: convert sRGB values to linear light

Screens store colors in sRGB, which applies a gamma curve. To measure light accurately, each red, green and blue channel (0 to 255) is divided by 255 and then linearized. Values at or below 0.03928 are divided by 12.92, and larger values use ((value + 0.055) / 1.055) ^ 2.4.

Step 2: calculate relative luminance

Relative luminance combines the linear channels using weights that reflect how the human eye responds to each primary:

L = 0.2126 * R + 0.7152 * G + 0.0722 * B

Green dominates because our eyes are most sensitive to it, while blue contributes very little. This is why a saturated blue such as #0000FF looks dark and takes white text easily, while pure green looks bright and needs dark text.

Step 3: compare the two luminances

contrast = (L_lighter + 0.05) / (L_darker + 0.05)

The 0.05 term models ambient light reflecting off the screen. Black on white gives (1 + 0.05) / (0 + 0.05) = 21. Medium gray #767676 on white gives about 4.54, which is why it is the lightest neutral gray that passes AA on a white page.

A useful consequence: the ratio does not depend on which color is the text and which is the background. Swapping them gives the same number. That symmetry is a known limitation of WCAG 2, and it is the main reason APCA was developed.

WCAG 2.2 contrast thresholds at a glance

Content typeLevel AALevel AAASuccess criterion
Normal text (below 24px regular or 18.66px bold)4.5:17:11.4.3 and 1.4.6
Large text (at least 24px regular or 18.66px bold)3:14.5:11.4.3 and 1.4.6
UI components and graphical objects (borders, icons, focus rings)3:1No AAA requirement1.4.11 Non-text Contrast
Inactive controls, pure decoration, logotypesExemptExempt1.4.3 exceptions

Large text is defined as 18 point (24 CSS pixels) or 14 point bold (about 18.66 CSS pixels bold) and above. The ratio is not rounded up: 4.49:1 fails the 4.5:1 requirement, which is why the generator displays the floored value rather than a rounded one.

Remember criterion 1.4.1 (Use of Color) as well: contrast alone is not enough if color is the only way to tell links from body text or errors from success states. Add underlines, icons or labels.

How to choose text color automatically for any background

There are several ways to decide between light and dark text. They differ in accuracy, and the differences matter for mid-tone backgrounds.

The luminance method (accurate)

Compute the contrast ratio of the background against black and against white, then keep the higher one. The crossover can be derived exactly: set (1.05) / (L + 0.05) equal to (L + 0.05) / 0.05, and L comes out at about 0.179. A background with relative luminance above 0.179 is better served by black text, and anything below it by white text. This is the method behind the Auto mode in the generator, which also lets you replace pure black and white with softer options such as #111827.

The YIQ shortcut (fast but approximate)

Many snippets compute (R * 299 + G * 587 + B * 114) / 1000 and compare it with 128. This works for obvious cases but ignores gamma, so it can choose the lower-contrast option on saturated mid-tones such as orange, medium red and some teals. If you care about passing audits, prefer the luminance method.

HSL lightness (unreliable)

HSL lightness is not perceptually uniform. Yellow and blue with the same HSL lightness have radically different luminance. Avoid it as a contrast predictor.

OKLCH lightness (good for generating and shifting colors)

OKLCH separates perceptual lightness (L), chroma (C) and hue (H). That makes it ideal for tinted text: keep the hue of the background, hold chroma low, and move L away from the background until the target ratio is met. The generator tries both directions, lighter and darker, and keeps the smaller change.

When no color can pass

Some backgrounds cannot reach 4.5:1 with any text color. The worst case is a mid-gray near luminance 0.18, where both black and white give only around 4.6:1 at best, and a saturated mid-tone can fall below that. If the generator reports that the target is unreachable, change the background rather than the text.

CSS techniques for automatic text color

Modern CSS can now pick readable text color without JavaScript. Here are the options from most compatible to most future-proof.

1. Static values

The simplest and most robust approach is a fixed pair, ideally stored as design tokens or CSS custom properties:

.button-primary {
  background-color: #2563EB;
  color: #FFFFFF; /* 5.17:1, AA pass */
}

2. Relative color syntax

CSS Color Level 5 relative color syntax lets you read the channels of one color and build another. A known pattern chooses black or white from lightness:

.card {
  --bg: #2563EB;
  background-color: var(--bg);
  color: oklch(from var(--bg) clamp(0, (l - 0.62) * -1000, 1) 0 0);
}

When the lightness l is above 0.62 the expression goes negative and clamps to 0 (black). Below it, the value is large and clamps to 1 (white). The multiplier of 1000 simply makes the switch abrupt. Because OKLCH lightness is only an approximation of luminance, the best switch point varies slightly with hue, so test your brand colors. The generator warns you when the shortcut picks a lower-contrast option than the exact method. Relative colors are supported in current Chrome, Safari and Firefox releases, so keep a fallback.

3. The contrast-color() function

contrast-color() is designed to return a color with maximum contrast against the one you give it, so you do not need clamp tricks. Browser support is still arriving, which makes progressive enhancement the right approach:

.card {
  background-color: var(--bg);
  color: #FFFFFF; /* fallback */
}
@supports (color: contrast-color(red)) {
  .card { color: contrast-color(var(--bg)); }
}

4. color-mix() for tints and hover states

Use color-mix(in oklch, var(--bg) 85%, black) to derive a darker hover color, then re-check that the text still passes on the new background. Hover, active and focus states are frequently forgotten in audits.

5. JavaScript helper

When colors come from a CMS, a user profile or an API, compute the text color at runtime with the luminance method. The generator exports a ready-made getContrastText() function. Set the result as an inline style or a CSS variable, for example element.style.setProperty('--on-bg', getContrastText(color)).

6. Design tokens, Sass and Tailwind

In design systems, store paired tokens such as --color-primary and --color-on-primary so every surface has a guaranteed readable counterpart. In Tailwind CSS, generate the pair once and reference it as bg-brand text-on-brand through your theme. In Sass, a build-time function can compute the pair when the stylesheet compiles, which removes any runtime cost.

APCA and the future of contrast: WCAG 2 versus WCAG 3 drafts

The Accessible Perceptual Contrast Algorithm (APCA) is the contrast method proposed for the WCAG 3 working drafts. Instead of a ratio, it outputs a lightness contrast value, Lc, roughly from 0 to 108 in absolute terms. It is polarity aware: dark text on a light background and light text on a dark background produce different scores, because the eye perceives them differently.

APCA also ties the required Lc to font size and weight. Commonly cited guidance is Lc 90 for comfortable long-form reading, around Lc 75 as a practical minimum for body text, Lc 60 for content text such as short labels, Lc 45 for large headlines, and Lc 30 for spot text such as placeholders. These are simplified levels rather than the full lookup table.

Why show both numbers? WCAG 2.2 is what auditors, regulators and procurement documents reference today, so you need to pass it. APCA is a valuable second opinion, especially for catching pairs that squeak past 4.5:1 yet feel weak, such as mid-gray text or light text on saturated mid-tone buttons. The generator displays both so you can design for real readers while staying compliant.

Dark mode, light-dark() and theme-aware text colors

Dark mode is not just an inverted palette. Pure white text on pure black can cause halation and eye strain for some readers, and saturated colors that pass in light mode may fail on dark surfaces. Test both themes separately.

The CSS light-dark() function lets one declaration hold two values: color: light-dark(#111827, #F9FAFB). It follows the used color-scheme, so it responds to the operating system preference or a manual toggle. Combine it with relative colors so each surface derives its own readable text from its own background.

Also respect user preferences. The prefers-contrast: more media query lets you raise contrast for people who ask for it, and forced-colors: active (Windows High Contrast) overrides your palette, so never rely on background color alone to convey information.

Common contrast mistakes and how to avoid them

  • Light gray body text. #999 on white is only 2.85:1. Use #767676 or darker for secondary text.
  • White text on bright brand colors. Orange, amber, lime and many teals look strong with white text but frequently land under 3:1. Use dark text instead, or darken the background.
  • Placeholder text. Placeholders are text and must reach 4.5:1 to be accessible, even though browsers default to lighter gray.
  • Ignoring states. Check hover, focus, active, visited links, selected tabs and error messages, not only the default state.
  • Opacity on text. opacity: 0.6 or rgba text lowers the final ratio. Test the blended result.
  • Trusting your own eyes. Good monitors and bright rooms hide problems. Measure instead.
  • Forgetting non-text elements. Input borders, icons, chart lines and focus indicators need 3:1 against their surroundings.
  • Relying on color alone. Pair color with underline, icon or text so meaning survives for color blind users.

Text over images, videos and gradients

Backgrounds that change across the text area are the hardest case, because a single ratio does not exist. Use one of these patterns:

  1. Solid panel: place text in a card with a solid or near-solid background and test that color.
  2. Gradient overlay: add a dark or light gradient behind the text, such as linear-gradient(to top, rgb(0 0 0 / .65), transparent), and measure the lightest point of the image under the weakest part of the overlay.
  3. Uniform scrim: a flat overlay at 40 to 60 percent opacity is predictable and easy to verify by blending the colors.
  4. Text shadow as a helper only: a shadow can soften busy edges, but it is not a substitute for adequate base contrast.

For gradients, test the text against the nearest and farthest stops and any mid-point where the text crosses a color shift. Use the batch mode above to check several stops at once.

Color blindness, low vision and contrast

Roughly 1 in 12 men and 1 in 200 women have some form of color vision deficiency, most commonly red-green (protanopia and deuteranopia). Blue-yellow (tritanopia) and total color blindness (achromatopsia) are rarer. Luminance contrast is the most reliable aid for all of them, because brightness differences are perceived even when hues are confused.

Two practical rules help. First, make sure text passes by luminance, not just hue difference: red on green can look vivid yet have almost identical luminance. Second, never encode status only with red and green. Combine color with icons, patterns or text labels. Low vision users who zoom or increase font size also benefit when contrast is generous, so aim above the minimum whenever the design allows.

A practical workflow to keep contrast accessible

  1. Define tokens. For each surface define a paired text token, for example --surface and --on-surface.
  2. Generate pairs. Use this generator in batch mode to compute the text color for every background in your palette at your target level (AA for most products, AAA for long-form reading).
  3. Verify in context. Test real components in light and dark themes, with all interaction states.
  4. Automate checks. Add axe-core, Lighthouse or Pa11y to continuous integration so regressions fail the build. Automated tools catch many contrast failures but not text over images, so keep manual review.
  5. Review with browser DevTools. Chrome, Edge and Firefox display contrast ratios in the color picker and highlight failing text in their accessibility panels.
  6. Document decisions. Record approved pairs in your design system so designers and developers do not reinvent them.

How this generator calculates its results

The tool runs entirely in your browser. It linearizes sRGB channels, computes WCAG 2 relative luminance with the standard 0.2126, 0.7152 and 0.0722 weights, and compares ratios without rounding up. Tinted and adjusted colors are generated in OKLCH with gamut mapping, then verified with the same WCAG formula. APCA scores use the published 0.0.98G constants. No colors are uploaded or stored.

Frequently asked questions about contrast and text color

What is a CSS color contrast text generator?

A CSS color contrast text generator takes a background color and returns a text color with enough contrast to be readable. It calculates the WCAG contrast ratio between the two colors and outputs CSS you can paste into a project. Most tools aim for WCAG 2.2 AA, which needs at least 4.5:1 for normal text.

What contrast ratio do I need for readable text?

For WCAG 2.2 level AA, normal text needs 4.5:1 and large text needs 3:1. For level AAA, normal text needs 7:1 and large text needs 4.5:1. Large text means at least 24px regular or about 18.66px bold. User interface components and meaningful graphics need 3:1 against adjacent colors.

Should I use black or white text on my background?

Use whichever gives the higher contrast ratio. Mathematically, the switch happens at a relative luminance of about 0.179. Backgrounds lighter than that work best with black or very dark text, and darker backgrounds work best with white text. Mid-tone colors such as medium blue or orange are the tricky ones, so always check the actual ratio.

How do I automatically choose text color in CSS?

You have three options. The first is relative color syntax, for example color: oklch(from var(--bg) clamp(0, (l - 0.62) * -1000, 1) 0 0), which switches between black and white by lightness. The second is the contrast-color() function from CSS Color Level 5, where browsers support it. The third is a small JavaScript function that compares contrast ratios. Always keep a static fallback color.

Does the CSS contrast-color() function work in all browsers?

Not yet everywhere. contrast-color() is part of the CSS Color Module Level 5 and support is still rolling out, so check current browser compatibility tables before relying on it. Wrap it in an @supports rule and keep a static text color as a fallback so older browsers still show readable text.

What is the difference between WCAG contrast and APCA?

WCAG 2 uses a simple luminance ratio from 1:1 to 21:1 and treats light-on-dark and dark-on-light the same. APCA, the algorithm proposed for WCAG 3, produces a Lc score that depends on polarity, font size and weight. APCA is often stricter for light text on dark backgrounds, but WCAG 2.2 remains the accepted legal and compliance standard today.

Is color contrast a legal requirement?

In many places it is effectively required. Section 508 in the United States, the European Accessibility Act and EN 301 549 in the European Union, and many national laws point to WCAG, usually level AA. The ADA has no technical standard of its own, but courts and settlements frequently use WCAG AA as the benchmark. This is general information and not legal advice.

Why does my text fail contrast even though it looks fine to me?

Perception varies with screen quality, brightness, ambient light, age and vision conditions such as low vision or color blindness. Your eyes also adapt to what you see all day. A measured ratio removes the guesswork, and a pair that looks acceptable on a bright designer monitor can be hard to read on a phone outdoors.

Can I use opacity or gray text and still pass contrast?

Yes, but test the final blended color rather than the original. Opacity mixes the text color with the background, which lowers the ratio. Light gray text such as #999999 on white is only 2.85:1 and fails. The lightest gray that passes AA on a white background is #767676 at about 4.54:1.

How do I check text contrast over an image or gradient?

Test the worst-case spot where the text sits on the lightest or darkest part of the image. A reliable fix is a semi-transparent overlay behind the text, or placing the text on a solid panel. Then measure the contrast between the text and the blended overlay color, not the raw photo.

Do disabled buttons and logos need to meet contrast rules?

WCAG exempts inactive user interface components and logotypes from the text contrast minimum. That does not mean disabled controls should be unreadable. Aim for around 3:1 so people can still see what is there, and make sure the disabled state is not communicated by color alone.

Which color space is best for generating accessible text colors?

OKLCH is a strong choice because its lightness channel is perceptually uniform, so equal steps in lightness look like equal steps to the eye. HSL lightness is not uniform, which means two colors with the same HSL lightness can have very different contrast. Use OKLCH to generate candidates and the WCAG formula to verify them.

Glossary of color contrast terms

  • Contrast ratio: the WCAG measure of luminance difference between two colors, from 1:1 to 21:1.
  • Relative luminance: the perceived brightness of a color on a 0 to 1 scale, based on linearized sRGB.
  • Foreground and background color: the text (or icon) color and the surface behind it.
  • Gamma and linearization: the conversion from stored sRGB values to physical light intensity.
  • APCA and Lc: a perceptual contrast model and its score, proposed for WCAG 3.
  • OKLCH: a perceptually uniform color space with lightness, chroma and hue, supported in modern CSS.
  • Relative color syntax: the CSS from keyword that derives a new color from an existing one.
  • Large text: 24px regular or 18.66px bold and above, which has a lower required ratio.
  • Non-text contrast: the 3:1 requirement for icons, input borders and focus indicators.
  • Design tokens: named, reusable values such as --on-primary that keep color decisions consistent.

Key takeaways

  • Aim for at least 4.5:1 for normal text and 3:1 for large text and UI components (WCAG 2.2 AA).
  • Black text wins above a relative luminance of about 0.179, white text wins below it.
  • Verify with the luminance formula rather than YIQ shortcuts or HSL lightness.
  • Use OKLCH to generate tinted text, then verify with WCAG.
  • Keep a static fallback when using relative color syntax or contrast-color().
  • Test every state, both themes and text over images with an overlay.
  • Treat APCA as a helpful second opinion and WCAG 2.2 as the compliance baseline.

Use the generator at the top of this page whenever you pick a new background color. It takes seconds, and it keeps your interface readable for everyone.