Animating CSS Box Shadows — Smooth Hover Effects and Transitions
CSS box-shadow transitions create smooth hover effects for cards and buttons. Here's how to animate shadows efficiently, avoid performance issues, and create material design...
Animating CSS box shadows on hover creates the sense of elevation change — a card lifting off the page, a button being pressed. Done right, it’s smooth and performant.
Use the Box Shadow Generator to create and preview shadow values.
Basic hover transition
.card {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.card:hover {
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
transform: translateY(-2px); /* slight lift */
}
The transform: translateY(-2px) combined with a larger shadow reinforces the elevation effect visually.
Performance: opacity vs shadow interpolation
Animating box-shadow triggers paint (not just composite), which can be slow. For high-performance animations, animate opacity of a pseudo-element instead:
/* Performance-optimized shadow animation: */
.card {
position: relative;
isolation: isolate;
}
.card::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
opacity: 0;
transition: opacity 0.3s ease;
z-index: -1;
}
.card:hover::after {
opacity: 1;
}
opacity changes are handled by the compositor (no repaint), making this much smoother on complex pages.
Button press effect (inset shadow)
.btn {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08);
transition: box-shadow 0.1s ease, transform 0.1s ease;
}
.btn:hover {
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);
transform: translateY(-1px);
}
.btn:active {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
transform: translateY(1px);
}
Elevation system with transitions
Define a set of elevation levels and transition between them:
:root {
--shadow-sm: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.24);
--shadow-md: 0 3px 6px rgba(0,0,0,.16), 0 3px 6px rgba(0,0,0,.23);
--shadow-lg: 0 10px 20px rgba(0,0,0,.19), 0 6px 6px rgba(0,0,0,.23);
--shadow-xl: 0 14px 28px rgba(0,0,0,.25), 0 10px 10px rgba(0,0,0,.22);
}
.card {
box-shadow: var(--shadow-sm);
transition: box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.card:hover {
box-shadow: var(--shadow-lg);
}
The cubic-bezier creates a spring-like feel — fast at the start, easing at the end.
Keyframe shadow animation
For continuous or attention-drawing animations:
/* Pulse / breathing effect: */
@keyframes shadow-pulse {
0%, 100% {
box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
}
50% {
box-shadow: 0 0 0 12px rgba(59, 130, 246, 0);
}
}
.notification-badge {
animation: shadow-pulse 2s infinite;
}
/* Loading skeleton shimmer with shadow: */
@keyframes skeleton-glow {
0% { box-shadow: 0 0 10px rgba(0,0,0,0.05); }
50% { box-shadow: 0 0 20px rgba(0,0,0,0.15); }
100% { box-shadow: 0 0 10px rgba(0,0,0,0.05); }
}
Glow effects for dark mode
/* Neon glow: */
.neon-button {
background: #1e293b;
color: #38bdf8;
border: 1px solid #38bdf8;
box-shadow: 0 0 10px rgba(56, 189, 248, 0.3);
transition: box-shadow 0.2s ease;
}
.neon-button:hover {
box-shadow:
0 0 10px rgba(56, 189, 248, 0.5),
0 0 20px rgba(56, 189, 248, 0.3),
0 0 40px rgba(56, 189, 248, 0.15);
}
Colored shadow on hover
Match the shadow color to the element’s background for a “bloom” effect:
.btn-red {
background: #ef4444;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.btn-red:hover {
box-shadow: 0 8px 20px rgba(239, 68, 68, 0.4); /* red shadow */
transform: translateY(-2px);
}
.btn-blue {
background: #3b82f6;
transition: box-shadow 0.2s ease;
}
.btn-blue:hover {
box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4); /* blue shadow */
}
transition-duration recommendations
| Effect | Duration |
|---|---|
| Button hover shadow | 100–150ms |
| Card hover elevation | 200–300ms |
| Modal appear shadow | 200–250ms |
| Pulse animation cycle | 1500–2500ms |
Micro-interactions (hover effects) should be fast (< 200ms). Longer durations feel sluggish.
Related tools
- Box Shadow Generator — create shadows visually
- CSS Box Shadow Guide — box-shadow property syntax
- CSS Box Shadow Generator Guide — elevation patterns
Related posts
- CSS Box Shadow Performance — GPU Compositing and Repaint Optimization — Box shadows can hurt scroll and animation performance if used incorrectly. Learn…
- Colored Box Shadow in CSS — Glow Effects and Color Shadows — CSS box-shadow isn't limited to black. Create colored glows, neon effects, brand…
- CSS Box Shadow Examples — Generate and Customize Shadow Effects — CSS box-shadow creates drop shadows, inset shadows, and layered shadow effects. …
- CSS Box Shadow Generator — Build Drop Shadows and Inset Effects — CSS box-shadow creates drop shadows and inset effects with five values: offset-x…
- CSS Box Shadow — How to Use box-shadow Correctly — CSS box-shadow adds depth, elevation, and focus effects to elements. Here's the …
Related tool
Visual CSS box-shadow builder. Control offset, blur, spread, color, inset. Multi-layer shadows. Live preview + copyable CSS.
Written by Mian Ali Khalid. Part of the Frontend & Design pillar.