Neumorphism in CSS — Soft UI Box Shadows and Design Patterns
Neumorphism uses two box shadows — one light, one dark — to create soft extruded or inset UI elements. Learn how to implement neumorphic CSS buttons, cards, and inputs with the...
Neumorphism (soft UI) simulates physical depth by casting two shadows: a light shadow on the top-left and a dark shadow on the bottom-right, on a background that matches the element. The element appears to extrude from or indent into the surface.
Use the Box Shadow Generator to build neumorphic shadows visually.
The neumorphic formula
/* Background and element must share the same color */
:root {
--bg: #e0e5ec;
--shadow-light: #ffffff;
--shadow-dark: #a3b1c6;
}
.card {
background: var(--bg);
border-radius: 20px;
/* Extruded (raised) effect: */
box-shadow:
8px 8px 16px var(--shadow-dark),
-8px -8px 16px var(--shadow-light);
}
The key: --bg, --shadow-light, and --shadow-dark are derived from the same base color. Light shadow is a lighter tint; dark shadow is a darker shade.
Generating shadow colors from a base
/* Given base color #e0e5ec: */
/* Light shadow ≈ base + 15% lightness */
/* Dark shadow ≈ base - 15% lightness */
:root {
--bg: #e0e5ec;
--shadow-light: color-mix(in srgb, #e0e5ec 70%, white);
--shadow-dark: color-mix(in srgb, #e0e5ec 70%, #9baacf);
}
Or calculate manually:
Base: #e0e5ec (hsl: 216, 27%, 90%)
Light: hsl(216, 27%, 100%) → #ffffff
Dark: hsl(216, 27%, 72%) → #a3b1c6
Extruded vs pressed states
.button {
background: #e0e5ec;
border-radius: 12px;
cursor: pointer;
border: none;
padding: 16px 32px;
transition: box-shadow 0.15s ease;
/* Default: raised */
box-shadow:
6px 6px 12px #a3b1c6,
-6px -6px 12px #ffffff;
}
/* Pressed: inset shadows */
.button:active {
box-shadow:
inset 4px 4px 8px #a3b1c6,
inset -4px -4px 8px #ffffff;
}
/* Hover: slightly more pronounced */
.button:hover {
box-shadow:
10px 10px 20px #a3b1c6,
-10px -10px 20px #ffffff;
}
Neumorphic input field
.input-field {
background: #e0e5ec;
border: none;
border-radius: 10px;
padding: 14px 18px;
font-size: 1rem;
color: #4a5568;
outline: none;
/* Inset = field is recessed into surface */
box-shadow:
inset 4px 4px 8px #a3b1c6,
inset -4px -4px 8px #ffffff;
transition: box-shadow 0.2s ease;
}
.input-field:focus {
box-shadow:
inset 6px 6px 12px #a3b1c6,
inset -6px -6px 12px #ffffff;
}
Neumorphic card component
.neo-card {
background: #e0e5ec;
border-radius: 24px;
padding: 32px;
box-shadow:
12px 12px 24px #b8c2d0,
-12px -12px 24px #ffffff;
}
.neo-card__icon {
width: 60px;
height: 60px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16px;
/* Inset icon circle */
box-shadow:
inset 4px 4px 8px #b8c2d0,
inset -4px -4px 8px #ffffff;
}
.neo-card__button {
background: #e0e5ec;
border: none;
border-radius: 12px;
padding: 12px 24px;
cursor: pointer;
box-shadow:
4px 4px 8px #b8c2d0,
-4px -4px 8px #ffffff;
transition: all 0.15s ease;
}
.neo-card__button:active {
box-shadow:
inset 3px 3px 6px #b8c2d0,
inset -3px -3px 6px #ffffff;
}
Toggle / switch
.neo-toggle {
width: 64px;
height: 32px;
background: #e0e5ec;
border-radius: 16px;
position: relative;
cursor: pointer;
box-shadow:
inset 3px 3px 6px #a3b1c6,
inset -3px -3px 6px #ffffff;
}
.neo-toggle::after {
content: '';
position: absolute;
width: 24px;
height: 24px;
border-radius: 50%;
top: 4px;
left: 4px;
background: #e0e5ec;
transition: transform 0.2s ease, box-shadow 0.2s ease;
box-shadow:
3px 3px 6px #a3b1c6,
-3px -3px 6px #ffffff;
}
.neo-toggle.active::after {
transform: translateX(32px);
background: linear-gradient(145deg, #6a9bf4, #4a7ef0);
box-shadow:
3px 3px 6px #3a6ad8,
-3px -3px 6px #7ab0ff;
}
Accessibility considerations
Neumorphism has real accessibility problems:
/* Problem: low contrast on the same background */
/* Solution: add visible border on focus */
.neo-button:focus-visible {
outline: 3px solid #4a7ef0;
outline-offset: 2px;
}
/* Use WCAG color contrast checker — neumorphic text
on the same background often fails AA (4.5:1) */
/* Don't rely solely on shadow depth to indicate state.
Add color change or icon change for color-blind users */
.neo-button.active {
box-shadow: inset 4px 4px 8px #a3b1c6, inset -4px -4px 8px #ffffff;
color: #4a7ef0; /* Color change too, not just shadow */
}
Related tools
- Box Shadow Generator — generate and preview box shadows
- CSS Box Shadow Guide — box-shadow syntax reference
- CSS Shadow Animation — animating shadows on hover
Related posts
- Animating CSS Box Shadows — Smooth Hover Effects and Transitions — CSS box-shadow transitions create smooth hover effects for cards and buttons. He…
- CSS Box Shadow Performance — GPU Compositing and Repaint Optimization — Box shadows can hurt scroll and animation performance if used incorrectly. Learn…
- Colored Box Shadow in CSS — Glow Effects and Color Shadows — CSS box-shadow isn't limited to black. Create colored glows, neon effects, brand…
- CSS Box Shadow Examples — Generate and Customize Shadow Effects — CSS box-shadow creates drop shadows, inset shadows, and layered shadow effects. …
- CSS Box Shadow — How to Use box-shadow Correctly — CSS box-shadow adds depth, elevation, and focus effects to elements. Here's the …
Related tool
Visual CSS box-shadow builder. Control offset, blur, spread, color, inset. Multi-layer shadows. Live preview + copyable CSS.
Written by Mian Ali Khalid. Part of the Frontend & Design pillar.