CSS Box Shadow: The Complete Guide with Examples

Build Shadows Visually

Skip the guesswork and design beautiful CSS box shadows with our interactive CSS Box Shadow Generator. Adjust offsets, blur, spread, and color in real time, then copy the CSS with one click.

1. Understanding CSS Box Shadow Syntax

The box-shadow property adds one or more shadow effects to an element's frame. Shadows are drawn outside (or inside) the element's border box, creating the illusion of depth or elevation. The property has been supported in all major browsers since 2011 and remains one of the most widely used CSS properties for visual design.

The full syntax for a single box shadow is:

box-shadow: [inset] <h-offset> <v-offset> [blur-radius] [spread-radius] <color>;

Let us break down each value in detail:

h-offset (Horizontal Offset)

The horizontal distance the shadow is displaced from the element. A positive value pushes the shadow to the right. A negative value pushes it to the left. This value is required.

/* Shadow 10px to the right */
box-shadow: 10px 0 10px rgba(0, 0, 0, 0.3);

/* Shadow 10px to the left */
box-shadow: -10px 0 10px rgba(0, 0, 0, 0.3);

v-offset (Vertical Offset)

The vertical distance the shadow is displaced from the element. A positive value pushes the shadow downward. A negative value pushes it upward. This value is required. In most UI design, a positive vertical offset simulates a light source from above, which is the most natural-looking shadow direction.

/* Shadow 10px below */
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.3);

/* Shadow 10px above */
box-shadow: 0 -10px 10px rgba(0, 0, 0, 0.3);

blur-radius

Controls the blurriness of the shadow. A value of 0 produces a sharp, hard-edged shadow with no blur at all. Larger values create softer, more diffused shadows. This value is optional and defaults to 0. Negative values are not allowed. The blur is implemented as a Gaussian blur, meaning the shadow gradually fades from full opacity at the edge of the spread area to fully transparent at the outer edge of the blur.

/* No blur - sharp edge */
box-shadow: 5px 5px 0 rgba(0, 0, 0, 0.5);

/* Moderate blur - soft shadow */
box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.3);

/* Heavy blur - very diffused */
box-shadow: 5px 5px 40px rgba(0, 0, 0, 0.2);
blur: 0
blur: 15px
blur: 40px

spread-radius

Expands or contracts the shadow relative to the element's size. A positive value makes the shadow larger than the element. A negative value makes it smaller. This value is optional and defaults to 0. Spread is particularly useful for creating one-sided shadows (using negative spread to clip the shadow on unwanted sides) and for outline-like effects without affecting layout.

/* Positive spread - shadow is larger than the element */
box-shadow: 0 0 10px 5px rgba(0, 0, 0, 0.3);

/* Negative spread - shadow is smaller than the element */
box-shadow: 0 10px 10px -5px rgba(0, 0, 0, 0.3);

/* Spread with no blur - solid outline effect */
box-shadow: 0 0 0 3px #e94560;
spread: 5px
spread: -5px
outline effect

color

The color of the shadow. Any valid CSS color value works: hex, rgb, rgba, hsl, hsla, named colors, or modern color functions like oklch. Using rgba() or hsla() with an alpha channel is recommended because transparent shadows look more natural than fully opaque ones. If omitted, the shadow color defaults to the element's color property value in most browsers, though this behavior is not consistent, so always specify a color explicitly.

/* Semi-transparent black (most common) */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);

/* Colored shadow */
box-shadow: 0 4px 12px rgba(233, 69, 96, 0.4);

/* HSL with alpha */
box-shadow: 0 4px 12px hsla(210, 50%, 50%, 0.3);

inset

The optional inset keyword changes the shadow from an outer shadow (the default) to an inner shadow. An inset shadow is drawn inside the element's border box, making the content appear sunken or pressed into the surface. We cover inset shadows in detail in section 4.

/* Outer shadow (default) */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);

/* Inner shadow */
box-shadow: inset 0 4px 12px rgba(0, 0, 0, 0.15);

2. Basic Box Shadow Examples

Choosing the right shadow intensity depends on the context. A subtle shadow works for cards and containers in a flat design system. A heavier shadow signals elevated or interactive elements like modals, dropdowns, and floating action buttons. Here are three common shadow levels.

Subtle Shadow

A barely-there shadow that provides just enough separation between an element and its background. This is the workhorse shadow for card layouts, content panels, and form inputs.

.card-subtle {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12),
                0 1px 2px rgba(0, 0, 0, 0.08);
}
Subtle Shadow

Medium Shadow

A more visible shadow that adds clear depth. Good for hovered states, navigation bars, and content that needs to stand out from the page.

.card-medium {
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1),
                0 2px 4px rgba(0, 0, 0, 0.06);
}
Medium Shadow

Heavy Shadow

A strong, dramatic shadow for high-elevation elements: modals, dialogs, popovers, and tooltips. This signals to users that the element is floating above the rest of the content.

.card-heavy {
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2),
                0 10px 15px rgba(0, 0, 0, 0.12);
}
Heavy Shadow

Bottom-Only Shadow

A shadow that appears only on the bottom edge of an element. Achieved by using a negative spread value that is equal to the blur radius, combined with a positive vertical offset. This is ideal for sticky headers and navigation bars.

.bottom-shadow {
    box-shadow: 0 4px 8px -4px rgba(0, 0, 0, 0.3);
}
Bottom-Only Shadow

Shadow with Hover Transition

Shadows are commonly used for interactive feedback. Transitioning the shadow on hover makes elements feel clickable and responsive:

.card-hover {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
    transition: box-shadow 0.3s ease;
}

.card-hover:hover {
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
}

When transitioning between two box-shadow values, the browser interpolates the offset, blur, spread, and color values smoothly, producing a natural lift effect. Just ensure both states have the same number of shadow layers for the transition to animate correctly.

3. Multiple Box Shadows

The box-shadow property accepts a comma-separated list of shadow values. Each shadow is rendered in order, with the first shadow on top and subsequent shadows behind it. Layering multiple shadows creates richer, more realistic depth effects than a single shadow can achieve.

Why Layer Shadows?

In the real world, shadows are not uniform blurs. An object resting on a surface produces a tight, dark shadow close to its base (the contact shadow) and a softer, lighter shadow that spreads further. Recreating this in CSS requires at least two layers:

.realistic-shadow {
    /* Layer 1: Tight, dark contact shadow */
    /* Layer 2: Soft, wide ambient shadow */
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.2),
        0 8px 24px rgba(0, 0, 0, 0.12);
}
Two-Layer Realistic Shadow

Three-Layer Depth

For even more convincing depth, add a third layer. This approach is used by many modern design systems:

.deep-shadow {
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.07),
        0 4px 8px rgba(0, 0, 0, 0.07),
        0 16px 32px rgba(0, 0, 0, 0.07);
}
Three-Layer Depth

Each layer doubles the blur and offset of the previous one. The opacity stays low and consistent across layers so the combined result does not appear too dark. This geometric progression produces a shadow that closely mimics physically accurate light falloff.

Shadow with Colored Accent

Combining a standard dark shadow with a colored glow layer creates a branded or themed shadow effect:

.accent-shadow {
    box-shadow:
        0 4px 12px rgba(0, 0, 0, 0.15),
        0 0 0 1px rgba(233, 69, 96, 0.1),
        0 8px 30px rgba(233, 69, 96, 0.15);
}
Colored Accent Shadow

4. Inset Shadows

Adding the inset keyword flips the shadow to render inside the element rather than outside. Inset shadows create the visual effect of the element being pressed into or recessed below the surrounding surface.

/* Basic inset shadow */
.inset-basic {
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3);
}

/* Top-only inset shadow */
.inset-top {
    box-shadow: inset 0 4px 8px -4px rgba(0, 0, 0, 0.4);
}

/* Full inner glow */
.inset-glow {
    box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.2);
}
Inset Basic
Inset Top
Inner Glow

Pressed Button Effect

Inset shadows are commonly used to simulate a button being physically pressed down. Combined with a slight position shift and removal of the outer shadow, this creates a convincing tactile effect:

.press-button {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
    transition: all 0.15s ease;
}

.press-button:active {
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
    transform: translateY(2px);
}

Input Field Depth

Form inputs often use a subtle inset shadow to make them appear recessed into the page, giving a clear visual affordance that the field is an input area:

.input-field {
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(0, 0, 0, 0.15);
    padding: 0.75rem 1rem;
    border-radius: 6px;
    color: #ccd6f6;
}

.input-field:focus {
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2),
                0 0 0 3px rgba(100, 255, 218, 0.3);
}

Combining Inset and Outer Shadows

You can use both inset and outer shadows on the same element by comma-separating them. This creates complex, layered effects:

.combined {
    box-shadow:
        inset 0 1px 3px rgba(0, 0, 0, 0.2),
        0 4px 12px rgba(0, 0, 0, 0.15);
}
Inset + Outer Combined

5. Material Design Shadows

Google's Material Design system uses shadows to communicate the elevation of elements in a layered interface. Each elevation level has a specific shadow that grows softer and more diffused as the element moves further from the surface. Material Design defines shadows using two layers: a key light (directional, from above) and an ambient light (soft, omnidirectional).

Here is the Material Design elevation system recreated in CSS:

/* Elevation 1 - Cards, buttons at rest */
.elevation-1 {
    box-shadow:
        0 1px 3px rgba(0, 0, 0, 0.12),
        0 1px 2px rgba(0, 0, 0, 0.24);
}

/* Elevation 2 - Raised buttons, cards on hover */
.elevation-2 {
    box-shadow:
        0 3px 6px rgba(0, 0, 0, 0.15),
        0 2px 4px rgba(0, 0, 0, 0.12);
}

/* Elevation 3 - FAB, snackbar */
.elevation-3 {
    box-shadow:
        0 10px 20px rgba(0, 0, 0, 0.15),
        0 3px 6px rgba(0, 0, 0, 0.1);
}

/* Elevation 4 - Navigation drawer, right drawer */
.elevation-4 {
    box-shadow:
        0 14px 28px rgba(0, 0, 0, 0.2),
        0 5px 10px rgba(0, 0, 0, 0.12);
}

/* Elevation 5 - Modal, dialog */
.elevation-5 {
    box-shadow:
        0 19px 38px rgba(0, 0, 0, 0.25),
        0 8px 16px rgba(0, 0, 0, 0.15);
}
Elev 1
Elev 2
Elev 3
Elev 4
Elev 5

Using CSS Custom Properties for Elevation

To make your elevation system reusable and maintainable, define the shadows as CSS custom properties:

:root {
    --shadow-1: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
    --shadow-2: 0 3px 6px rgba(0,0,0,0.15), 0 2px 4px rgba(0,0,0,0.12);
    --shadow-3: 0 10px 20px rgba(0,0,0,0.15), 0 3px 6px rgba(0,0,0,0.1);
    --shadow-4: 0 14px 28px rgba(0,0,0,0.2), 0 5px 10px rgba(0,0,0,0.12);
    --shadow-5: 0 19px 38px rgba(0,0,0,0.25), 0 8px 16px rgba(0,0,0,0.15);
}

.card {
    box-shadow: var(--shadow-1);
    transition: box-shadow 0.3s ease;
}

.card:hover {
    box-shadow: var(--shadow-3);
}

This approach makes it trivial to switch between elevation levels across your entire application and keeps your shadow definitions consistent in one place.

6. Neumorphism Shadows

Neumorphism (also called soft UI or new skeuomorphism) is a design trend where elements appear to extrude from or sink into the background surface, as if the UI is carved from a single piece of material. The effect relies entirely on box-shadow: one light shadow simulating a highlight from above-left, and one dark shadow simulating depth from below-right.

Requirements for Neumorphism

Neumorphism only works when the element's background color closely matches the parent's background color. If there is too much contrast between the element and its surroundings, the illusion breaks down. The background should be a mid-tone (not too dark, not too light) so both the light and dark shadows are visible.

Extruded (Raised) Neumorphism

/* Light theme neumorphism */
.neumorph-raised {
    background: #e0e5ec;
    border-radius: 16px;
    box-shadow:
        8px 8px 16px #b8bec7,
        -8px -8px 16px #ffffff;
}

/* Dark theme neumorphism */
.neumorph-raised-dark {
    background: #2d3748;
    border-radius: 16px;
    box-shadow:
        8px 8px 16px #1a202c,
        -8px -8px 16px #404d64;
}
Raised Neumorphism

Pressed (Inset) Neumorphism

.neumorph-pressed {
    background: #2d3748;
    border-radius: 16px;
    box-shadow:
        inset 8px 8px 16px #1a202c,
        inset -8px -8px 16px #404d64;
}
Pressed Neumorphism

Neumorphic Button Toggle

.neumorph-toggle {
    background: #2d3748;
    border-radius: 16px;
    box-shadow:
        6px 6px 12px #1a202c,
        -6px -6px 12px #404d64;
    transition: box-shadow 0.2s ease;
    cursor: pointer;
}

.neumorph-toggle:active,
.neumorph-toggle.active {
    box-shadow:
        inset 6px 6px 12px #1a202c,
        inset -6px -6px 12px #404d64;
}

Neumorphism Accessibility Concerns

Neumorphism has significant accessibility challenges. The low contrast between elements and their background makes it difficult for users with low vision to distinguish interactive elements from static content. If you use neumorphism in production, supplement the shadow-based visual cues with borders, labels, or color indicators to maintain usability. Always test with WCAG contrast checkers.

7. Creative Shadow Effects

Box shadows are not limited to realistic drop shadows. With creative use of offsets, blur, spread, and color, you can produce a wide range of visual effects.

Neon Glow

A neon glow effect uses a bright, saturated color with zero offset, high blur, and positive spread. Layering multiple shadows at increasing blur values intensifies the glow:

.neon-glow {
    box-shadow:
        0 0 5px #e94560,
        0 0 10px #e94560,
        0 0 20px #e94560,
        0 0 40px #e94560;
    border: 1px solid #e94560;
}
Neon Glow

Neon Glow with Multiple Colors

.neon-multicolor {
    box-shadow:
        0 0 10px #64ffda,
        0 0 20px #64ffda,
        0 0 40px rgba(100, 255, 218, 0.5),
        inset 0 0 10px rgba(100, 255, 218, 0.1);
    border: 1px solid #64ffda;
}
Cyan Neon Glow

Colored Shadows

Instead of using black or gray shadows, match the shadow color to the element's background or brand color. This creates a cohesive, tinted look that feels more intentional than a generic dark shadow:

.colored-shadow-red {
    background: #e94560;
    box-shadow: 0 8px 25px rgba(233, 69, 96, 0.5);
}

.colored-shadow-blue {
    background: #667eea;
    box-shadow: 0 8px 25px rgba(102, 126, 234, 0.5);
}

.colored-shadow-green {
    background: #43e97b;
    box-shadow: 0 8px 25px rgba(67, 233, 123, 0.5);
}
Red
Blue
Green

Retro / 3D Shadow

A hard-edged shadow with zero blur and a noticeable offset creates a retro, comic-book or pixel-art aesthetic:

.retro-shadow {
    box-shadow: 6px 6px 0 #0f3460;
    border: 2px solid #0f3460;
}

/* Stacked layers for deeper 3D effect */
.retro-3d {
    box-shadow:
        2px 2px 0 #e94560,
        4px 4px 0 #0f3460,
        6px 6px 0 #64ffda;
}
Retro Shadow
Stacked 3D

Long Shadow (Flat Design)

The long shadow effect was popular in flat design. It creates a shadow that stretches at a 45-degree angle far beyond the element. This is achieved by stacking many small shadows with incrementally increasing offsets:

.long-shadow {
    box-shadow:
        1px 1px 0 rgba(0,0,0,0.1),
        2px 2px 0 rgba(0,0,0,0.1),
        3px 3px 0 rgba(0,0,0,0.1),
        4px 4px 0 rgba(0,0,0,0.1),
        5px 5px 0 rgba(0,0,0,0.1),
        6px 6px 0 rgba(0,0,0,0.1),
        7px 7px 0 rgba(0,0,0,0.09),
        8px 8px 0 rgba(0,0,0,0.08),
        9px 9px 0 rgba(0,0,0,0.07),
        10px 10px 0 rgba(0,0,0,0.06),
        11px 11px 0 rgba(0,0,0,0.05),
        12px 12px 0 rgba(0,0,0,0.04);
}
Long Shadow

Shadow as a Border Alternative

Using box-shadow with zero blur and a spread value creates a border-like effect that does not affect layout or box sizing. This is useful when you need an outline that does not shift surrounding elements:

/* Outline that doesn't affect layout */
.shadow-border {
    box-shadow: 0 0 0 2px #64ffda;
}

/* Double border effect */
.double-border {
    box-shadow:
        0 0 0 2px #e94560,
        0 0 0 5px #0f3460;
}
Shadow Border
Double Border

Design Shadows Interactively

Experiment with all of these effects in real time using our CSS Box Shadow Generator. Add multiple layers, toggle inset, adjust colors, and copy the CSS instantly.

8. Performance Considerations

Box shadows are rendered during the browser's paint phase. Understanding their performance characteristics helps you make informed decisions about when and how to use them.

How Box Shadows Are Rendered

When the browser encounters a box-shadow, it follows these steps during painting:

  1. Calculate the shadow's bounding rectangle (element size + offset + blur + spread).
  2. Fill the shadow rectangle with the specified color.
  3. Apply a Gaussian blur using the blur-radius value.
  4. Clip the shadow to exclude the area behind the element (for outer shadows) or to include only the area inside the element (for inset shadows).
  5. Composite the shadow onto the page.

The Gaussian blur is the most computationally expensive step. Larger blur values require sampling more pixels, which scales roughly quadratically with the blur radius.

What Makes Shadows Slow

Factor Impact Recommendation
Large blur radius High Keep blur under 30px for most elements
Many shadow layers Medium Limit to 2-4 layers per element
Animating box-shadow High Use pseudo-element opacity trick instead
Many shadowed elements Cumulative Apply shadows to containers, not every child
Large element dimensions Medium More pixels to blur = slower paint

The Pseudo-Element Trick for Animated Shadows

Directly animating box-shadow triggers a repaint on every animation frame. A much more performant approach is to prepare both shadow states on a pseudo-element and animate only its opacity:

.card-performant {
    position: relative;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.card-performant::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.25);
    opacity: 0;
    transition: opacity 0.3s ease;
    pointer-events: none;
}

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

With this technique, the browser only needs to composite two layers (the element with its base shadow and the pseudo-element with the hover shadow) and change the pseudo-element's opacity. This is a compositor-only operation that runs at 60fps even on low-end devices.

will-change

If you know an element's shadow will change (for example, on hover), you can hint to the browser to promote it to its own compositor layer:

.will-animate {
    will-change: box-shadow;
}

However, use will-change sparingly. Every promoted layer consumes GPU memory. Applying it to too many elements can actually hurt performance. Only use it on elements that will definitely be animated, and consider removing it after the animation completes.

9. Box Shadow vs Drop Shadow

CSS provides two shadow mechanisms: box-shadow and filter: drop-shadow(). They look similar on rectangular elements but behave very differently in key situations.

Key Differences

Feature box-shadow filter: drop-shadow()
Shape Always rectangular (follows border-box) Follows the element's alpha channel (actual shape)
Spread radius Supported Not supported
Inset Supported Not supported
Multiple shadows Comma-separated list Chain multiple filter functions
Performance Generally faster for simple cases Can be slower (processes pixel data)
Affects children No (applied to element's box only) Yes (applied to element and all descendants)
Works with clip-path Shadow is clipped (hidden) Shadow follows clipped shape

When to Use box-shadow

When to Use drop-shadow()

/* box-shadow: rectangular shadow regardless of shape */
.triangle-box {
    clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); /* shadow is clipped! */
}

/* drop-shadow: follows the clipped shape */
.triangle-drop {
    clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
    filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.3)); /* shadow visible! */
}

An important caveat: filter: drop-shadow() does not support the spread parameter or the inset keyword. Its syntax is simpler: drop-shadow(h-offset v-offset blur color). If you need spread or inset, you must use box-shadow.

10. Responsive Shadow Techniques

Shadows that look great on a large desktop monitor can appear overpowering on a small mobile screen. Here are techniques for making shadows scale appropriately with the viewport and element size.

Using clamp() for Fluid Shadows

The clamp() function lets you define a minimum, preferred, and maximum value that scales with the viewport. Applied to shadow values, it creates shadows that grow and shrink smoothly:

.fluid-shadow {
    box-shadow:
        0
        clamp(2px, 1vw, 8px)
        clamp(4px, 2vw, 20px)
        rgba(0, 0, 0, 0.15);
}

In this example, the vertical offset scales from 2px (minimum, for small screens) to 8px (maximum, for large screens), with 1vw as the preferred scaling value. The blur scales similarly. The shadow automatically adapts to the viewport width without any media queries.

Media Query Approach

For more control at specific breakpoints, use media queries to define distinct shadow levels:

.responsive-card {
    /* Mobile: subtle shadow */
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

@media (min-width: 768px) {
    .responsive-card {
        /* Tablet: medium shadow */
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
    }
}

@media (min-width: 1200px) {
    .responsive-card {
        /* Desktop: prominent shadow */
        box-shadow:
            0 2px 4px rgba(0, 0, 0, 0.06),
            0 8px 24px rgba(0, 0, 0, 0.12);
    }
}

Container Query Shadows

With CSS container queries, you can scale shadows based on the element's container size rather than the viewport, which is often more appropriate for component-based designs:

.card-container {
    container-type: inline-size;
}

.card {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

@container (min-width: 400px) {
    .card {
        box-shadow:
            0 2px 4px rgba(0, 0, 0, 0.06),
            0 8px 24px rgba(0, 0, 0, 0.12);
    }
}

Shadows with CSS Custom Properties and calc()

You can centralize your shadow scaling logic using custom properties and calc():

:root {
    --shadow-scale: 1;
}

@media (max-width: 768px) {
    :root {
        --shadow-scale: 0.5;
    }
}

.scalable-shadow {
    box-shadow:
        0
        calc(4px * var(--shadow-scale))
        calc(12px * var(--shadow-scale))
        rgba(0, 0, 0, 0.15);
}

This pattern lets you scale all shadows in your application by changing a single custom property, either through media queries, JavaScript, or user preference toggles.

Prefers-Reduced-Motion and Shadows

Users who prefer reduced motion may also appreciate simpler, non-animated shadows. While the prefers-reduced-motion media query is primarily for animations, it is good practice to disable shadow transitions for these users:

@media (prefers-reduced-motion: reduce) {
    .card {
        transition: none;
    }
}

11. Frequently Asked Questions

What is the difference between box-shadow and filter: drop-shadow() in CSS?

box-shadow applies a rectangular shadow to the element's box model (its border-box), regardless of the element's visual shape. filter: drop-shadow() applies a shadow to the element's alpha channel, meaning it follows the actual visible shape including transparent areas, border-radius curves, and even clip-path shapes. Use box-shadow for standard card and container shadows, and drop-shadow() when you need shadows that follow non-rectangular shapes like SVG icons, images with transparency, or clipped elements.

Can I animate CSS box-shadow without performance issues?

Animating box-shadow directly triggers a repaint on every frame, which can cause jank on lower-end devices. A more performant approach is to place the shadow on a pseudo-element (::after), set its initial opacity to 0, and then animate only the opacity property on hover or interaction. Since opacity is a compositor-friendly property, the browser handles the transition on the GPU without triggering layout or paint. Another technique is to stack two shadows and cross-fade between them using opacity on layered pseudo-elements.

How do I create a shadow on only one side of an element?

To create a one-sided shadow, use a combination of offset, blur, and a negative spread value. For a bottom-only shadow: box-shadow: 0 10px 10px -10px rgba(0,0,0,0.5). The negative spread (-10px) shrinks the shadow so it only appears on the side determined by the offset values. For a right-only shadow: box-shadow: 10px 0 10px -10px rgba(0,0,0,0.5). Adjust the offset direction and spread to control which side the shadow appears on.

What is neumorphism and how do I create it with box-shadow?

Neumorphism (soft UI) is a design trend where elements appear to extrude from or press into the background surface. It is achieved by applying two box-shadows: one light shadow offset toward the top-left (simulating a light source) and one dark shadow offset toward the bottom-right. The element's background must closely match the parent background. Example: box-shadow: 8px 8px 16px #d1d9e6, -8px -8px 16px #ffffff on a light gray background. Note that neumorphism has accessibility concerns due to low contrast between elements and their backgrounds.

How many box-shadows can I apply to a single element?

There is no hard limit in the CSS specification. You can comma-separate as many shadow layers as needed. However, each shadow adds rendering cost during the paint phase. In practice, two to five shadows work well for most designs (layered depth effects or Material Design elevations). Using more than ten shadows on a single element, especially across many elements simultaneously, can degrade paint performance on lower-end devices. For extreme effects like long shadows, consider generating the CSS with a preprocessor.

Conclusion

The CSS box-shadow property is deceptively simple in syntax but remarkably versatile in application. From subtle card elevations and Material Design depth systems to dramatic neon glows, retro 3D effects, and neumorphic interfaces, shadows are one of the most powerful tools for creating visual hierarchy and depth in web design.

The key takeaways from this guide are: layer multiple shadows for realistic depth, use inset shadows for pressed and recessed effects, choose between box-shadow and drop-shadow() based on the element's shape, and always consider performance when animating shadows. The pseudo-element opacity trick for animated shadows is one of the most valuable performance patterns you can learn.

For responsive designs, combine clamp(), CSS custom properties, and media queries to ensure shadows scale gracefully across screen sizes. And remember that shadows are a visual cue for elevation and interactivity -- use them intentionally to guide users through your interface, not just for decoration.

Whether you are building a design system, polishing a landing page, or experimenting with creative effects, box-shadow belongs in your everyday CSS toolkit.

Start Building Shadows

Put everything you have learned into practice with our CSS Box Shadow Generator. Experiment with offsets, blur, spread, inset, and multiple layers visually, then copy production-ready CSS in one click. No sign-up required.