Shadows in CSS add depth, separation, emphasis, and visual hierarchy. They are commonly used on cards, buttons, modals, dropdowns, sticky headers, images, text, and floating UI elements. A good shadow can make an interface feel layered. A bad shadow can make it look messy or heavy.
The main CSS shadow tools are box-shadow, text-shadow, and the drop-shadow() filter. They look similar at first, but they solve different problems.
box-shadow Syntax
The box-shadow property adds a shadow around an element box. The common syntax is horizontal offset, vertical offset, blur radius, optional spread radius, and color.
.card {
box-shadow: 0 12px 30px rgb(15 23 42 / 0.12);
}
The first value is x offset, the second is y offset, the third is blur, and the color controls shadow strength.
Shadow Offset
Positive x moves the shadow right. Negative x moves it left. Positive y moves it down. Negative y moves it up.
.floating {
box-shadow: 0 8px 20px rgb(0 0 0 / 0.18);
}
Most interface shadows use a positive y offset because light is usually imagined as coming from above.
Blur and Spread
The blur radius softens the shadow. The spread radius expands or shrinks the shadow before blur is applied.
.panel {
box-shadow: 0 10px 25px 4px rgb(0 0 0 / 0.12);
}
Use spread carefully. Large spread values can make shadows feel like glows or dirty borders.
Inset Shadows
The inset keyword places the shadow inside the element.
.input {
box-shadow: inset 0 1px 3px rgb(0 0 0 / 0.12);
}
Inset shadows can make inputs, panels, or pressed buttons feel recessed. Keep them subtle for modern UI.
Multiple Box Shadows
An element can have multiple shadows separated by commas. Layered shadows often look more natural than one harsh shadow.
.card {
box-shadow:
0 1px 2px rgb(15 23 42 / 0.08),
0 12px 30px rgb(15 23 42 / 0.12);
}
The first shadow adds a small contact shadow. The second adds softer depth. This creates a more realistic elevation effect.
Text Shadow
The text-shadow property adds shadows to text. It uses x offset, y offset, blur radius, and color.
.hero-title {
text-shadow: 0 2px 12px rgb(0 0 0 / 0.45);
}
Text shadows can improve readability over images, but they can also make text blurry. Use them lightly.
drop-shadow Filter
The drop-shadow() filter creates a shadow based on the visible shape of an element, including transparent areas. This is different from box-shadow, which follows the element box.
.logo {
filter: drop-shadow(0 8px 12px rgb(0 0 0 / 0.2));
}
This is useful for transparent PNGs, SVG icons, irregular shapes, and images where a rectangular box shadow would look wrong.
box-shadow vs drop-shadow
| Feature | box-shadow | drop-shadow |
|---|---|---|
| Shape | element box | visible pixels |
| Inset support | yes | no |
| Multiple shadows | yes | can chain filters |
| Common use | cards and panels | icons and transparent images |
Use box-shadow for normal UI surfaces. Use drop-shadow when the visible shape is not rectangular.
Elevation System
Large projects often define shadow levels. This keeps cards, dropdowns, modals, and popovers visually consistent.
:root {
--shadow-sm: 0 1px 2px rgb(15 23 42 / 0.08);
--shadow-md: 0 8px 20px rgb(15 23 42 / 0.12);
--shadow-lg: 0 20px 45px rgb(15 23 42 / 0.18);
}
.modal {
box-shadow: var(--shadow-lg);
}
Named shadow tokens are easier to maintain than random shadow values on every component.
Colored Shadows
Shadows do not have to be black. A subtle color can match a brand or glow effect.
.primary-card {
box-shadow: 0 16px 40px rgb(37 99 235 / 0.22);
}
Colored shadows should be used carefully. Strong colored glows can quickly make a design look noisy.
Performance
Large blurred shadows can be expensive, especially on many moving elements. Shadows on static cards are usually fine. Shadows on animated lists, large sticky elements, or frequent hover effects should be tested.
For smoother motion, animate transform or opacity instead of animating heavy shadow values. If the shadow must change, keep the difference subtle.
Accessibility and Shadows
Do not rely only on shadows to communicate state. A focused input should have a clear outline or border, not only a faint shadow. A disabled button should use more than a shadow change.
.button:focus-visible {
outline: 3px solid #93c5fd;
box-shadow: 0 0 0 6px rgb(147 197 253 / 0.35);
}
The outline gives a reliable focus indicator. The shadow adds visual support.
Shadow Tokens
A shadow system is easier to maintain when shadows are stored as tokens. Components can use the same shadow levels instead of inventing new values each time.
:root {
--shadow-1: 0 1px 2px rgb(15 23 42 / 0.08);
--shadow-2: 0 8px 24px rgb(15 23 42 / 0.12);
--shadow-3: 0 24px 60px rgb(15 23 42 / 0.2);
}
.dropdown {
box-shadow: var(--shadow-2);
}
This makes elevation predictable. A dropdown, popover, and modal can each use a known layer rather than a random shadow.
Contact Shadows
A contact shadow is a small, close shadow that makes an element feel attached to the surface below it. It is often paired with a larger soft shadow.
.floating-card {
box-shadow:
0 2px 4px rgb(15 23 42 / 0.10),
0 18px 40px rgb(15 23 42 / 0.14);
}
The small shadow gives contact. The large shadow gives elevation. Together they look more natural than one heavy blur.
Shadows in Dark UI
Shadows are less visible on dark backgrounds. Dark interfaces often need a mix of subtle shadows, borders, highlights, and background contrast to show depth.
.dark-card {
background: #111827;
border: 1px solid rgb(255 255 255 / 0.08);
box-shadow: 0 18px 45px rgb(0 0 0 / 0.35);
}
The border helps separate the card edge, while the shadow adds depth. On dark UI, relying only on shadow may not be enough.
Neumorphism Warning
Soft inner and outer shadows can create a neumorphic look, but this style often has weak contrast and unclear affordances. Buttons may not look clickable, and focus states can become hard to see.
If using soft UI effects, keep contrast strong and add clear states for hover, focus, active, and disabled controls.
Debugging Shadows
If a shadow is not visible, check overflow clipping, background color, stacking, and whether the element has enough space around it. Parents with overflow: hidden can cut off shadows.
- Check parent overflow.
- Check whether the shadow color has enough opacity.
- Check whether the background is too similar.
- Check border-radius because shadows follow the rounded box.
- Check performance if many large shadows animate.
- Check focus visibility without relying only on shadow.
Shadows and Border Radius
Box shadows follow the border radius of the element. This helps rounded cards, pills, and modals look natural.
.rounded-card {
border-radius: 18px;
box-shadow: 0 16px 40px rgb(15 23 42 / 0.14);
}
If the shadow looks clipped, check the parent element for overflow: hidden. The card itself may be correct, but an ancestor may be cutting off the blur.
Focus Rings with box-shadow
Box shadow can create focus rings that do not affect layout. This is useful for inputs, buttons, and custom controls.
.control:focus-visible {
outline: 2px solid #2563eb;
box-shadow: 0 0 0 5px rgb(37 99 235 / 0.25);
}
The outline provides strong accessibility, and the shadow adds a softer outer ring. This combination is clearer than a faint glow alone.
Inner Glow Effects
Inset shadows can also create inner glow effects. This is useful for badges, active tabs, or selected cards when used carefully.
.active-tab {
box-shadow: inset 0 -3px 0 #2563eb;
}
This creates an underline-like active state inside the element. It avoids moving layout because the line is drawn as a shadow.
Shadow Design Rule
The shadow should match the surface. Small controls need small shadows or no shadow. Floating panels and modals can use stronger shadows. If every element has a large shadow, nothing feels elevated because everything is competing for attention.
Shadow and Light Direction
A consistent light direction makes shadows feel more believable. Most interfaces assume light from above, so shadows usually fall downward. If some elements cast shadows upward and others downward without reason, the design feels inconsistent.
.surface {
box-shadow: 0 10px 24px rgb(15 23 42 / 0.12);
}
The positive vertical offset suggests the element is lifted from the surface. Keep similar components using similar offset logic.
Shadows with Transparent Elements
For transparent PNGs, SVG shapes, and irregular icons, drop-shadow() often looks better than box-shadow because it follows visible pixels instead of the rectangular element box.
.chip-icon {
filter: drop-shadow(0 6px 8px rgb(0 0 0 / 0.18));
}
Use this when the rectangular box shadow would expose the element boundary and make the effect look fake.
Shadow Checklist
- Use small shadows for small surfaces.
- Use stronger shadows for overlays and modals.
- Keep light direction consistent.
- Use drop-shadow for transparent shapes.
- Check parent overflow when shadows are clipped.
- Do not rely only on shadow for focus or state.
Shadow quality is mostly about restraint. If the shadow is the first thing users notice, it is probably too strong for normal interface work.
Common Shadow Mistakes
- Using shadows that are too dark or too blurry.
- Applying random shadow values without a system.
- Using text shadows that reduce readability.
- Using box-shadow on transparent images where drop-shadow fits better.
- Animating heavy shadows on many elements.
- Relying only on shadows for focus or disabled states.
Shadows in CSS FAQ
What is box-shadow in CSS?
box-shadow adds a shadow around an element box using offsets, blur, spread, and color.
What is the difference between box-shadow and drop-shadow?
box-shadow follows the element box, while drop-shadow follows the visible shape of the element.
Can CSS have multiple shadows?
Yes. box-shadow and text-shadow can use comma-separated multiple shadows.
Are shadows bad for performance?
Not always. Static shadows are usually fine, but large animated shadows can be expensive.
Continue learning CSS in order
Follow the topic sequence with the previous and next lesson.