Color Accessibility

Accessible Text on Colored Backgrounds, Images and Dark Mode

How to choose black or white text on any color, keep text readable over photos and gradients, and set up dark mode colors that stay comfortable and clear.

By ColorOverflow Editorial TeamUpdated November 13, 20267 min readIntermediate

Putting text on white is easy. The hard cases are everywhere else: a bright brand-colored banner, a hero photo, a gradient, or a dark theme. In each of them the background isn't simple, so the usual approach of checking one pair of colors either doesn't work or isn't enough.

This guide covers those cases. It assumes you know the contrast levels text needs; our guide to color contrast and WCAG explains them. Here the focus is on how to reach them when the background is colorful, busy or dark.

Read the full guideColor Contrast and WCAG: A Practical Guide

Black or white text on a colored background

For any background color, either black or white text will give you more contrast. Which one depends on the background's relative luminance, its perceived lightness, not on its hue. Bright yellows, oranges, greens, light blues and teals almost always want dark text. Deep blues, purples, reds and most dark colors want white.

  • Amber #F59E0B: 2.14:1 with white, 9.77:1 with black. Dark text, clearly.
  • Orange #F97316: 2.80:1 with white, 7.49:1 with black.
  • Sky blue #0EA5E9: 2.77:1 with white, 7.57:1 with black. Many people expect white here, but dark text wins.
  • Green #22C55E: 2.27:1 with white, 9.21:1 with black.
  • Blue #2563EB: 5.16:1 with white, 4.06:1 with black. White wins.

The surprises usually come from bright, saturated colors. They feel strong, so white text seems natural, but many of them are light in luminance terms. Trust the numbers over your instinct.

The awkward middle

There is a lightness at which black and white text give exactly the same contrast, and that contrast is only about 4.58:1. Colors near that point are the hardest to use: whichever text color you pick, you're close to the line. Red #EF4444 gives 3.76:1 with white and 5.58:1 with black. Violet #8B5CF6 gives 4.23:1 with white and 4.95:1 with black. Rose #E11D48 gives 4.69:1 with white and 4.47:1 with black.

With a mid-tone like these, don't choose between two weak options. Move the background a step darker so white text passes comfortably, or a step lighter so dark text does. A shade scale makes it easy to find the step you need while keeping the same hue.

Shades & TintsTurn one color into a full scale of lighter and darker versions.

Text over photos

A photo has hundreds of colors, and text over it has to be readable over every one of them. The rule is to check the worst spot: the part of the image under the text that is closest in lightness to the text. For white text, that is the brightest area, such as sky, a white shirt or a reflection. One bright patch behind a word can make it unreadable even if the rest of the image is dark.

Use an overlay or a scrim

The most reliable fix is to put a semi-transparent layer between the image and the text. A dark overlay limits how bright any part of the image can get, so you can work out the worst case exactly. Over a pure white patch, black at a given opacity produces a fixed gray:

  • Black at 40% opacity over white gives #999999. White text on it: 2.84:1.
  • Black at 50% gives #808080. White text: 3.94:1, enough only for large text.
  • Black at 55% gives #737373. White text: 4.74:1.
  • Black at 60% gives #666666. White text: 5.74:1.
  • Black at 70% gives #4D4D4D. White text: 8.45:1.

So a 60% black overlay guarantees that white text passes for normal sizes, whatever the photo looks like. If the image is already mostly dark, you may get away with less, but then you have to check the actual brightest spot under the text.

A full overlay darkens the whole image. A scrim is a gradient overlay that is dark only where the text sits, such as the bottom third of a card, and fades to transparent elsewhere. It keeps most of the photo bright while protecting the text.

A scrim: a solid 70% black band where the text sits, fading to transparent toward the top of the image.

CSS

background-image: linear-gradient(to top, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7) 30%, rgba(0, 0, 0, 0) 75%);

Keep the text inside the part of the scrim that is fully dark. Where the gradient fades, its protection fades too.

Other techniques

  • A solid or semi-opaque box behind the text, like a caption bar. It's the simplest to check, because the box is the background.
  • A light overlay with dark text, for bright, airy images. White at 60% over a pure black patch gives #999999, and black text on it is 7.37:1.
  • Placing text over a calm area of the image, such as plain sky or a wall, and checking that area at every screen size, since cropping changes on different screens.
  • A blur behind the text, which reduces busy detail but not brightness. Combine it with an overlay rather than relying on it alone.

Text shadows

A text shadow can help separate letters from a busy background, but it's hard to measure and easy to overdo. Treat it as an extra, not the main fix. A soft, dark shadow close to the letters helps white text most. A large blurry glow mostly adds visual noise.

CSS

.hero {
  position: relative;
  background-image: url("hero.jpg");
  background-size: cover;
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.7) 30%, rgba(0, 0, 0, 0) 75%);
}

.hero h1 {
  position: relative;
  color: #ffffff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
A scrim behind hero text, with a small shadow as an extra. The text sits in the fully dark part of the scrim.

Text over gradients

A gradient is a range of backgrounds, so the text has to pass against every color it crosses. Check both ends and the middle. White text on this indigo to pink gradient passes at the indigo end, 6.28:1 on #4F46E5, but drops to 3.52:1 at the pink end on #EC4899.

White text passes on the indigo end and fails for normal text on the pink end. Keep text on the darker side or darken the light end.

CSS

background-image: linear-gradient(90deg, #4f46e5, #ec4899);
  • Keep small text over the darker part of the gradient, and only large headings across the full width.
  • Darken the lighter end until it passes too. In a standard gradient, the colors in between are never lighter than the lighter end, so if white text passes on both ends, it passes everywhere in between.
  • With dark text, still check the middle. Halfway between two light colors of different hues can be darker than either end.
  • Add a scrim or a solid text box when the gradient has to stay bright.

Dark mode

Dark mode has its own problems. Pure white text on pure black reaches the maximum 21:1, but for many readers that much contrast causes glare and a halo effect around letters, especially in long text. Most dark themes use a very dark gray or navy for the background and an off-white for text.

  • Light gray #E5E7EB on near-black #111827: 14.32:1. Still very high, and softer than white on black.
  • Off-white #F1F5F9 on dark gray #121212: 17.10:1.
  • Slate #94A3B8 on #111827: 6.91:1, a good secondary text color for dark mode.
  • Slate #64748B on #111827: only 3.72:1. A gray that works as secondary text in light mode can fail in dark mode.

Lighten and desaturate colors

Saturated colors that look good on white tend to fail and vibrate on dark backgrounds. A deep indigo #4F46E5 is only 2.82:1 on #111827. A lighter, softer indigo #818CF8 reaches 5.94:1, and an even lighter #A5B4FC reaches 8.89:1. The same goes for reds: #DC2626 is 3.67:1 on #111827, while #F87171 is 6.41:1.

As a rule, move colors a few steps lighter and slightly less saturated for dark mode. They'll pass contrast more easily and feel calmer on a dark surface.

  • #111827
  • #1E293B
  • #E5E7EB
  • #94A3B8
  • #818CF8
  • #F87171

Near-black background, raised surface, off-white text, muted secondary text, a softened indigo and a lighter red, each checked against #111827.

Open in generatorPalette detailsVisualize

Recheck every pair

  • Check text, links, borders and icons against each dark surface, not just the page background. Cards and menus are usually a little lighter, which lowers contrast for light text.
  • Check images and illustrations. Logos and diagrams drawn for white backgrounds can disappear on dark ones and may need a dark-mode version.
  • Check shadows. They barely show on dark surfaces, so use a lighter surface color or a border to separate layers instead.
  • Let people choose. Respect the system setting, and offer a manual switch where you can.
Contrast CheckerTest a text and background pair against WCAG AA and AAA.

Checklist

  1. On colored backgrounds, pick black or white text by the numbers, and move mid-tone backgrounds away from the awkward middle.
  2. Over photos, check the brightest spot under the text, and use an overlay, scrim or text box that guarantees the contrast.
  3. Over gradients, check both ends and the middle.
  4. In dark mode, avoid pure white on pure black for long text, lighten and soften accent colors, and recheck every pair on every surface.
  5. Test on real layouts at several screen sizes, where images crop and text moves.
Palette VisualizerSee your palette on real designs, outfits and rooms.

Put it into practice

Unsaved changes

“” has changes that aren't saved to your wishlist. Save them before continuing?