CSS shadows are visual effects that create the illusion of depth and elevation in web design. They simulate how light interacts with objects in the real world, casting shadows that help users understand spatial relationships between elements. Shadows are fundamental to modern UI design, particularly in Material Design and neumorphism, where they indicate which elements are interactive, elevated, or layered above others.
CSS provides three main shadow properties: box-shadow for element boxes, text-shadow for text, and filter: drop-shadow() for complex shapes. Each serves different purposes and has unique characteristics. Understanding when and how to use each type is crucial for creating polished, professional interfaces.
The box-shadow property adds shadow effects around an element's frame (box). It's the most commonly used shadow property and is essential for creating cards, buttons, modals, and other elevated UI components.
/* Syntax: box-shadow: [inset] offset-x offset-y [blur-radius] [spread-radius] color */
.element {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
/* ↑ ↑ ↑ ↑
│ │ │ └─ Color (with alpha transparency)
│ │ └───── Blur radius (optional, default: 0)
│ └───────── Vertical offset (required)
└─────────── Horizontal offset (required)
*/
}
/* With all parameters */
.complete {
box-shadow: 2px 4px 8px 2px rgba(0, 0, 0, 0.2);
/* ↑ ↑ ↑ ↑ ↑
│ │ │ │ └─ Color
│ │ │ └───── Spread radius (expands/contracts shadow)
│ │ └───────── Blur radius (softness)
│ └───────────── Vertical offset (down if positive)
└───────────────── Horizontal offset (right if positive)
*/
}
/* Inset shadow (inner shadow) */
.inset {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
}
| Parameter | Description | Values | Effect |
|---|---|---|---|
| offset-x | Horizontal offset | Positive = right, Negative = left | Required |
| offset-y | Vertical offset | Positive = down, Negative = up | Required |
| blur-radius | Blur amount | 0 = sharp, higher = softer | Optional (default: 0) |
| spread-radius | Shadow size | Positive = expand, Negative = contract | Optional (default: 0) |
| color | Shadow color | Any CSS color (rgba recommended) | Optional (default: currentColor) |
| inset | Inner shadow | Keyword before other values | Optional |
/* 1. Subtle tl-card Shadow (Material Design inspired) */
.card-subtle {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12),
0 1px 2px rgba(0, 0, 0, 0.24);
}
/* 2. Elevated tl-card (Medium depth) */
.card-elevated {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1),
0 2px 4px rgba(0, 0, 0, 0.06);
}
/* 3. Floating tl-card (High elevation) */
.card-floating {
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15),
0 5px 10px rgba(0, 0, 0, 0.05);
}
/* 4. Button Shadow (Interactive) */
.button {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease;
}
.button:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
.button:active {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
/* 5. Inset Shadow (Pressed/Sunken effect) */
.input-field {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.06);
border: 1px solid #e5e7eb;
}
.input-field:focus {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.06),
0 0 0 3px rgba(59, 130, 246, 0.1);
}
/* 6. Colored Shadow (Brand emphasis) */
.button-primary {
background: #3b82f6;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}
/* 7. Neumorphism (Soft UI) */
.neumorphic {
background: #e0e5ec;
box-shadow: 9px 9px 16px rgba(163, 177, 198, 0.6),
-9px -9px 16px rgba(255, 255, 255, 0.5);
}
/* 8. Layered Modal Shadow */
.modal {
box-shadow: 0 20px 25px rgba(0, 0, 0, 0.1),
0 10px 10px rgba(0, 0, 0, 0.04),
0 0 0 1px rgba(0, 0, 0, 0.05);
}
/* 9. Bottom-only Shadow */
.bottom-shadow {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
/* 10. Glow Effect */
.glow {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.6),
0 0 40px rgba(59, 130, 246, 0.4);
}
The text-shadow property adds shadow effects to text. Unlike box-shadow, it doesn't support the spread-radius or inset keyword. Text shadows are commonly used for headings, logos, and creating text effects like embossing or glowing text.
/* Syntax: text-shadow: offset-x offset-y blur-radius color */
/* 1. Simple Text Shadow */
.heading {
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
/* 2. Multiple Text Shadows */
.logo {
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3),
0 0 10px rgba(255, 255, 255, 0.5);
}
/* 3. Embossed Text Effect */
.embossed {
color: #333;
background: #ddd;
text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.8),
-1px -1px 0 rgba(0, 0, 0, 0.3);
}
/* 4. Engraved Text Effect */
.engraved {
color: #666;
background: #ddd;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8),
0 -1px 0 rgba(0, 0, 0, 0.3);
}
/* 5. Glowing Text */
.glow-text {
color: #fff;
text-shadow: 0 0 10px #00ff00,
0 0 20px #00ff00,
0 0 30px #00ff00;
}
/* 6. 3D Text Effect */
.text-3d {
color: #fff;
text-shadow: 0 1px 0 #ccc,
0 2px 0 #c9c9c9,
0 3px 0 #bbb,
0 4px 0 #b9b9b9,
0 5px 0 #aaa,
0 6px 1px rgba(0, 0, 0, 0.1),
0 0 5px rgba(0, 0, 0, 0.1),
0 1px 3px rgba(0, 0, 0, 0.3),
0 3px 5px rgba(0, 0, 0, 0.2),
0 5px 10px rgba(0, 0, 0, 0.25);
}
/* 7. Outline Text */
.outline-text {
color: #fff;
text-shadow: -1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
}
/* 8. Soft Shadow for Readability */
.readable {
color: #fff;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}
The drop-shadow() filter function creates a shadow that follows the alpha channel of an image or element, rather than just the box. This is particularly useful for PNG images with transparency, SVG graphics, and elements with complex shapes. Unlike box-shadow, drop-shadow() respects the actual shape of the content.
/* Syntax: filter: drop-shadow(offset-x offset-y blur-radius color) */
/* 1. Basic Drop Shadow */
.icon {
filter: drop-shadow(2px 2px 4px rgba(0, 0, 0, 0.3));
}
/* 2. PNG Image with Transparency */
.logo-png {
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2));
}
/* 3. SVG Icon Shadow */
.svg-icon {
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.15));
}
/* 4. Multiple Drop Shadows */
.complex-shape {
filter: drop-shadow(2px 2px 2px rgba(0, 0, 0, 0.2))
drop-shadow(4px 4px 4px rgba(0, 0, 0, 0.1));
}
/* 5. Colored Drop Shadow */
.colored-icon {
filter: drop-shadow(0 4px 8px rgba(59, 130, 246, 0.5));
}
/* Comparison: box-shadow vs drop-shadow */
.with-box-shadow {
/* Shadow follows the rectangular box */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.with-drop-shadow {
/* Shadow follows the actual shape (alpha channel) */
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2));
}
| Feature | box-shadow | filter: drop-shadow() |
|---|---|---|
| Shadow Shape | Follows element's box | Follows alpha channel (actual shape) |
| Transparency Support | No - shadows rectangular box | Yes - respects PNG/SVG transparency |
| Multiple Shadows | Yes (comma-separated) | Yes (multiple filter functions) |
| Inset Support | Yes (inset keyword) | No |
| Spread Radius | Yes (4th parameter) | No |
| Performance | Better (GPU accelerated) | Slower (requires repainting) |
| Browser Support | Excellent (all modern browsers) | Good (IE not supported) |
| Best For | Cards, buttons, containers | PNG images, SVG icons, complex shapes |
Combining multiple shadows creates more realistic depth by simulating how light scatters in the real world.
/* Material Design Elevation Levels */
.elevation-1 {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12),
0 1px 2px rgba(0, 0, 0, 0.24);
}
.elevation-2 {
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16),
0 3px 6px rgba(0, 0, 0, 0.23);
}
.elevation-3 {
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19),
0 6px 6px rgba(0, 0, 0, 0.23);
}
.elevation-4 {
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25),
0 10px 10px rgba(0, 0, 0, 0.22);
}
.elevation-5 {
box-shadow: 0 19px 38px rgba(0, 0, 0, 0.30),
0 15px 12px rgba(0, 0, 0, 0.22);
}
/* Realistic Shadow (3 layers) */
.realistic-card {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05), /* Ambient shadow */
0 8px 16px rgba(0, 0, 0, 0.1), /* Penumbra */
0 16px 32px rgba(0, 0, 0, 0.05); /* Umbra */
}
/* Hover Lift Effect */
.card-lift {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card-lift:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
/* Button Press Effect */
.button-press {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
transition: all 0.1s ease;
}
.button-press:active {
transform: translateY(2px);
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
}
/* Pulsing Glow Animation */
@keyframes pulse-glow {
0%, 100% {
box-shadow: 0 0 10px rgba(59, 130, 246, 0.5);
}
50% {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.8),
0 0 30px rgba(59, 130, 246, 0.6);
}
}
.pulse {
animation: pulse-glow 2s ease-in-out infinite;
}
| Mistake | Problem | Solution |
|---|---|---|
| Too dark shadows | Looks harsh and unrealistic | Use opacity 0.1-0.3 instead of 0.5+ |
| No blur radius | Sharp, unnatural shadows | Always add blur (4px-20px typical) |
| Inconsistent direction | Confusing visual hierarchy | Keep light source consistent |
| Using pure black | Too harsh, doesn't match real shadows | Use rgba(0, 0, 0, 0.1-0.3) |
| Too many shadows | Performance issues, visual clutter | Limit to 2-3 layers maximum |
| Wrong shadow type | box-shadow on transparent PNGs | Use drop-shadow() for transparency |
| Property | Chrome | Firefox | Safari | Edge | IE |
|---|---|---|---|---|---|
box-shadow | ✓ 10+ | ✓ 4+ | ✓ 5.1+ | ✓ 12+ | ✓ 9+ |
text-shadow | ✓ 4+ | ✓ 3.5+ | ✓ 4+ | ✓ 12+ | ✓ 10+ |
drop-shadow() | ✓ 18+ | ✓ 35+ | ✓ 9+ | ✓ 79+ | ✗ No |
box-shadow is GPU-accelerated in most browserswill-change: box-shadow for frequently animated shadowsdrop-shadow() only when necessary (transparency)Explore 500+ free tutorials across 20+ languages and frameworks.