CSS allows any number of box-shadow layers on a single element, each with its own offset, blur, spread, colour, and optional inset keyword.
Loading Shadow Effect Builder…
Add multiple shadow layers with individual controls
Live preview showing all layers composited together
Supports mixing inset and outer shadows in one declaration
Generates the full comma-separated CSS declaration
Drop the Shadow Effect Builder into any page — blog post, product docs, intranet, school portal — with a single line of HTML. Your visitors get the full tool, processed entirely in their browser. No backend, no uploads, no signup.
Embed code
<iframe
src="https://www.fixtools.io/css-tool/shadow-effect-builder?embed=1"
width="100%"
height="780"
frameborder="0"
style="border:0;border-radius:16px;max-width:900px;"
title="Shadow Effect Builder by FixTools"
loading="lazy"
allow="clipboard-write"
></iframe>Attribution-friendly: a small "Powered by FixTools" link appears in the embed footer.
CSS processes the box-shadow property as a comma-separated list of shadow declarations. The browser renders them in order, with the first listed shadow appearing on top visually. Each shadow in the list operates independently with its own offset, blur, spread, colour, and optional inset keyword. They are composited on top of each other and on top of the element's background. This means each layer adds its visual contribution independently. A dark shadow and a light shadow on the same element both appear, each at their specified opacity and position, without blending or merging.
Three practical multi-layer patterns appear regularly in production. The two-component elevation shadow (used by Material Design) combines a close contact shadow at low blur with a diffused ambient shadow at higher blur and lower opacity. For example: box-shadow: 0 2px 4px rgba(0,0,0,0.18), 0 6px 16px rgba(0,0,0,0.1). The first layer creates the tight directional shadow; the second creates the wider haze. Together they match how physical objects cast shadows more accurately than a single layer can. The second common pattern adds a focus ring without a separate outline: box-shadow: 0 2px 8px rgba(0,0,0,0.12), 0 0 0 3px rgba(59,130,246,0.5). The second shadow uses zero offset and a spread of 3px to create a solid ring at the desired focus colour.
Performance consideration: each shadow layer adds compositing work during rendering. Two or three layers on standard card and button components render without any measurable performance cost in modern browsers because the layers are rasterised and composited on the GPU once. Stacking ten or more layers on a single element, or applying multi-layer shadow definitions to every item in a long scrollable list, can introduce real frame rate issues on low-powered devices because each scroll frame requires re-composition. Keep shadow layers at three or fewer on any element that appears more than a dozen times per page, and test scroll performance on a mid-range Android device if shadow complexity is a concern. The visual return on adding a fourth or fifth layer is typically minimal anyway.
Multi-layer shadows pair particularly well with CSS custom properties because the comma-separated nature of the value lends itself to composition. You can define each shadow concern as its own property, such as --shadow-elevation for the standard depth cue and --shadow-focus for the focus ring, then compose them together at the use site with box-shadow: var(--shadow-elevation), var(--shadow-focus). Updating one concept in one place updates every consumer simultaneously, and individual concerns can be toggled on or off without rewriting the full declaration. This composition pattern keeps complex multi-layer shadows maintainable in large design systems where dozens of components share elevation and focus styling, and where ad-hoc value copying would quickly drift out of sync across the codebase.
Add a first layer with a small offset and tight blur for the contact shadow. Click Add Layer and increase the offset and blur with lower opacity for the ambient shadow. Add a third inset layer for an inner highlight if needed. Copy the combined CSS declaration.
Step-by-step guide to css multiple box shadows:
Add the first shadow layer
Set a close, directional shadow for the first layer of the stack: a small offset of 1 to 2 pixels, a moderate blur of 4 to 6 pixels, and a medium opacity dark colour around rgba(0,0,0,0.15). This first layer creates the tight contact shadow that anchors the element to the surface beneath it. Tune this layer to read well on its own before adding any additional layers on top of it.
Add a second ambient layer
Click the Add Layer control to introduce a second shadow with a larger offset, a higher blur radius of roughly 12 to 24 pixels, and a noticeably lower opacity around 0.08 to 0.1. This wider ambient layer produces the diffused outer haze that mimics how light scatters around a real object. The combination of the close and ambient layers reads as a single coherent depth cue rather than two separate effects, which is the entire point of the multi-layer technique.
Optionally add an inset or focus ring layer
Add a third layer either as an inset highlight at the top edge of the element using inset 0 1px 0 rgba(255,255,255,0.1) for a gloss treatment, or as a zero-offset, zero-blur, spread-only layer for a focus ring effect. The third layer is optional but unlocks rich finishes that two layers alone cannot achieve. Toggle the layer on and off in the preview to confirm whether it improves the composition or simply adds visual noise without benefit.
Copy the full comma-separated declaration
Click Copy CSS to copy the complete box-shadow value containing every active layer in the correct order. Paste the declaration into your component CSS rule as a single box-shadow property value. If you store the value in a CSS custom property for reuse, paste the entire comma-separated list as the variable value and reference it from each consuming component with var() for ongoing maintainability.
Common situations where this approach makes a real difference:
Clickable card with elevation and accessible focus ring
A developer builds a clickable card component that needs both an elevation shadow at rest and a visible focus ring for keyboard navigation users. Using two box-shadow layers, the first handles the resting elevation with a soft 0 2px 8px rgba(0,0,0,0.1) and the second provides the focus ring at 0 0 0 3px rgba(59,130,246,0.6) inside the :focus-visible rule. One property declaration handles both concerns without requiring a separate outline style that would conflict with the rounded border-radius of the card. The focus ring layer also animates in cleanly because both states keep the same number of layers.
Modal dialog with two-component depth
A designer implements a confirmation modal using a two-layer shadow defined explicitly in CSS: 0 8px 20px rgba(0,0,0,0.2) for the close directional shadow that anchors the modal in space, and 0 24px 60px rgba(0,0,0,0.12) for the wide ambient haze that establishes the surrounding atmosphere. The combined shadow makes the modal feel genuinely elevated above the dimmed background rather than sitting flat on top of it like a sticker. The paired layers also read as more polished than any single-layer alternative the team had previously tested in early design exploration sessions before settling on this final pattern.
Premium CTA button with gloss finish
A developer adds three carefully tuned shadow layers to a premium CTA button on a high-end product landing page: an outer elevation shadow that lifts the button off the background, a zero-offset spread border that creates a crisp ring around the button edge, and an inset white highlight at the top interior edge that simulates light reflecting off the button surface. The triple-layer combination gives the button a refined gloss finish appearance that no single layer could achieve. All three layers are defined as separate CSS custom properties so the design team can update each visual aspect of the button independently without rewriting the full shadow declaration.
Design system elevation scale via custom properties
A design systems engineer defines four explicit elevation levels as multi-layer custom properties: --elevation-1 through --elevation-4, each containing a two-layer shadow declaration tuned for that tier. All card, button, modal, drawer, and popover components reference these named variables rather than embedding raw shadow values, which means the elevation scale stays internally consistent across the entire component library. When the design team adjusts the elevation scale during a visual refresh, a single update to the custom property definitions at the root level propagates to every component instance simultaneously, dramatically reducing the manual coordination work required to ship a system-wide elevation change.
Use this when a single box-shadow layer is not producing the depth or effect you need, or when you want to combine an elevation shadow with a focus ring or inner highlight in one CSS property.
Get better results with these expert suggestions:
Simulate a border with a zero-blur spread layer
A zero-offset, zero-blur shadow with only a spread value creates a solid ring around the element that looks identical in appearance to a border, without taking up any space in the box model or affecting computed layout dimensions. Combining box-shadow: 0 4px 12px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.06) adds a subtle hairline border appearance alongside an elevation shadow in a single CSS property. The technique is especially useful when the real border property is already reserved for another purpose such as state styling.
Animate the focus ring layer independently with CSS variables
Separate your focus ring shadow into a dedicated CSS custom property: --focus-ring: 0 0 0 3px rgba(59,130,246,0.5). Set the default value to 0 0 0 0 transparent so the ring is effectively invisible at rest, then override --focus-ring to the full value inside the :focus-visible rule. This pattern animates only the focus ring layer without disrupting the resting elevation shadow at all, because both layers continue to exist throughout the transition and only their internal values change as the state shifts.
Use a third shadow layer for inner content highlight
After an outer elevation shadow and an ambient layer, a subtle inset shadow at the top of the element simulates a highlight gloss as if light were reflecting off the upper edge of the surface. box-shadow: [outer1], [outer2], inset 0 1px 0 rgba(255,255,255,0.1) adds a barely visible white pixel line at the top interior, giving a slight glossy finish that reads particularly well on dark buttons, dark cards, and any saturated coloured surface where the white highlight contrasts cleanly with the background fill colour underneath.
Document each layer's purpose in a source comment
Multi-layer shadow declarations are not self-documenting because the comma-separated value gives no hint as to what each layer is intended to accomplish. In your CSS source file, add an inline comment identifying each layer in order: /* elevation, ambient, focus ring */ on the same line as the box-shadow declaration. Future contributors who modify the component will immediately know which layer to change without reverse-engineering the values from the rendered output. The same convention applies inside CSS custom property definitions for shared shadow tokens used by the system.
Put the tightest shadow first in the list
CSS renders shadows from the first listed item downward. The tightest, most specific shadow (low blur, close to the element) should be first so it appears on top. Wider ambient shadows go in subsequent layers.
Use a zero-offset spread layer as a focus ring
box-shadow: [existing-shadow], 0 0 0 3px rgba(59,130,246,0.5) adds a focus ring using only the box-shadow property. This avoids conflicting with CSS outline styles while keeping focus visible and styled to match your design.
Define shadow layers as separate CSS custom properties
When using a CSS custom property for shadows, define separate variables for the elevation shadow and the highlight layer. This makes it easy to change one aspect of a complex multi-layer shadow without reconstructing the full declaration.
More use-case guides for the same tool:
Open the full Shadow Effect Builder — free, no account needed, works on any device.
Open Shadow Effect Builder →Free · No account needed · Works on any device