Skip to content

Cookie settings

Optional analytics help us understand which pages and tools are useful. If you allow them, we use Google Analytics. Your files are never included, and every tool works the same if you decline. Cookie policy

CSS Box Shadow: 15 Examples You Can Copy

How the box-shadow syntax works, 15 copyable shadows from soft cards to neon glows and focus rings, the mistakes that make shadows look cheap or slow, and when to use drop-shadow instead.

By Silas Montgomery9 min read

A good shadow is mostly invisible: it tells the eye that a card sits above the page or that a button is pressed, without drawing attention to itself. A bad one looks like a grey smudge. This guide explains every part of the box-shadow value, then gives you 15 shadows you can paste straight into a stylesheet, each with a note on when it fits.

How the box-shadow syntax works

A single shadow is a list of up to four lengths plus an optional color and an optional inset keyword:

box-shadow: [inset] <offset-x> <offset-y> [<blur-radius>] [<spread-radius>] [<color>];
  • offset-x moves the shadow right (positive) or left (negative).
  • offset-y moves it down (positive) or up (negative).
  • blur-radius softens the edge. It defaults to 0, which gives a hard edge, and negative values are not allowed.
  • spread-radius grows (positive) or shrinks (negative) the shadow before blurring. It defaults to 0, meaning the shadow starts at the same size as the element.
  • color can sit at the start or the end. If you leave it out, the shadow uses the element's color value, which is rarely what you want, so always set it.
  • inset draws the shadow inside the border instead of outside, as if the box were cut into the page.

Three behaviors are worth knowing before you write any shadow:

  1. Multiple shadows are comma-separated, and the first one is drawn on top. Put your sharpest, closest shadow first and the large ambient one last.
  2. A shadow never affects layout. It does not change the box's size or push neighbors, so you can add or animate one without causing reflow. It can, however, be clipped by a parent with overflow: hidden.
  3. A shadow follows border-radius. Rounded corners give rounded shadows automatically.

All of this is documented in the MDN box-shadow reference. The examples below use the modern rgb(0 0 0 / 0.1) color syntax, where the number after the slash is opacity. Low-opacity black or a dark tint is almost always better than a solid grey.

15 box-shadow examples

1. Hairline card

A barely-there edge plus a tiny drop. Use it for list items and table rows that need separation without looking raised.

.card {
  box-shadow:
    0 1px 2px rgb(0 0 0 / 0.06),
    0 0 0 1px rgb(0 0 0 / 0.04);
}

2. Soft card

The everyday shadow for content cards on a light background. Two layers read as more natural than one.

.card {
  box-shadow:
    0 1px 3px rgb(0 0 0 / 0.08),
    0 4px 12px rgb(0 0 0 / 0.06);
}

3. Elevation scale

Define levels once as custom properties so every component in a design system uses the same depth. Higher elevations get a larger y-offset and blur, and lower opacity per layer.

:root {
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.08);
  --shadow-2: 0 2px 4px rgb(0 0 0 / 0.08), 0 4px 8px rgb(0 0 0 / 0.06);
  --shadow-3: 0 4px 8px rgb(0 0 0 / 0.08), 0 12px 24px rgb(0 0 0 / 0.08);
  --shadow-4: 0 8px 16px rgb(0 0 0 / 0.1), 0 24px 48px rgb(0 0 0 / 0.12);
}
.dropdown {
  box-shadow: var(--shadow-3);
}

4. Floating modal

A dialog should look clearly detached from everything behind it. A large blur with a negative spread keeps the shadow from spilling far to the sides.

.modal {
  box-shadow: 0 24px 64px -12px rgb(0 0 0 / 0.35);
}

5. Hard offset (brutalist)

No blur at all, a solid dark color and a diagonal offset. Use it for playful or neo-brutalist interfaces, usually with a thick border.

.brutal {
  border: 2px solid #111;
  box-shadow: 6px 6px 0 #111;
}

6. Pressed button

Pair the hard offset with an active state that moves the button into its shadow. The translate makes the click feel physical.

.brutal:active {
  transform: translate(4px, 4px);
  box-shadow: 2px 2px 0 #111;
}

7. Inset well for inputs

An inner shadow along the top edge makes a field look recessed, which signals "type here".

input {
  box-shadow: inset 0 2px 4px rgb(0 0 0 / 0.08);
}

8. Inset pressed state

For toggle buttons that stay "on", a deeper inset shadow shows the pressed state without changing the button's size.

.toggle[aria-pressed='true'] {
  box-shadow: inset 0 3px 6px rgb(0 0 0 / 0.2);
}

9. Neon glow

Zero offsets and several increasingly large blurs in one bright color. This only works on a dark background.

.neon {
  box-shadow:
    0 0 4px #fff,
    0 0 12px #0ff,
    0 0 24px #0ff,
    0 0 48px #0ff;
}

10. Layered realistic shadow

Real shadows are sharp near the object and diffuse further away. Stacking layers that double in offset and blur imitates that, and the result looks far smoother than one big blur.

.realistic {
  box-shadow:
    0 1px 1px rgb(0 0 0 / 0.08),
    0 2px 2px rgb(0 0 0 / 0.08),
    0 4px 4px rgb(0 0 0 / 0.08),
    0 8px 8px rgb(0 0 0 / 0.08),
    0 16px 16px rgb(0 0 0 / 0.08);
}

11. Colored shadow

A shadow tinted with the element's own color looks like light passing through it. Use it for a primary button or a colorful card, ideally on a light background. It works especially well under a gradient; you can build the gradient with the CSS gradient generator and tint the shadow with its darker stop.

.button-primary {
  background: #4f46e5;
  box-shadow: 0 8px 20px -6px rgb(79 70 229 / 0.6);
}

12. Focus ring

Two zero-blur spread shadows draw a gap and a ring. The transparent outline matters: in Windows high contrast (forced colors) mode, box-shadow is forced to none but the outline is repainted in a system color, so keyboard users still see focus.

.button:focus-visible {
  outline: 2px solid transparent;
  outline-offset: 2px;
  box-shadow:
    0 0 0 2px #fff,
    0 0 0 4px #2563eb;
}

13. Border without layout shift

A spread-only shadow looks like a border but takes no space, so changing it on hover or selection never nudges the layout. For real borders with per-corner radius and styles, the CSS border generator is the better fit.

.option.is-selected {
  box-shadow: 0 0 0 2px #2563eb;
}

14. Bottom-only shadow

A negative spread roughly equal to the blur hides the shadow on the left and right, leaving it only under the element. Good for sticky headers and toolbars.

.sticky-header {
  box-shadow: 0 8px 6px -6px rgb(0 0 0 / 0.25);
}

15. Stacked paper

Alternating background-colored and shadow-colored layers, each with a negative spread, draw sheets peeking out underneath. The #f4f4f5 must match your page background.

.paper-stack {
  box-shadow:
    0 1px 1px rgb(0 0 0 / 0.15),
    0 10px 0 -5px #f4f4f5,
    0 10px 1px -4px rgb(0 0 0 / 0.15),
    0 20px 0 -10px #f4f4f5,
    0 20px 1px -9px rgb(0 0 0 / 0.15);
}

If you would rather tune these by eye, paste any of them into the CSS box shadow generator, which lets you adjust each layer's offset, blur, spread, opacity and inset with a live preview and copy the result.

Common mistakes and how to fix them

Shadows that are too dark

The most common problem is a single shadow at 30–50% black, which looks heavy and dated. Lower the opacity to somewhere around 5–15% per layer and add a second, larger layer instead. Also check the offset direction: if every shadow on the page has a positive y-offset, the light appears to come from above, and one element with a sideways shadow will look wrong.

Animating box-shadow directly

Shadows with blur are relatively expensive to paint, and animating box-shadow repaints on every frame. The web.dev animations guide recommends keeping animations to transform and opacity. For a hover lift, put the larger shadow on a pseudo-element and fade only its opacity:

.card {
  position: relative;
  isolation: isolate;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.1);
  transition: transform 0.2s;
}
.card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.15);
  opacity: 0;
  transition: opacity 0.2s;
}
.card:hover {
  transform: translateY(-2px);
}
.card:hover::after {
  opacity: 1;
}

A static shadow is fine. The cost only matters for animation and for very large blurs on many elements at once, so use your browser's performance tools if scrolling feels slow.

Forgetting dark mode

A black shadow on a near-black background is nearly invisible, so a card that relies on its shadow for separation disappears. In dark themes, separate surfaces with a slightly lighter background color and a subtle ring, and keep a stronger shadow for elevation:

@media (prefers-color-scheme: dark) {
  .card {
    background: #1f2937;
    box-shadow:
      0 0 0 1px rgb(255 255 255 / 0.08),
      0 8px 24px rgb(0 0 0 / 0.5);
  }
}

Relying on the shadow alone

Because forced colors mode removes box-shadow, any state that is shown only by a shadow (focus, selection, a pressed toggle) vanishes for those users. Back it up with an outline, border or text change. The MDN forced-colors page lists which properties are overridden.

Shadows that get clipped

If a parent has overflow: hidden (common on carousels and scroll containers), outer shadows are cut off at its edge. Add padding to the parent so the shadow has room.

box-shadow vs filter: drop-shadow()

filter: drop-shadow() looks similar but follows the element's actual visible shape (its alpha channel) rather than its rectangular box. That makes it the right choice for:

  • transparent PNGs and SVG icons, where box-shadow would draw a rectangle behind the image
  • shapes made with clip-path, which clips a box shadow away along with the box
  • speech-bubble tails and other shapes built from pseudo-elements, since the filter shadows the combined result
box-shadowfilter: drop-shadow()
ShapeElement's box, with border radiusVisible pixels (alpha)
SpreadYesNo
InsetYesNo
Multiple shadowsComma-separated listChain several drop-shadow() functions
.logo {
  filter: drop-shadow(0 4px 6px rgb(0 0 0 / 0.25));
}

Per MDN's drop-shadow() reference, the function takes the same values as box-shadow except that inset and spread are not allowed. Note that a filter applies to the element and all its children, so a drop shadow on a card also shadows the text inside it if the card has no background. For ordinary rectangular cards and buttons, stay with box-shadow.

Build your own shadow

The fastest way to get a shadow right is to see it while you change it. The CSS box shadow generator on ToolsVerse runs in your browser, is free and needs no account. Start from one of the examples above, stack layers, toggle inset, and copy the CSS when the preview looks right.

Key takeaways

  • The order is offset-x offset-y blur spread color, with optional inset; blur and spread default to 0.
  • The first shadow in a list is drawn on top, and shadows never change layout.
  • Use several low-opacity layers rather than one dark one for natural depth.
  • Animate opacity or transform of a shadowed pseudo-element instead of animating box-shadow.
  • Shadows disappear in forced colors mode and fade out in dark mode, so never let them carry meaning alone.
  • Use filter: drop-shadow() for transparent images and non-rectangular shapes.

Tools for this