Skip to content

Components

Text Over Images — Use a Scrim, Not a 50% Black Blanket

An Eased Gradient Where the Text Is, Full Image Everywhere Else — and It Must Survive Any Photo
Written by Aiden Wood Founder and Lead Design Engineer
🌄 🔲 🔤

Every image hero faces the same physics: photos have bright spots, text needs contrast, and the CMS means you don't control which photo ships next quarter. The lazy fix is a 50% black overlay across the whole image — readable text, murdered photo. The craft fix is the scrim: darkness only where the text lives, fading to nothing where the image does its job.

Velocity X's hero-background-scrim packages the pattern; the gradient recipe is worth understanding even if you never install it.

The Money Pattern

<section class="relative">
  <img src={hero.src} alt="" class="absolute inset-0 h-full w-full object-cover" />

  <!-- The scrim: eased multi-stop, bottom-anchored where the text sits -->
  <div class="absolute inset-0 bg-gradient-to-t
              from-black/70 via-black/35 via-40% to-transparent to-75%" />

  <div class="relative px-6 pb-14 pt-40 text-white">
    <h1 class="text-5xl font-semibold">{hero.title}</h1>
    <p class="mt-3 max-w-xl text-white/85">{hero.sub}</p>
  </div>
</section>

The multi-stop matters: a naive two-stop from-black to-transparent has a visible hard band where the gradient ends — the "scrim line" you've seen on a thousand news sites. Stacking intermediate stops (70 → 35 → 0) approximates an eased curve and the edge disappears. Text sits in the dense zone; the image's top two-thirds stays untouched.

The Catch

The scrim must survive the worst-case photo, not the one in the design file. The test: swap in a white wall and a night shot — if the headline passes contrast on both, the scrim is doing its job. If your imagery is editor-controlled chaos, add text-shadow as the second line of defence; it's unfashionable and it works.

Two implementation notes: the decorative hero image gets alt="" (the headline is the content — a screen reader doesn't need "photo of roof" before it), and the scrim div takes pointer-events-none if anything interactive sits under it... but nothing interactive should sit under a scrim, because a darkened button is a disabled-looking button.

The Verdict

Scrim where the text is, image everywhere else, eased stops so there's no band, tested against photos you don't control. It's in Velocity X's Heroes & Sections — pure Astro, zero JS, like a hero backdrop should be.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.