The CSS Trick That Makes Text Always Readable
Text over videos usually looks kinda garbage.
You pick white text, looks great on dark parts, invisible on light parts. Pick black text, same problem in reverse. Pick some weird color with a text shadow? Congrats, you've made it kinda ugly AND hard to read.
But mix-blend-mode: difference
? This thing is magic.
mix-blend-mode: difference
Watch that text adapt in real-time. Clean af.
Why This Actually Works
The browser does math so you don't have to.
difference
calculates the color difference between your text and whatever's behind it:
- White text on dark stuff → stays white
- White text on light stuff → flips to black
- Works with any color → always finds contrast
It's like having smart text that knows what color it should be.
How to Build It
<div class="video-container">
<video autoplay loop muted>
<source src="background-video.mp4" type="video/mp4">
</video>
<div class="text-overlay">
<h1 class="dynamic-text">Your Text Here</h1>
</div>
</div>
.video-container {
position: relative;
width: 100%;
height: 400px;
overflow: hidden;
}
.video-container video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.text-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.dynamic-text {
color: white;
mix-blend-mode: difference;
font-size: 3rem;
font-weight: bold;
margin: 0;
}
Standard positioning stuff, then mix-blend-mode: difference
does all the work.
Tailwind Version (Because Of Course)
<div class="relative w-full h-96 overflow-hidden">
<video class="absolute inset-0 w-full h-full object-cover" autoplay loop muted>
<source src="video.mp4" type="video/mp4">
</video>
<div class="absolute inset-0 flex items-center justify-center">
<h1 class="text-5xl text-white mix-blend-difference font-bold">
Dynamic Text
</h1>
</div>
</div>
Same effect, less CSS.
The Important Bits
Start With White
White text works best as your base color. Trust me on this one.
Position It Right
Absolute positioning to get the text over your background. Basic stuff.
Performance Is Fine
Hardware accelerated in modern browsers. Smooth even with video backgrounds.
Where This Actually Works
Hero Sections
Background videos with text that stays readable no matter what's playing.
Image Carousels
Text over slideshows that doesn't disappear on light images.
Interactive Stuff
Combine with hover effects for some really smooth interactions.
Browser Support
- ✅ Chrome 41+
- ✅ Firefox 32+
- ✅ Safari 8+
- ✅ Edge 79+
- ❌ Internet Explorer (who cares)
Fallback (If You Must)
.dynamic-text {
color: #333; /* for ancient browsers */
mix-blend-mode: difference;
}
@supports (mix-blend-mode: difference) {
.dynamic-text {
color: white;
}
}
Probably unnecessary unless you're supporting corporate clients with Windows XP.
Full Hero Section Example
<div class="hero-section">
<video autoplay loop muted>
<source src="background.mp4" type="video/mp4">
</video>
<div class="content">
<h1 class="main-title">Always Readable</h1>
<p class="subtitle">No matter the background</p>
</div>
</div>
.hero-section {
position: relative;
height: 100vh;
overflow: hidden;
}
.hero-section video {
position: absolute;
top: 50%;
left: 50%;
min-width: 100%;
min-height: 100%;
transform: translate(-50%, -50%);
z-index: -1;
}
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.main-title, .subtitle {
color: white;
mix-blend-mode: difference;
margin: 0;
}
.main-title {
font-size: 4rem;
font-weight: bold;
margin-bottom: 1rem;
}
.subtitle {
font-size: 1.5rem;
opacity: 0.9;
}
Full-screen hero with text that adapts to whatever video you throw at it.
Pro Tips
- Test with your actual content - what works on stock videos might suck with your stuff
- Accessibility matters - make sure it's actually readable for everyone
- Mobile can be weird - test on actual devices, not just browser dev tools
- Have a fallback - because some clients still use IE (unfortunately)
Wrap It Up
mix-blend-mode: difference
solves the "text over video" problem without weird hacks.
One line of CSS, works everywhere that matters, looks clean as hell.
Use it next time you need text over dynamic backgrounds. Your designer will thank you for not using Comic Sans with a drop shadow.