CSS Box Shadows: Creative Techniques & Best Practices

The CSS box-shadow property is one of the most versatile tools in a web designer's toolkit. It creates depth, draws attention to interactive elements, and when used creatively can produce effects that once required image editors. Yet many developers stick to a single generic shadow and never explore the property's full potential.

This guide covers everything from basic syntax to advanced multi-layer techniques, modern design trends like neumorphism and glassmorphism, performance considerations, and accessibility best practices. By the end, you'll have the knowledge to craft shadows that feel natural, purposeful, and performant.

Understanding the Box-Shadow Syntax

The box-shadow property accepts one or more shadow layers, each defined by up to six values:

box-shadow: [inset] offset-x offset-y blur-radius spread-radius color;
  • inset (optional): Places the shadow inside the element rather than outside
  • offset-x: Horizontal displacement — positive moves right, negative moves left
  • offset-y: Vertical displacement — positive moves down, negative moves up
  • blur-radius (optional, default 0): The larger the value, the softer and more spread the shadow edge
  • spread-radius (optional, default 0): Positive expands the shadow, negative shrinks it
  • color: Any CSS color value — rgba and hsla allow transparency control

Multiple shadows are separated by commas and rendered back-to-front (first shadow on top).

Multi-Layer Shadows for Realism

Real-world objects don't cast a single uniform shadow. Light sources produce complex shadow patterns with varying softness and intensity depending on distance and angle. Multi-layer shadows in CSS simulate this natural behavior.

The Two-Layer Technique

The simplest realistic shadow combines a tight, dark shadow for definition with a larger, softer shadow for ambient depth:

/* Tight key shadow + soft ambient shadow */
box-shadow:
  0 1px 3px rgba(0, 0, 0, 0.12),
  0 4px 12px rgba(0, 0, 0, 0.08);

The first layer grounds the element; the second creates the perception of floating above the surface.

Layered Depth (Smooth Shadows)

For ultra-smooth shadows that mimic real-world lighting, stack 4–5 layers with progressively larger blur and offset values while decreasing opacity:

box-shadow:
  0 0.5px 1px rgba(0,0,0,0.05),
  0 2px 4px rgba(0,0,0,0.05),
  0 4px 8px rgba(0,0,0,0.05),
  0 8px 16px rgba(0,0,0,0.04),
  0 16px 32px rgba(0,0,0,0.03);

This produces a shadow that feels organic and lifelike — far superior to a single heavy shadow with high blur.

Inset Shadows

Adding the inset keyword flips the shadow inside the element, creating effects that simulate pressed buttons, recessed panels, or inner glows:

/* Pressed button effect */
.btn-pressed {
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
}

/* Inner glow */
.inner-glow {
  box-shadow: inset 0 0 20px rgba(59, 130, 246, 0.3);
}

Inset shadows are essential for creating depth that goes "into" the surface — a key ingredient in neumorphic design.

Material Design Elevation

Google's Material Design system uses shadow to communicate hierarchy and interaction. Elements at higher elevations cast larger, softer shadows — mimicking objects held closer to a light source and farther from a surface.

Elevation LevelUse CaseCSS box-shadow
0dpFlat surfacenone
1dpCard at rest0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)
2dpRaised button0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)
8dpFloating action button0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)
16dpModal/dialog0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22)
24dpNavigation drawer0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22)

The key principle: interactive elements should visually "lift" on hover/focus by increasing their elevation shadow. This gives users clear feedback about what is clickable.

Neumorphism (Soft UI)

Neumorphism creates a soft, extruded appearance by combining a light shadow and a dark shadow on a background that matches the element color:

.neumorph-card {
  background: #e0e5ec;
  border-radius: 16px;
  box-shadow:
    8px 8px 16px #b8bec7,
    -8px -8px 16px #ffffff;
}

The light shadow simulates light hitting the top-left; the dark shadow simulates the bottom-right being in shade. The background must be close to the shadow colors for the effect to work.

Accessibility warning: Neumorphism often fails WCAG contrast requirements. The subtle shadows that define element boundaries can be invisible to users with low vision. If you use neumorphism, add borders or other visual indicators for interactive elements.

Glassmorphism

Glassmorphism combines frosted-glass blur with subtle shadows to create translucent card effects. While backdrop-filter handles the blur, box-shadow adds the crucial edge definition and depth:

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

The outer shadow creates lift while the inset shadow adds a subtle inner highlight that reinforces the glass edge.

Color Shadows

Traditional shadows use black or gray at low opacity. Color shadows — using the element's own hue — create a modern, vibrant glow effect:

.btn-primary {
  background: #3b82f6;
  box-shadow: 0 4px 14px rgba(59, 130, 246, 0.4);
}

.btn-danger {
  background: #ef4444;
  box-shadow: 0 4px 14px rgba(239, 68, 68, 0.4);
}

Color shadows make buttons and cards feel luminous — as if they emit light rather than simply block it. They're particularly effective on dark backgrounds and in modern SaaS interfaces.

Animated Shadows and Hover Effects

Shadows can transition on hover to provide feedback, but animating box-shadow directly is expensive because it triggers repaint on every frame. The performant approach uses a pseudo-element:

.card {
  position: relative;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  transition: transform 0.2s ease;
}

.card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 12px 40px rgba(0,0,0,0.15);
  opacity: 0;
  transition: opacity 0.2s ease;
  z-index: -1;
}

.card:hover {
  transform: translateY(-2px);
}

.card:hover::after {
  opacity: 1;
}

This technique pre-renders both shadow states and animates only opacity and transform — both GPU-accelerated properties that run at 60fps without triggering layout or paint.

Performance Considerations

Shadows are purely cosmetic and don't affect layout, but they do impact rendering performance:

  • Blur radius cost: Larger blur values require more computation. A 50px blur is significantly more expensive than a 5px blur.
  • Number of shadows: Each layer adds rendering work. Keep production shadows under 5 layers per element.
  • Animating shadows: Never transition box-shadow directly on many elements simultaneously. Use the opacity/pseudo-element pattern instead.
  • Mobile devices: Budget GPUs struggle with large shadows on scrolling content. Test on real low-end devices.
  • will-change: Adding will-change: transform to shadowed elements can promote them to their own compositor layer, improving scroll performance.

Text-Shadow vs Box-Shadow

While related, these properties serve different purposes:

Featurebox-shadowtext-shadow
Applies toElement's border boxText content only
Inset supportYesNo
Spread radiusYesNo
Respects border-radiusYesN/A
Common useCards, buttons, modalsText glow, emboss, legibility on images

Accessibility Best Practices

Shadows enhance visual design but must never be the sole indicator of state or interactivity:

  • Don't rely on shadow alone for focus states: Always combine shadow with an outline or border change that meets 3:1 contrast. Screen readers can't perceive shadows.
  • Hover shadow changes need alternatives: Touch devices have no hover. Ensure your UI works without hover-shadow feedback.
  • Respect reduced-motion preferences: Wrap shadow animations in @media (prefers-reduced-motion: no-preference) — users who are sensitive to motion should get instant state changes.
  • Neumorphism caution: If you use soft-UI shadows as the only boundary between elements, add subtle borders or contrast differences for users with low vision.
Pro tip: Use our Box Shadow Generator to visually experiment with multi-layer shadows, inset effects, and color shadows — then copy the production-ready CSS directly into your project.

Frequently Asked Questions

box-shadow applies a shadow around the entire element's box (including border-radius), while text-shadow applies only to the text characters inside an element. box-shadow supports inset shadows and spread radius; text-shadow does not. Use box-shadow for cards, buttons, and containers; use text-shadow for decorative text effects or subtle legibility improvements on images.
There is no hard limit — you can stack as many comma-separated shadow layers as needed. Realistic shadows typically use 2–4 layers with varying blur and offset to simulate natural light. However, more layers mean more rendering work, so keep it practical. Five or fewer layers is a good guideline for production use.
Yes, large blur-radius shadows and shadows on many elements can impact rendering performance, particularly on mobile devices. Shadows trigger paint operations but don't cause layout changes. Animating box-shadow directly is expensive — instead, animate opacity on a pseudo-element that already has the shadow applied, or use transform with a pre-rendered shadow for smooth 60fps transitions.
Neumorphism (soft UI) uses inset and outset shadows on a matching-color background to create a soft, extruded appearance. It looks striking but has significant accessibility issues — low contrast between elements and backgrounds makes interfaces hard to navigate for users with visual impairments. Use neumorphism sparingly for decorative elements, not for primary interactive controls.
Material Design defines elevation levels (0–24dp) using multiple shadow layers. Each level uses two or three shadows — a key light shadow (sharper, offset downward) and an ambient shadow (softer, spread wider). For example, elevation 2 uses approximately: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23). Higher elevations increase the offset and blur values progressively.

Create Stunning Shadows Instantly

Experiment with multi-layer shadows, color shadows, and inset effects — then copy the CSS directly into your project.

Explore All Tools →