Home / Snippets / Typography /
Shadow text heading
Add depth to headings with text-shadow using oklch() for soft glows, hard offset shadows, layered 3D effects, and neon glows.
Display Heading
Display Heading
Display Heading
Display Heading
Quick implementation
/* Soft glow */
.shadow-soft-glow {
text-shadow:
0 0 20px oklch(0.72 0.19 265 / 0.6),
0 0 40px oklch(0.72 0.19 265 / 0.3);
}
/* Hard offset shadow */
.shadow-hard-offset {
text-shadow: 4px 4px 0 oklch(0.35 0.12 265);
}
/* 3D stacked shadow */
.shadow-3d-stacked {
text-shadow:
1px 1px 0 oklch(0.50 0.15 265),
2px 2px 0 oklch(0.45 0.15 265),
3px 3px 0 oklch(0.40 0.14 265),
4px 4px 0 oklch(0.35 0.13 265),
5px 5px 0 oklch(0.30 0.12 265),
6px 6px 8px oklch(0.10 0.04 265 / 0.5);
}
/* Neon glow */
.shadow-neon-glow {
color: oklch(0.95 0.05 165);
text-shadow:
0 0 8px oklch(0.80 0.22 165 / 0.9),
0 0 20px oklch(0.70 0.25 165 / 0.7),
0 0 40px oklch(0.60 0.28 165 / 0.4);
}
Prompt this to your LLM
Includes role, constraints, four shadow variants, and edge cases to handle.
You are a senior frontend engineer building styled headings for a dark-mode UI.
Goal: Use CSS text-shadow to add depth and visual interest to display headings.
Produce four named variants — soft glow, hard offset, 3D stacked, and neon glow.
Technical constraints:
- Use text-shadow only — no pseudo-elements, no SVG filters, no box-shadow.
- Use oklch() for all color values — no hex, rgb(), or hsl().
- Use the alpha channel (oklch(L C H / A)) for transparency.
- Target large headings (font-size 2rem–4rem) with a display font weight of 700+.
- All four variants must work on dark backgrounds (lightness 0.10–0.20).
Variant specifications:
1. Soft glow — zero offset, two layered blurs at different radii and opacity.
Use the brand hue (265) with moderate chroma.
2. Hard offset shadow — small X/Y offset (3px–5px), zero blur, single dark shadow.
Creates a flat, retro print look.
3. 3D stacked shadow — five to seven incremental 1px offset layers with no blur,
each step slightly darker. Final layer adds a diffuse blur for grounding.
4. Neon glow — three stacked zero-offset blurs at increasing radii, a different hue
(e.g. green/teal at 165), high opacity on the inner blur, low on the outer.
Edge cases to handle:
- text-shadow does not respect border-radius or overflow — it bleeds through
parent containers. Clip with overflow: hidden on the parent if needed.
- On very large headings, increase blur radii proportionally; small blur values
on large type look clipped.
- Stacked shadows increase paint cost with each layer — limit 3D stacks to
six layers or fewer for smooth scrolling on low-end devices.
- For reduced motion preferences, text-shadow is static and safe — no changes
needed unless the shadow itself is animated.
Return CSS class definitions only.
How text-shadow creates depth
The text-shadow property accepts a list of shadow layers, each defined by X offset, Y offset, blur radius, and color. A positive X offset shifts the shadow right; a positive Y offset shifts it down. The blur radius controls how far the shadow spreads — a radius of 0 gives a crisp hard edge, while larger values produce a diffuse glow.
The key insight is that text-shadow accepts a comma-separated list of shadows, all rendered in order from bottom to top. This stacking is what makes complex effects possible. A 3D extrusion effect, for example, is just five or six shadows, each offset one pixel further than the last and tinted progressively darker to simulate a light source hitting the front face of the text.
Using oklch() colors gives you perceptual control over each shadow layer. Because oklch lightness is linear (halving the L value halves perceived brightness), you can step down each shadow in the 3D stack by a consistent 0.05 increment and get a smooth gradient of depth rather than the uneven jumps you'd get with hex codes.
Stacking multiple shadows for 3D
The 3D stacked technique works by layering multiple hard shadows (blur radius 0) at incrementing offsets. Each step moves one pixel further in both X and Y and is tinted slightly darker than the step before. The sequence creates the illusion of a solid extruded surface beneath the text.
A final shadow with a small blur and very low opacity acts as a diffuse "drop shadow" beneath the extrusion, grounding the text on the page and making the 3D effect more convincing. Without this, the stack can look like it's floating at an arbitrary Z height.
The number of layers controls how tall the extrusion appears. Six layers at one pixel each gives roughly 6px of visual depth — appropriate for large display headings. More layers add more depth but also more paint cost. For headings that appear mid-page (not in a fixed hero), five to seven layers is the practical ceiling.
Performance
Static text-shadow triggers paint at render time but does not cause layout recalculation. It is significantly cheaper than SVG filters or filter: drop-shadow() for text, because the browser can cache the rasterized shadow alongside the text glyph and avoid repainting on scroll.
The cost scales with the number of shadow layers and the blur radius. A single soft glow with a large blur radius is more expensive than a sharp hard shadow because blurring requires a convolution operation across the affected pixels. On mobile, keep blur radii below 40px on text that appears many times per page (e.g. list headings). A single hero heading with a large glow is unlikely to cause performance issues.
Animated text-shadow is a different story — animating it via CSS transitions or @keyframes forces a repaint on every frame and does not run on the compositor thread. If you need an animated glow, consider animating opacity on a pseudo-element instead, which stays compositor-only. For static headings, however, text-shadow is lightweight and well-supported across all modern browsers with no flags required.