The box-shadow Syntax
box-shadow: [inset] offset-x offset-y [blur] [spread] color;
- offset-x / offset-y: Shadow position. Positive x goes right, positive y goes down.
- blur: How soft the shadow is. 0 = hard edge.
- spread: How much the shadow expands beyond the element. Can be negative.
- inset: Moves the shadow inside the element.
- You can stack multiple shadows separated by commas.
Technique 1: Layered Shadows for Real Depth
A single shadow looks flat and generic. Layering 2–3 shadows at different blur radii and opacities produces the depth you see in professional design systems:
/* Material Design-inspired elevation */
.card--elevated {
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.30),
0 4px 8px rgba(0, 0, 0, 0.25),
0 16px 32px rgba(0, 0, 0, 0.20);
}
The smallest shadow adds the crisp edge detail; the largest creates the ambient shadow. Together they feel physically convincing.
Technique 2: Colored Glow Effects
Using a colored shadow with no offset creates a glow. Pair it with a spread for extra intensity:
/* Purple glow for a primary button */
.btn-primary {
background: #7c5cfc;
box-shadow:
0 0 0 0 transparent, /* ring-offset */
0 8px 24px rgba(124,92,252,0.45), /* ambient glow */
0 0 60px rgba(124,92,252,0.15); /* distant halo */
transition: box-shadow 0.3s ease;
}
.btn-primary:hover {
box-shadow:
0 0 0 0 transparent,
0 12px 32px rgba(124,92,252,0.65),
0 0 80px rgba(124,92,252,0.25);
}
Technique 3: Neumorphism (Soft UI)
Neumorphism creates an extruded-from-surface look using two shadows — one light, one dark — offset in opposite directions. The element's background must match the container background exactly:
:root { --bg: #e0e5ec; }
.neomorphic {
background: var(--bg);
border-radius: 16px;
box-shadow:
8px 8px 16px #b8bec7, /* dark shadow (bottom-right) */
-8px -8px 16px #ffffff; /* light shadow (top-left) */
}
/* Pressed/active state */
.neomorphic:active {
box-shadow:
inset 6px 6px 12px #b8bec7,
inset -6px -6px 12px #ffffff;
}
Accessibility warning: Neumorphism often produces very low contrast between the element and background. Always verify your contrast ratios pass WCAG AA — use StudioLimb's Contrast Checker.
Technique 4: Inset Shadows for Depth
Inset shadows create a sunken or engraved appearance, great for input fields, wells, and pressed button states:
/* Dark mode input field */
.input {
background: rgba(0, 0, 0, 0.3);
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.6),
inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
.input:focus {
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.6),
0 0 0 2px rgba(124, 92, 252, 0.6);
}
Technique 5: Negative Spread for Tight Shadows
A negative spread radius shrinks the shadow, letting you create a shadow that only appears below the element (like it's floating above a surface) without spreading to the sides:
/* Shadow appears only below, not on sides */
.floating {
box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.5);
/* ^^^ negative spread */
}
Performance: box-shadow vs filter: drop-shadow()
box-shadow is GPU-accelerated in all modern browsers and is the right choice for most cases. filter: drop-shadow() follows the element's alpha channel (including transparent PNG cutouts) but is more expensive and shouldn't be used on animating elements. Stick with box-shadow unless you specifically need the shape-following behavior.
Transition Tip
Avoid animating box-shadow on scroll or hover for many elements simultaneously. Instead, animate opacity on a pseudo-element that has the target shadow — this is GPU-composited and far smoother.