Type something to search...
How to keep text readable on top of images?

How to keep text readable on top of images?

You keep text readable on top of images by controlling the contrast between the text and whatever part of the image sits behind it. The most reliable techniques are a semi-transparent colour overlay across the image, a gradient scrim that darkens only the area behind the text, a solid or translucent panel behind the text, and a subtle text shadow for extra separation. Choosing images with calm, uniform areas for text and keeping the copy short helps just as much. Because images vary and crop differently on each screen, you should design for the worst case and test contrast against the lightest (or darkest) part of the image the text can overlap.

Hero banners, cards and promotional tiles often put headings directly over photographs, and they're one of the most common places for text to become unreadable. A heading that looks fine on the designer's screen can land on a bright sky or a busy pattern once the image is cropped for a phone. In this article you'll learn why text on images fails, the main CSS techniques for fixing it, how to choose and prepare images, how to handle responsive cropping, and how to check that your text meets accessibility requirements.

Why Text on Images Is Hard to Read

Text is readable when it stands out clearly from its background. On a flat colour, that contrast is constant and easy to measure. On a photograph, the background changes from one pixel to the next:

  • Brightness varies: A white heading can be readable over a dark tree and invisible over the bright sky beside it.
  • Detail competes with letters: Leaves, crowds, textures and text within the photo create visual noise that breaks up letter shapes.
  • Crops change: With background-size: cover or object-fit: cover, different parts of the image appear behind the text at different screen sizes.
  • Images get swapped: Content editors replace hero images without considering the text placed over them.
  • Images fail to load: If the image is slow or missing, white text may end up on a white page.

WCAG's contrast requirements still apply to text over images: 4.5:1 for normal text and 3:1 for large text at Level AA. You need to meet that ratio against the background the text actually sits on, which for a photograph means the most difficult area behind it.

Start With the Right Markup

Whatever technique you use, a solid structure makes it easier. Put the image and the text in a positioned container, with the image as a real element if it conveys meaning, or as a CSS background if it's decorative:

<section class="hero">
  <img class="hero__image" src="/images/harbour-1600.jpg"
       srcset="/images/harbour-800.jpg 800w, /images/harbour-1600.jpg 1600w"
       sizes="100vw" alt="" width="1600" height="900">
  <div class="hero__content">
    <h1>Weekend trips from Bristol</h1>
    <p>Twelve easy escapes, all under two hours away.</p>
  </div>
</section>
.hero {
  position: relative;
  isolation: isolate;
  display: grid;
  min-height: 60vh;
  align-items: end;
  background-color: #1c2530; /* fallback if the image doesn't load */
  color: #ffffff;
}

.hero__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -1;
}

.hero__content {
  padding: clamp(1.5rem, 5vw, 4rem);
  max-width: 40rem;
}

The empty alt attribute tells assistive technology the image is decorative. If the image carries meaning the text doesn't, describe it instead. The dark background-color on the container means the white text stays readable even before the image arrives or if it fails completely.

Technique 1: A Full Colour Overlay

The simplest approach is to place a translucent layer over the entire image. It reduces the brightness range of the photo, so text has consistent contrast wherever it lands:

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background-color: rgb(0 0 0 / 0.45);
  z-index: -1;
}

Because the ::after pseudo-element comes after the image in source order and shares its negative z-index, it paints above the image but below the text. Opacity between 0.35 and 0.6 is common, depending on how bright the image is.

Trade-off: A full overlay dulls the whole picture. For photography-led sites, that can undermine the reason for using the image.

You can tint the overlay with a brand colour instead of black, but darker tints work better. Bright or saturated overlays often don't reduce the image's brightness enough.

Technique 2: A Gradient Scrim

A scrim is a gradient that darkens only the part of the image behind the text and fades to transparent elsewhere. It keeps most of the photo vivid:

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: linear-gradient(
    to top,
    rgb(0 0 0 / 0.75) 0%,
    rgb(0 0 0 / 0.5) 35%,
    rgb(0 0 0 / 0) 70%
  );
}

This works well when the text sits at the bottom of the image, which is a common pattern for cards and heroes. Change the direction to match where your text is, for example to right for text on the left.

Linear gradients with only two stops can show a visible edge where the darkening ends. Adding intermediate stops, as above, gives a smoother fade.

Technique 3: A Panel Behind the Text

If you can't control the images, a solid or translucent panel behind the text gives guaranteed contrast:

.hero__content {
  background-color: rgb(17 24 39 / 0.85);
  border-radius: 0.5rem;
  padding: 1.5rem 2rem;
}

For a lighter look, combine a translucent panel with backdrop-filter to blur the image behind it. Supported in all current major browsers, it smooths out busy detail so the letters stand out:

.hero__content {
  background-color: rgb(17 24 39 / 0.55);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

@supports not (backdrop-filter: blur(1px)) {
  .hero__content {
    background-color: rgb(17 24 39 / 0.85);
  }
}

The @supports fallback makes the panel more opaque where blur isn't available, so contrast doesn't depend on the filter.

Highlighting Inline Text

For a magazine-style look, you can put a background behind each line of text rather than a single box. box-decoration-break: clone repeats padding on each line:

.hero__highlight {
  background-color: #111827;
  color: #ffffff;
  padding: 0.1em 0.35em;
  line-height: 1.6;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
<h1><span class="hero__highlight">Weekend trips from Bristol</span></h1>

Technique 4: Text Shadow

A soft text-shadow adds a dark halo around each letter, which helps text stand out from mid-tone or slightly busy areas:

.hero h1,
.hero p {
  text-shadow:
    0 1px 2px rgb(0 0 0 / 0.6),
    0 0 12px rgb(0 0 0 / 0.4);
}

Shadows are best used as a supplement to an overlay or scrim, not as the only fix. A shadow can't rescue thin text over a white sky, and heavy shadows make text look dated and blurry. Automated contrast checkers also don't take shadows into account.

Choose and Prepare Images Carefully

The best technique is often a better image. When selecting photos for text overlays:

  • Look for calm areas: Sky, water, blurred backgrounds, walls and empty space give text a uniform backdrop.
  • Prefer images with consistent tone: An image that's mostly dark or mostly light is easier to work with than one with strong highlights and shadows.
  • Avoid text in the image: Signs and labels inside a photo compete directly with your heading.
  • Edit the image itself: Darkening or blurring the area behind the text before upload gives the most control and costs nothing at runtime.

Art Direction for Different Screens

On narrow screens, a landscape image cropped to a tall shape may move a bright area behind the text. The picture element lets you supply differently cropped images for different layouts:

<picture>
  <source media="(min-width: 48em)" srcset="/images/harbour-wide.jpg">
  <img class="hero__image" src="/images/harbour-tall.jpg" alt="" width="800" height="1000">
</picture>

You can also control which part of the image stays visible with object-position, for example keeping the dark lower area in view on mobile:

.hero__image {
  object-position: 50% 80%;
}

@media (min-width: 48em) {
  .hero__image {
    object-position: center;
  }
}

Typography Choices That Help

The type itself affects how robust it is against a busy background:

  • Use heavier weights: Semibold and bold letters have thicker strokes that hold up better than light or thin weights.
  • Use larger sizes: Large text needs only 3:1 contrast under WCAG and is easier to read over texture.
  • Keep copy short: A heading and one sentence work over an image; a paragraph rarely does.
  • Avoid delicate typefaces: Script fonts and fonts with hairline serifs disappear quickly over photographs.
  • Use real text, not images of text: Baking the heading into the image file prevents translation, resizing and accessibility tools from working. It also fails WCAG 1.4.5 Images of Text where real text could be used.

How to Test Contrast on Images

Automated tools usually can't measure contrast over images, so you have to check manually:

  1. Find the worst spot: Identify the lightest area of the image behind light text, or the darkest area behind dark text, at each breakpoint.
  2. Sample the colour: Use your browser's developer tools eyedropper, or a colour picker on a screenshot, to sample that area including any overlay.
  3. Check the ratio: Compare the sampled colour with your text colour in a contrast checker. It needs 4.5:1 for normal text or 3:1 for large text.
  4. Resize the window: Repeat at several widths, because the crop changes.
  5. Test with images disabled or blocked: Confirm the fallback background colour keeps the text readable.
  6. Test with real content: Try the brightest image an editor might realistically upload, not just the carefully chosen sample.

If you're building a CMS component, set a minimum overlay strength in code so that editors can't accidentally choose an image that makes text unreadable.


FAQ: Text on Images

A gradient scrim or semi-transparent dark overlay behind the text is usually the most reliable approach. Combine it with a heavier font weight, a larger size and short copy.

Yes. Text over images must meet 4.5:1 for normal text or 3:1 for large text at Level AA, measured against the background behind the text. Text that is part of a photograph's content, such as a sign in a street scene, is exempt.

Usually not on its own. Text shadows help separate letters from mid-tone backgrounds, but they cannot make thin white text readable over a bright area. Use them alongside an overlay or scrim.

It depends on the image. Black at around 35 to 60 percent opacity is a common range. Test the lightest area behind the text to confirm the contrast ratio, and go darker if it fails.

No. Text in images can't be resized, translated, searched or restyled, and it blurs when zoomed. Use live HTML text placed over the image with CSS.

Use the picture element to serve a differently cropped image for narrow screens, or set object-position so the calmer part of the image stays behind the text.


Conclusion

Text on images is readable only when it has reliable contrast against the specific part of the image behind it. Full overlays, gradient scrims and panels with optional background blur all control that contrast in different ways, from dimming the whole image to darkening just the area under the heading. Text shadows add useful separation but shouldn't be the only safeguard, and a dark fallback background colour protects you when images fail to load.

Combine those techniques with good image choices, art direction for different screen shapes, heavier and larger type, and short copy. Then test the worst-case area of the image at several screen widths rather than trusting a single preview. That way your hero banners and cards stay striking and readable, whatever image ends up behind the text.

Share :

Related Posts

How to make typography accessible?

How to make typography accessible?

You make typography accessible by choosing clear typefaces, setting text in relative units so it scales with user preferences, giving it enough colou

Dive Deeper
What are the parts of a letterform?

What are the parts of a letterform?

A letterform is the shape of a single letter, and typographers break it down into named parts. The main ones are the stem (the main vertical

Dive Deeper
What are ascenders, descenders and the baseline?

What are ascenders, descenders and the baseline?

The baseline is the invisible line that letters sit on. Ascenders are the parts of lowercase letters that rise above the x-height, such as th

Dive Deeper