You want text that looks like it has been punched out of a solid layer, revealing the image or gradient beneath. That effect draws attention without extra markup or raster graphics. By the end of this guide you will build a responsive hero with a “cutout” headline using pure CSS, plus a few production touches to keep it accessible and fast.
Why a CSS “Cutout” Text Effect Matters
Text cutouts are often built in image editors or exported as SVG. That locks the message to a graphic and makes content changes painful. A CSS approach keeps the text live and selectable, lets you switch themes at runtime, and scales cleanly across viewports. You can layer overlays, gradients, and animations with simple property changes instead of replacing assets. You also avoid layout jank from image swaps and keep your DOM lean.
Prerequisites
You do not need a framework or build tools for this technique. A single HTML file with a stylesheet will do. Understanding a few basics helps you move faster.
- Basic HTML
- CSS custom properties
- CSS pseudo-elements (::before / ::after)
Step 1: The HTML Structure
The markup is minimal: a hero container with a heading for the cutout text and an optional subheading. This keeps semantics clear and styling flexible.
<!-- HTML -->
<section class="hero" aria-label="Promotional banner">
<h1 class="cutout" data-cutout="Experience Clarity">Experience Clarity</h1>
<p class="tagline">Readable, responsive, and fully CSS-driven.</p>
</section>
The section provides a background canvas. The h1 displays the cutout effect. The data-cutout attribute mirrors the text so you can create subtle layered effects without extra DOM nodes if you want to extend it later. The paragraph is ordinary text and remains readable on top of the background overlay.
Step 2: The Basic CSS & Styling
Set up custom properties for the background image and overlay hues. The hero uses a centered, cover-sized background and a grid layout to center the content. Keep the background on the container so the heading can inherit and align its own clipped background perfectly.
/* CSS */
:root {
--bg-url: url("https://images.unsplash.com/photo-1496307042754-b4aa456c4a2d?auto=format&fit=crop&w=1600&q=60");
--overlay-color: rgba(15, 18, 20, 0.65);
--text-color: #e9eef3;
--accent: #73e3ff;
--font: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
}
body {
font-family: var(--font);
color: var(--text-color);
background: #0f1316;
line-height: 1.5;
}
.hero {
position: relative;
display: grid;
place-items: center;
text-align: center;
padding: clamp(3rem, 6vw, 8rem) 1.5rem;
min-height: 70vh;
/* Source background that the cutout will reference */
background: var(--bg-url) center / cover no-repeat;
isolation: isolate; /* keep stacking nice when blending or masking */
}
.cutout {
font-size: clamp(2.75rem, 10vw, 8rem);
line-height: 0.95;
margin: 0 0 0.75rem;
letter-spacing: 0.02em;
font-weight: 800;
}
.tagline {
margin: 0;
font-size: clamp(1rem, 2.5vw, 1.25rem);
color: #d1d9e0;
max-width: 42rem;
}
Advanced Tip: Keep the hero background on the container and store it in a variable or as the shorthand on .hero. The heading can read it using background: inherit to guarantee perfect alignment, even if you later swap the image or change background-position.
Step 3: Building the Look-Through Text
Now create the core effect using background-clip: text. The heading renders its own background that matches the hero and clips it to the glyphs. The rest of the heading box stays transparent, so it feels like the image peeks through the letters.
/* CSS */
.cutout {
/* Inherit the exact background from .hero */
background: inherit;
background-clip: text;
-webkit-background-clip: text; /* Safari and older Chromium */
color: transparent;
-webkit-text-fill-color: transparent; /* Safari, for good measure */
/* A subtle highlight for legibility on busy images */
text-shadow:
0 1px 0 rgba(255,255,255,0.04),
0 8px 20px rgba(0,0,0,0.4);
}
/* Improve contrast with a second layer of the same text using a stroke effect via CSS-only */
.cutout::after {
content: attr(data-cutout);
position: absolute;
inset: 0;
z-index: -1; /* behind the text glyphs */
color: transparent;
background: inherit;
background-clip: text;
-webkit-background-clip: text;
filter: blur(1px) saturate(105%);
opacity: 0.5;
pointer-events: none;
}
How This Works (Code Breakdown)
The hero holds the image so the page layout and the art stay decoupled. That means you can swap the picture at any breakpoint without touching HTML. The heading pulls the same background with background: inherit. Because both elements share the same background positioning, the texture inside the letters lines up with the scene behind them, which sells the cutout effect.
The magic comes from background-clip: text and the transparent text fill. On browsers that support the unprefixed property, the letters act as a mask. On Safari, -webkit-background-clip and -webkit-text-fill-color: transparent complete the behavior. The optional ::after layer adds a faint glow that helps readability when the underlying image has low contrast in parts of the headline.
At this point the letters show the image, but the rest of the hero also shows the image. To make a true “cutout that reveals what sits beneath a tinted panel,” add a separate overlay above the photo but below the heading. A simple pseudo-element handles that.
Step 4: Building the Knockout Overlay
Add a semi-opaque film across the hero using ::before. Place it under the heading in the stacking order. The overlay dims everything except the letters, which still render a fresh copy of the image through background-clip. That contrast makes the words feel punched out of the panel.
/* CSS */
.hero::before {
content: "";
position: absolute;
inset: 0;
background:
linear-gradient(180deg, rgba(0,0,0,0.25) 0%, rgba(0,0,0,0) 30%),
linear-gradient(0deg, var(--overlay-color), var(--overlay-color));
z-index: 0; /* sits below the heading */
}
/* Keep the heading above the overlay */
.cutout {
position: relative;
z-index: 1;
}
/* Slight color pop for the tagline to sit on the overlay */
.tagline strong { color: var(--accent); }
How This Works (Code Breakdown)
The ::before element covers the container with a film that uses two gradient layers. The top gradient adds a soft highlight near the top for depth, while the flat color provides the main tint. The z-index on .cutout lifts the text above that film, but the text still draws its own background that matches the hero. That means the image inside the letters appears “untinted,” which the eye reads as a cutout.
Using inherit for the heading background keeps backgrounds in sync even if you later switch to a pattern or a video-backed gradient. If you want extra visual hooks around the headline, combine the effect with a simple geometric accent. For example, attach a badge behind the text with a ::after pseudo-element that draws a circle. If you need a refresher, see how to make a circle with CSS. For directional callouts that point at features on a screenshot behind the cutout, a small right-pointing pointer works well; here is a guide on how to make a triangle right with CSS.
Advanced Techniques: Animations & Hover Effects
Motion can bring the effect to life. A slow background pan inside the letters creates a subtle parallax-like feel with almost no extra markup. Apply the animation to the heading’s background position only, so the rest of the hero stays still and legible.
/* CSS */
@keyframes slide-bg {
0% { background-position: 50% 50%; }
50% { background-position: 55% 48%; }
100% { background-position: 50% 50%; }
}
.cutout {
animation: slide-bg 18s ease-in-out infinite;
transition: letter-spacing 250ms ease;
}
/* Micro-interaction: widen the letters on hover/focus for a crisp "breathe" effect */
.cutout:hover,
.cutout:focus {
letter-spacing: 0.04em;
}
/* A gradient pass that only affects the letters */
.cutout.gradient-pass {
background-image:
radial-gradient(1200px 600px at 30% 40%, rgba(115,227,255,0.35), transparent 60%),
var(--bg-url);
background-size: auto, cover;
background-repeat: no-repeat;
background-position: center, center;
}
/* Respect users who prefer less motion */
@media (prefers-reduced-motion: reduce) {
.cutout {
animation: none;
}
}
The keyframes nudge the background-position a few percent across a long cycle, which looks calm and intentional. The hover interaction changes letter-spacing only, a cheap property that does not trigger layout shifts elsewhere. The gradient-pass variant adds a soft glow that sweeps only through the letters while the rest of the hero remains dimmed by the overlay. If you want to attach a label next to the headline for a pricing ribbon or promotion, a shaped tag can pair nicely with this aesthetic; here is a quick reference on how to make a ribbon banner with CSS.
Accessibility & Performance
Cutout text is real text, so screen readers and search engines can parse it. The visual effect must not reduce readability or trigger discomfort, and it should not burden the rendering pipeline.
Accessibility
Use a heading level that matches the structure of your page. The hero section has aria-label to convey purpose to assistive tech, but the main information is the h1, which is already exposed. Keep the overlay contrast high enough so the tagline stays readable across images. If your headline sits on an image with wide brightness swings, consider a stronger overlay color or a text-shadow tuned for clarity. When you add decorative shapes behind or around the headline with pseudo-elements, mark them as presentational by keeping them in CSS and not adding extra markup, or if you must add an element, include aria-hidden=”true”.
Motion is opt-in by default in this guide, and the prefers-reduced-motion media query turns it off for users who choose less motion. Keep hover-only effects optional, since touch devices do not hover. If the headline content conveys key information (a number or a date), do not rely on animation to make it visible or understandable.
Performance
The properties used here are cheap to paint on modern engines. background-clip: text is widely supported and runs on the compositor. The overlay is a single pseudo-element with two gradients, which is light. Avoid animating blur, large drop shadows, or filters across the whole hero. Animating background-position of the heading only is safer because the area is small and isolated. Keep image sizes modest and pick cover-friendly art with consistent texture, which hides scaling differences across breakpoints. Preload the key hero image if it sits above the fold to avoid flashing a blank panel.
Bring It Into Your Design System
You built a flexible cutout headline that reveals imagery through live text, layered under a controllable overlay. With variables, pseudo-elements, and a single semantic heading, you can theme it, animate it, and combine it with small CSS shapes when you need extra accents. Now you can roll this pattern into hero banners, section dividers, and promo cards with confidence.