Himanshu SharmaSoftware engineer
Let’s talk

CSS · Lesson 24 of 29

Shadows

Add depth with box-shadow and text-shadow, use offsets, blur, spread and inset, layer soft realistic shadows, and apply drop-shadow to images with transparency.

11 minPolishUpdated 18 October 2026

By the end of this lessonWrite box-shadow and text-shadow values, build soft layered shadows for cards and buttons, and know when a shadow hurts readability or performance.

Depth on a flat screen

Shadows suggest that one thing floats above another. Used with restraint, they tell the eye what is a card, what is a button and what is a pop-up. Used heavily, they make a page look dated and noisy. CSS has three shadow tools: box-shadow, text-shadow and the drop-shadow() filter.

box-shadow

css
box-shadow: offset-x offset-y blur spread color;
html
<style>
  body { background: #f1f5f9; padding: 16px; }
  .card { background: white; padding: 20px; border-radius: 12px; margin-bottom: 20px; }
  .s1 { box-shadow: 0 1px 3px rgb(0 0 0 / 0.2); }
  .s2 { box-shadow: 0 8px 24px rgb(15 23 42 / 0.15); }
  .s3 { box-shadow: 6px 6px 0 #1e293b; }               /* hard "sticker" shadow */
</style>
<div class="card s1">Small and subtle</div>
<div class="card s2">Soft and lifted</div>
<div class="card s3">Hard offset, no blur</div>
  • offset-x / offset-y: how far right and down (negative values go left and up).
  • blur: how soft the edge is. 0 is a crisp copy; larger is softer.
  • spread (optional): grows or shrinks the shadow before blurring.
  • color: nearly always a transparent dark colour such as rgb(0 0 0 / 0.15), so it blends with any background.

The first two lengths are required. With a light source above, a small positive vertical offset and no horizontal offset looks natural.

inset

Add inset to draw the shadow inside the box. It is good for pressed buttons and hollow input fields:

css
.input { box-shadow: inset 0 2px 4px rgb(0 0 0 / 0.12); }
.btn:active { box-shadow: inset 0 2px 6px rgb(0 0 0 / 0.3); }

Layered shadows

A single hard shadow rarely looks real. In life, a shadow is crisp and dark right under an object and wide and faint further away. Layer two or three comma-separated shadows:

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

Increase offset and blur together to show higher "elevation", for instance more for a dropdown than for a card. Pick a few levels and reuse them across the site, ideally as CSS variables (a later lesson).

Focus rings and glows

A shadow with no blur and a spread acts as a ring that follows rounded corners, and unlike outline it respects border-radius in every browser:

css
.field:focus-visible { box-shadow: 0 0 0 3px rgb(59 130 246 / 0.5); }

If you replace the default outline, keep the new focus indicator clearly visible. Note that in Windows high-contrast mode, shadows are removed, so keep a transparent outline as a backup: outline: 2px solid transparent;.

text-shadow

css
text-shadow: 1px 2px 3px rgb(0 0 0 / 0.4);

It takes offsets, a blur, and a colour (no spread). Use a faint shadow to lift text from a busy background. Heavy shadows and multiple glows reduce legibility and look amateurish. Never use a shadow to fix poor contrast; fix the colours.

drop-shadow for images and shapes

box-shadow always follows the rectangle of the element. A logo with a transparent background would get a rectangular shadow. The drop-shadow() filter follows the actual visible shape:

css
.logo { filter: drop-shadow(0 4px 6px rgb(0 0 0 / 0.25)); }

It works on PNG, WebP and SVG with transparency, and on any element's rendered shape.

Things to remember

  • Shadows take no layout space and do not affect neighbours. A big shadow can be clipped by a parent with overflow: hidden.
  • Large blurred shadows on many elements, or animated shadows, can slow older devices. Animate opacity or transform instead, or fade a pseudo-element's shadow.
  • In dark themes, shadows are less visible; use subtle borders or lighter surfaces to show elevation.
  • Never use a shadow as the only signal of a state (such as selected). Add colour, text or shape too.

Common mistakes

  • Pure black, fully opaque shadows, which look harsh.
  • Huge blur and spread values everywhere.
  • Shadows on text that reduce contrast.
  • Using box-shadow on transparent images instead of drop-shadow.
  • Animating box-shadow on big lists.

Exercise

Create a card with a three-layer soft shadow that grows slightly on hover (use a transition on box-shadow), and a button with an inset shadow when pressed.

Show one possible answer
html
<style>
  .card {
    padding: 20px; border-radius: 12px; background: white; max-width: 280px;
    box-shadow: 0 1px 2px rgb(0 0 0 / .08), 0 4px 8px rgb(0 0 0 / .08), 0 12px 24px rgb(0 0 0 / .08);
    transition: box-shadow .2s;
  }
  .card:hover { box-shadow: 0 2px 4px rgb(0 0 0 / .1), 0 8px 16px rgb(0 0 0 / .1), 0 24px 40px rgb(0 0 0 / .12); }
  .btn { padding: 8px 18px; border: 0; border-radius: 8px; background: #4f46e5; color: white; }
  .btn:active { box-shadow: inset 0 3px 6px rgb(0 0 0 / .35); }
</style>
<div class="card"><p>Hover me.</p><button class="btn">Press</button></div>

Key points

  • box-shadow takes horizontal offset, vertical offset, blur, spread and colour; inset puts it inside.
  • Subtle shadows look best, with a low-opacity colour, a soft blur and a small vertical offset.
  • Several comma-separated shadows layered together look more natural than a single heavy one.
  • text-shadow works on text, drop-shadow on the visible shape of an image, including transparent PNG and SVG.
  • Shadows do not take up layout space, and they must not be the only thing that signals a state.

Check yourself

1. In box-shadow: 4px 8px 12px rgb(0 0 0 / 0.2), what is 12px?
2. What does the inset keyword do?
3. Why layer several soft shadows?
4. Which works best to give a shadow to a transparent PNG logo?

Free tools for this lesson