Layered Natural Shadows
The Problem
Shadows are one of the most important depth cues in UI design, yet AI agents almost always generate a single, flat box-shadow declaration. A single shadow looks artificial because real-world shadows are not uniform blurs. When an object sits on a surface, it casts a tight, dark contact shadow near its base and a softer, lighter shadow that spreads further. A single box-shadow cannot reproduce this layered behavior.
The Solution
Use multiple comma-separated box-shadow values with progressively increasing blur radius and vertical offset. Each layer represents a different aspect of natural light behavior. Keep all shadows consistent with a single implied light source direction across the entire page.
Core Principles
Consistent Light Source
Every shadow on the page should share the same ratio between horizontal and vertical offsets. A common convention is a light source above and slightly to the left, meaning vertical offset is roughly 2x the horizontal offset.
Elevation Model
As elements "rise" toward the viewer, three properties change:
- Offset increases — the shadow moves further from the element
- Blur expands — the shadow becomes softer and more diffused
- Opacity decreases — the shadow fades as the element lifts higher
Color-Matched Shadows
Avoid pure black shadows (rgba(0, 0, 0, ...)). Instead, match the hue of the background at low saturation. This prevents the washed-out, desaturated appearance that black shadows cause.
Code Examples
Basic Layered Shadow
.card {
box-shadow:
0 1px 1px hsl(0deg 0% 0% / 0.075),
0 2px 2px hsl(0deg 0% 0% / 0.075),
0 4px 4px hsl(0deg 0% 0% / 0.075),
0 8px 8px hsl(0deg 0% 0% / 0.075),
0 16px 16px hsl(0deg 0% 0% / 0.075);
}
Each layer doubles the previous offset and blur. The cumulative effect is a smooth, natural-looking shadow with depth.
Elevation Levels
/* Low elevation — resting on surface */
.elevation-1 {
box-shadow:
0 1px 1px hsl(220deg 60% 50% / 0.07),
0 2px 2px hsl(220deg 60% 50% / 0.07),
0 4px 4px hsl(220deg 60% 50% / 0.07);
}
/* Medium elevation — card hover */
.elevation-2 {
box-shadow:
0 1px 1px hsl(220deg 60% 50% / 0.06),
0 2px 2px hsl(220deg 60% 50% / 0.06),
0 4px 4px hsl(220deg 60% 50% / 0.06),
0 8px 8px hsl(220deg 60% 50% / 0.06),
0 16px 16px hsl(220deg 60% 50% / 0.06);
}
/* High elevation — modal / dialog */
.elevation-3 {
box-shadow:
0 1px 1px hsl(220deg 60% 50% / 0.05),
0 2px 2px hsl(220deg 60% 50% / 0.05),
0 4px 4px hsl(220deg 60% 50% / 0.05),
0 8px 8px hsl(220deg 60% 50% / 0.05),
0 16px 16px hsl(220deg 60% 50% / 0.05),
0 32px 32px hsl(220deg 60% 50% / 0.05);
}
Color-Matched Shadows on Colored Backgrounds
/* On a blue-tinted background */
.card-on-blue {
background: hsl(220deg 80% 98%);
box-shadow:
0 1px 2px hsl(220deg 60% 50% / 0.1),
0 3px 6px hsl(220deg 60% 50% / 0.08),
0 8px 16px hsl(220deg 60% 50% / 0.06);
}
/* On a warm background */
.card-on-warm {
background: hsl(30deg 80% 98%);
box-shadow:
0 1px 2px hsl(30deg 40% 40% / 0.1),
0 3px 6px hsl(30deg 40% 40% / 0.08),
0 8px 16px hsl(30deg 40% 40% / 0.06);
}
Sharp + Diffuse Combination
/* Tight contact shadow + wide ambient shadow */
.card-sharp-diffuse {
box-shadow:
0 1px 3px hsl(0deg 0% 0% / 0.12),
0 8px 24px hsl(0deg 0% 0% / 0.06);
}
Complete Card Example
<div class="shadow-card">
<h3>Card Title</h3>
<p>Card content goes here.</p>
</div>
.shadow-card {
padding: 24px;
border-radius: 8px;
background: white;
box-shadow:
0 0.5px 1px hsl(220deg 60% 50% / 0.06),
0 1px 2px hsl(220deg 60% 50% / 0.06),
0 2px 4px hsl(220deg 60% 50% / 0.06),
0 4px 8px hsl(220deg 60% 50% / 0.06),
0 8px 16px hsl(220deg 60% 50% / 0.06);
transition: box-shadow 0.3s ease;
}
.shadow-card:hover {
box-shadow:
0 1px 2px hsl(220deg 60% 50% / 0.05),
0 2px 4px hsl(220deg 60% 50% / 0.05),
0 4px 8px hsl(220deg 60% 50% / 0.05),
0 8px 16px hsl(220deg 60% 50% / 0.05),
0 16px 32px hsl(220deg 60% 50% / 0.05),
0 32px 64px hsl(220deg 60% 50% / 0.05);
}
Live Preview
Common AI Mistakes
- Single flat shadow — Using
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1)everywhere. This produces a uniform, artificial look that lacks depth. - Pure black shadow color —
rgba(0, 0, 0, ...)desaturates the area beneath the shadow, creating a gray, washed-out appearance over colored backgrounds. - Inconsistent light direction — Generating different offset angles for different elements, breaking the illusion of a unified light source.
- Same shadow for all elevations — Using the same shadow for cards, modals, dropdowns, and tooltips, when each should have a distinct elevation level.
- Overly dark shadows — Setting high opacity values (0.2-0.5) for a single shadow instead of distributing lower opacities across multiple layers.
When to Use
- Cards and raised surfaces that need to feel physically present
- Elevation systems where multiple UI layers overlap (cards, dropdowns, modals, tooltips)
- Hover states that should make an element appear to lift off the page
- Any element that benefits from a sense of depth without feeling artificially heavy