CSS gradients and shadows: a practical recipe book
Gradients and shadows do most of the visual heavy lifting in modern interfaces, and a handful of patterns cover almost every case you will hit.
Linear gradients for backgrounds
A two-stop linear gradient at 135deg is the most common "brand" background:
.hero {
background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
}Adding a third stop lets you control the midpoint instead of relying on even interpolation:
.hero {
background: linear-gradient(135deg, #2563eb 0%, #6d28d9 55%, #db2777 100%);
}Radial gradients for spotlight effects
A radial gradient anchored off-center creates a "light source" look that works well behind hero text:
.spotlight {
background: radial-gradient(circle at 20% 20%, rgba(255,255,255,0.15), transparent 60%),
#0f172a;
}Conic gradients for progress and color wheels
Conic gradients sweep around a center point instead of across an axis, which makes them the natural tool for pie charts, loading rings and hue pickers:
.ring {
background: conic-gradient(#22c55e 0deg 216deg, #e5e7eb 216deg 360deg);
border-radius: 50%;
}216deg here represents 60% completion (0.6 × 360deg).
Layered box-shadows for depth
A single shadow looks flat; two or three layered shadows at different offsets and blur radii read as "elevation":
.card {
box-shadow:
0 1px 2px rgb(0 0 0 / 0.06),
0 4px 8px rgb(0 0 0 / 0.06),
0 12px 24px rgb(0 0 0 / 0.08);
}The tight, low-opacity shadow near the element simulates ambient occlusion; the larger, softer one simulates the cast shadow.
Inset shadows for pressed states
An inset shadow reads as "pushed in", which is exactly what you want for an active button or a focused input:
.button:active {
box-shadow: inset 0 2px 4px rgb(0 0 0 / 0.2);
}Glassmorphism, correctly
The look is a semi-transparent surface with a blurred backdrop and a subtle border:
.glass {
background: rgb(255 255 255 / 0.12);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgb(255 255 255 / 0.2);
}Always include the `-webkit-` prefix, and set a fallback background color for browsers or accessibility settings where `backdrop-filter` is disabled — otherwise text sitting on the "glass" becomes unreadable against whatever is behind it.
Rounded corners that scale with size
Match the border-radius to the element's role rather than using one value everywhere: small controls (4-6px), cards (12-16px), pill buttons (9999px). A radius that is too large on a small element looks like a rendering bug rather than a design choice.
Putting it together as tokens
Once you have shapes you like, extract them into CSS custom properties so the whole system stays consistent and easy to theme:
:root {
--shadow-sm: 0 1px 2px rgb(0 0 0 / 0.06);
--shadow-lg: 0 12px 24px rgb(0 0 0 / 0.12);
--radius-card: 12px;
--gradient-brand: linear-gradient(135deg, #2563eb, #7c3aed);
}Generators are for exploring the parameter space quickly; tokens are what actually ships.