Creating Text Shadows in CSS: Simple to Advanced Techniques



This content originally appeared on DEV Community and was authored by Thea

Ever wanted to add beautiful shadows to your text? CSS offers different methods depending on how complex you want your shadows to be. Let’s explore both simple and advanced techniques!

The Simple Way: text-shadow (Best for Most Cases)

For basic shadows, use the built-in text-shadow property:

h1 {
  text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}

Why this is awesome:

  • Super easy to write
  • Works in all modern browsers
  • Best performance
  • Perfect for standard shadows
  • Supports multiple shadows in one rule (e.g., add a glow with -2px -2px 4px rgba(255,255,255,0.3))

When You Need Fancy Shadows: The data-text Technique

Sometimes you want special effects like:

  • Gradient shadows that match gradient text
  • Multiple shadow layers for depth
  • Advanced visual effects

The Problem With Duplicating Text

When creating complex shadows, you might duplicate text in HTML:

<h1>
  I ♥ coding
  <span class="shadow">I ♥ coding</span>
</h1>

This works but creates messy code that’s hard to maintain.

A Cleaner Way: Using data-text

Here’s a better way using a custom HTML attribute:

<h1 data-text="I ♥ coding">I ♥ coding</h1>

Then in your CSS:

h1 {
  position: relative;
  background: linear-gradient(135deg, #667eea, #764ba2);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent; /* If -webkit-text-fill-color fails */
}

h1::before {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  background: linear-gradient(135deg, 
             rgba(102, 126, 234, 0.3), 
             rgba(118, 75, 162, 0.3));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  transform: translate(2px, 3px);
  filter: blur(1px);
}

Using attr(data-text) means you only write the text once in HTML. If you later change the text, you don’t have to edit multiple places.

How It Works

  1. data-text attribute: Stores your text in HTML
  2. attr(data-text): CSS grabs the text from the attribute
  3. ::before: Creates a shadow layer behind the real text
  4. transform: Moves the shadow slightly
  5. filter: blur(): Makes the shadow soft

Pro Tip: Use filter: blur() sparingly. It’s rendered on the GPU but can cause jank on lower-end devices. Avoid animating elements with blur or backdrop-filter.
Also, backdrop-filter has limited support in some older browsers, especially Firefox on Android.

Adding a Second Shadow Layer

For extra depth, add another layer with ::after:

h1::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  z-index: -2;
  background: linear-gradient(135deg, 
             rgba(102, 126, 234, 0.2), 
             rgba(118, 75, 162, 0.2));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  transform: translate(4px, 5px);
  filter: blur(2px);
  opacity: 0.6;
}

Note: Stacking pseudo-elements like this adds a bit of rendering complexity, so reserve it for cases where text-shadow isn’t enough.

Important Things to Know

Browser Support

  • Works in Chrome, Firefox, Edge, and Safari
  • -webkit- prefixes (like -webkit-background-clip) are mainly for older browsers
  • Always test your designs in different browsers

Performance Tips

  • Avoid animating these effects (can slow down your page)
  • Too many filter: blur effects may lag on low-end devices
  • For simple shadows, text-shadow is always faster

Accessibility

  • These effects are visual only and won’t affect screen readers
  • Make sure your text has enough contrast with the background

Alternative Methods

Using drop-shadow Filter

For some effects, you can try:

.filter-shadow {
  filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.3));
}

drop-shadow works better than text-shadow for see-through text or images, because it keeps the shadow looking clean around transparent parts.

Multiple text-shadow Layers

For simple gradient-like effects:

.multi-shadow {
  text-shadow: 
    1px 1px 0 rgba(102, 126, 234, 0.4),
    2px 2px 0 rgba(118, 75, 162, 0.3);
}

When to Use Each Method

Situation Best Technique Why
Simple shadows text-shadow Easy to write, best performance
Multiple solid layers Multiple text-shadow Good balance of simplicity and effect
Gradient shadows data-text method Only way to achieve gradient shadows behind gradient text
Performance critical text-shadow No pseudo-elements or complex rendering
Complex animations filter: drop-shadow Can be GPU accelerated; works well with transforms
Accessibility All methods Ensure high contrast (4.5:1)

Try It Yourself

Check out all these shadow techniques with working examples and copy-paste code:

Demo on CodePen →

Text shadows can take your design from plain to wow. Start with the simple text-shadow for most cases, and level up to the data-text technique when you need those fancy gradient effects.
Happy coding!


This content originally appeared on DEV Community and was authored by Thea