Blog
Custom Print on Demand Apparel — Free Storefront for Your Business
Wild & Free Tools

CSS Multiple Box Shadows & All-Sides Shadow Techniques

Last updated: April 20268 min readDeveloper Tools

A single box-shadow looks flat. Multiple layered shadows look real. Real-world light creates multiple shadow components at different distances and intensities. CSS lets you replicate this by comma-separating shadow values. Here is exactly how to use multiple shadows, all-sides shadows, and advanced techniques like neumorphism.

Multiple Shadows — The Syntax

Separate each shadow with a comma. They render in order — first shadow on top:

box-shadow:
  0 1px 2px rgba(0,0,0,0.07),
  0 4px 8px rgba(0,0,0,0.07),
  0 12px 24px rgba(0,0,0,0.07);

Three layers: a tight contact shadow (1px), a medium ambient shadow (4px), and a wide environmental shadow (12px). Each has low opacity (0.07) so they add up to a natural-looking depth without any single layer being heavy.

All-Sides Even Shadow

The simplest technique — zero offset, blur only:

box-shadow: 0 0 15px rgba(0,0,0,0.2);

With h-offset: 0 and v-offset: 0, the shadow radiates equally from all edges. The blur radius controls how far it extends. This works for:

Add spread for more control: box-shadow: 0 0 15px 5px rgba(0,0,0,0.15); — the spread (5px) expands the shadow base before blur is applied.

Layered Shadow for Realistic Depth

The most important technique in modern CSS shadows. Three layers with increasing offset and blur create natural-looking elevation:

Layer 1 — Contact shadow (tight, dark)

0 1px 1px rgba(0,0,0,0.08)

Simulates where the element "touches" the surface. Very small offset and blur. Adds definition.

Layer 2 — Ambient shadow (medium)

0 4px 8px rgba(0,0,0,0.08)

The main visible shadow. Mid-range offset and blur. Provides the primary sense of elevation.

Layer 3 — Environmental shadow (wide, soft)

0 16px 32px rgba(0,0,0,0.06)

Large offset and blur, very low opacity. Creates the sense that light is diffusing around the element from a distant source.

Combined:

box-shadow:
  0 1px 1px rgba(0,0,0,0.08),
  0 4px 8px rgba(0,0,0,0.08),
  0 16px 32px rgba(0,0,0,0.06);

This is the shadow system used by Stripe, Tailwind UI, and most premium design systems. It looks more realistic than any single shadow because it mimics how light actually behaves.

Shadow Elevation Scale

Build a reusable elevation system with CSS custom properties:

:root {
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
  --shadow-md: 0 1px 3px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.08);
  --shadow-lg: 0 1px 3px rgba(0,0,0,0.08), 0 8px 16px rgba(0,0,0,0.08), 0 24px 48px rgba(0,0,0,0.06);
  --shadow-xl: 0 2px 4px rgba(0,0,0,0.08), 0 12px 24px rgba(0,0,0,0.1), 0 32px 64px rgba(0,0,0,0.08);
}

Apply consistently: cards get --shadow-md, modals get --shadow-xl, buttons get --shadow-sm. The scale creates visual hierarchy through consistent depth.

How Layers Affect Performance

ScenarioShadow CountPerformance ImpactRecommendation
Static card2-3 layers✓ Negligible — renders onceUse as many as design needs
Hover transition2-3 layers~Moderate — repaint per frameKeep transitions under 300ms
Scroll animation1-2 layers~Moderate — frequent repaintsPrefer pseudo-element opacity trick
Animated element (JS)1 layer~Frequent repaints per frameUse transform + opacity instead
Decorative static (no interaction)5-10 layers✓ Single paint, then cachedNo practical limit for static

The rule: static shadows are cheap regardless of count. Animated shadows are expensive per frame. For hover effects, the pseudo-element trick avoids the repaint cost:

.card { position: relative; }
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 12px 32px rgba(0,0,0,0.2);
  opacity: 0;
  transition: opacity 0.25s ease;
}
.card:hover::after { opacity: 1; }

The shadow is always rendered (cached). Only the opacity animates — which is GPU-composited and does not trigger repaint.

Neumorphism (2 Shadows)

Neumorphism creates the illusion of elements extruding from the surface using two opposing shadows:

background: #e0e0e0;
box-shadow:
  8px 8px 16px rgba(0,0,0,0.2),
  -8px -8px 16px rgba(255,255,255,0.7);

The dark shadow (bottom-right) creates depth. The light shadow (top-left) creates a highlight, as if light is hitting the raised edge. The background must match the surrounding surface — neumorphism breaks if the element background differs from the page.

Pressed / inset neumorphism:

box-shadow:
  inset 6px 6px 12px rgba(0,0,0,0.2),
  inset -6px -6px 12px rgba(255,255,255,0.7);

Same technique with inset. Creates a concave, pressed-in appearance. Use for active button states or toggle switches in the "on" position.

Glassmorphism (Shadow + Backdrop)

Glassmorphism combines a light shadow with a translucent background and blur:

.glass-card {
  background: rgba(255, 255, 255, 0.1);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: 0 8px 32px rgba(0,0,0,0.1);
  border-radius: 16px;
}

The shadow grounds the glass panel. Without it, the frosted glass looks like it is flat on the surface. A soft, wide shadow (large blur, low opacity) works best — sharp shadows conflict with the ethereal glass aesthetic.

Note: backdrop-filter has performance implications on mobile devices with lower-end GPUs. Test on real devices, not just desktop browsers.

Long Shadow (Dozens of 1px Shadows)

Long shadow is a retro flat-design effect built from many 1px-offset shadows stacked diagonally:

box-shadow:
  1px 1px 0 #bbb,
  2px 2px 0 #bbb,
  3px 3px 0 #bbb,
  4px 4px 0 #bbb,
  5px 5px 0 #bbb,
  /* ... continue to 50-100px */
  50px 50px 0 #bbb;

Writing this by hand is impractical. Use a CSS preprocessor (Sass or PostCSS) with a loop to generate the values. Or use a shadow generator that supports long shadow presets.

Long shadows look striking on hero sections and large headings. Avoid on small elements or interactive components — the visual weight is too heavy for buttons or cards.

Animating Between Shadow States

CSS transitions interpolate each shadow in the list by position. Critical rule: both states must have the same number of shadows.

/* Base: 3 shadows */
box-shadow:
  0 1px 2px rgba(0,0,0,0.1),
  0 4px 8px rgba(0,0,0,0.08),
  0 0 0 transparent; /* placeholder for 3rd */

/* Hover: 3 shadows */
box-shadow:
  0 2px 4px rgba(0,0,0,0.1),
  0 8px 16px rgba(0,0,0,0.12),
  0 24px 48px rgba(0,0,0,0.08);

The base has a transparent third shadow as a placeholder. On hover, it transitions to a visible third layer. If the counts do not match, the browser cannot interpolate and the change is instant (no smooth transition).

Quick Reference: Shadow Techniques

TechniqueShadow CountCSS PatternUse Case
All-sides even10 0 blur rgba()Modals, featured cards
Layered depth2-3Increasing offset + blur per layerCards, panels, design systems
Neumorphism2Opposite offsets, light + darkSoft UI, toggle buttons
Glassmorphism1Soft shadow + backdrop-filterFrosted panels, overlays
Long shadow50-1001px increments, same colorHero text, flat design accents
Border ring10 0 0 spread colorFocus indicators, selection
Animated2-3 (matched count)Transition with same shadow countHover effects, interactions

Tools for Building Shadows

Build layered box-shadow CSS visually — adjust every value, copy instantly.

Open Box Shadow Generator
Launch Your Own Clothing Brand — No Inventory, No Risk