The default direction most people reach for first. Horizontal flows naturally for western reading patterns.
1. linear-gradient
The workhorse of CSS gradients. The first argument is the direction: either a keyword like to right or an angle in degrees. Everything after that is a list of colors (and optionally where each color starts). You can chain as many stops as you want.
Useful for hero sections where you want a colour to fade into the page below it.
135° is probably the sweet-spot for diagonal. Feels dynamic without looking tilted.
Worth knowing: 0deg goes bottom-to-top, not left-to-right. Every 90° rotates the direction clockwise.
Just keep adding colours. CSS space them evenly by default, or you can give each one an explicit position.
Put two colour stops at the same percentage and you get a hard edge instead of a blend. Useful for stripes and flags.
You can approximate a full rainbow by stepping through the hue wheel. Five stops gets you close enough.
Fading to rgba(color, 0) instead of white or black lets the element dissolve into whatever's behind it.
/* Direction keywords */
background: linear-gradient(to right, #6366f1, #a855f7);
background: linear-gradient(to bottom, #6366f1, #ec4899);
background: linear-gradient(to bottom right, #6366f1, #06b6d4);
/* Angle in degrees (0deg = bottom→top, 90deg = left→right) */
background: linear-gradient(135deg, #6366f1, #06b6d4);
/* Multiple color stops */
background: linear-gradient(to right, #6366f1, #a855f7, #ec4899);
/* Explicit stop positions */
background: linear-gradient(to right, #6366f1 0%, #a855f7 50%, #ec4899 100%);
/* Hard stop - no blend between colors */
background: linear-gradient(to right, #6366f1 50%, #ec4899 50%);
/* Fade to transparent */
background: linear-gradient(to bottom, rgba(99, 102, 241, 0.9), rgba(99, 102, 241, 0));2. radial-gradient
Where linear-gradient draws a line, radial-gradient expands outward from a point. You pick the shape (circle stays perfectly round; ellipse stretches to fill the box), where the centre sits, and how far the gradient reaches before it stops blending.
Bright in the middle, dark at the edges. Works well for spot-lit product shots.
The browser's default if you leave out the shape keyword. It auto-sizes to the element's aspect ratio, so it rarely looks perfectly circular.
Moving the origin to an edge or corner makes it look like light is coming from outside the frame. Very popular in dark-mode hero sections.
Corner origins give you that cinematic wide-angle lens flare feel.
closest-side stops the gradient at whichever side of the box is nearest to the centre. Handy when you need tight control over the falloff radius.
Stack enough stops and you end up with a bullseye. Not always practical, but it shows how stop positions work radially.
This is the pattern behind most "hero glow" designs: a wide, semi-transparent ellipse at the top that fades into the dark background below it.
A 1px circle fading to transparent, tiled with background-size. Zero images, just CSS. You can change the dot colour or spacing with a couple of variables.
/* Circle from center */
background: radial-gradient(circle, #6366f1, #1e1b4b);
/* Ellipse (default shape) */
background: radial-gradient(ellipse, #06b6d4, #0c4a6e);
/* Position: at keyword or percentage */
background: radial-gradient(circle at top, #a855f7, #1e1b4b);
background: radial-gradient(circle at 30% 70%, #f59e0b, #451a03);
/* Size keywords: closest-side | farthest-side | closest-corner | farthest-corner */
background: radial-gradient(circle closest-side, #10b981, #022c22);
/* Explicit size */
background: radial-gradient(ellipse 80% 50% at 50% 0%, rgba(99,102,241,0.4), transparent);
/* Multi-stop rings */
background: radial-gradient(circle, #fff 0%, #c7d2fe 30%, #6366f1 70%, #1e1b4b 100%);
/* Dot pattern with background-size */
background-image: radial-gradient(circle, #94a3b8 1px, transparent 1px);
background-size: 1.5rem 1.5rem;3. conic-gradient
conic-gradient is the newest of the three and genuinely fun to work with. Instead of radiating outward, it sweeps around a centre point like the hands of a clock. That makes it the only CSS-native way to draw a pie chart without JavaScript or SVG. It's also surprisingly good at checkerboards and sunburst patterns.
Six colours spread across 360° gives you a rough colour wheel. Round it off with border-radius: 50%.
Each slice is defined by a start and end percentage. The math is just addition, and unlike SVG you can update the percentages with a CSS variable.
By default the sweep starts at 3 o'clock (east). from -90deg rotates it to 12, which is what people expect for a clock or gauge.
Same idea as hard stops in linear-gradient. Pair the end of one colour with the start of the next and you get a clean solid edge with no blend.
Two colours alternating every 30° gives you a starburst. Twelve stops total and the browser handles the rest.
Four 90° hard stops + background-size tiling = checkerboard. If you've ever wondered how Figma does its transparency grid, this is exactly it.
/* Color wheel */
background: conic-gradient(#6366f1, #a855f7, #ec4899, #f59e0b, #10b981, #06b6d4, #6366f1);
/* Pie chart - hard stop segments */
background: conic-gradient(
#6366f1 0% 40%, /* 40% slice */
#a855f7 40% 65%, /* 25% slice */
#ec4899 65% 80%, /* 15% slice */
#f59e0b 80% 100% /* 20% slice */
);
border-radius: 50%;
/* Start from -90deg (12 o'clock) */
background: conic-gradient(from -90deg, #6366f1, #ec4899, #f59e0b, #6366f1);
/* Checkerboard with background-size */
background:
conic-gradient(#e5e7eb 90deg, #fff 90deg 180deg, #e5e7eb 180deg 270deg, #fff 270deg);
background-size: 2rem 2rem;4. Gradient Text
The trick is simple: apply a gradient as the background, then clip it to the text shape with background-clip: text and make the text itself transparent so the background shows through. Browser support is solid now, but keep the -webkit-background-clip prefix because Safari still needs it. Not great for body text (contrast audits will hate you), but brilliant for headlines.
Four-stop diagonal, the classic starting point. Add more stops or tighten the angle to taste.
Dark amber → bright yellow → near-white → back again. The symmetry of the stops is what gives it that metallic highlight look.
Make the gradient twice as wide as the element, then slide the position. The text stays put but the colours move underneath it.
Top-to-bottom direction means warm tones at the top of the letters and cool ones at the bottom. Works really well on tall letterforms.
Monochromatic gradients (different shades of one hue) feel more refined than multi-colour ones. Sky blues work well for tech brands.
Real fire is hottest at the base and cooler at the tips. to top puts the reds at the bottom and the yellows up top, which maps to that naturally.
/* The gradient text recipe */
.gradient-text {
background-image: linear-gradient(135deg, #6366f1, #a855f7, #ec4899);
-webkit-background-clip: text; /* Safari */
background-clip: text;
-webkit-text-fill-color: transparent; /* Safari */
color: transparent;
}
/* Animated shimmer - oversized background moves via animation */
.shimmer-text {
background-image: linear-gradient(90deg, #22d3ee, #10b981, #22d3ee);
background-size: 200%; /* twice as wide as the element */
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
animation: shimmer 3s linear infinite;
}
@keyframes shimmer {
0% { background-position: 200% center; }
100% { background-position: 0% center; }
}5. Layered & Multi-background Gradients
CSS lets you stack as many gradients on top of each other as you want, separated with commas. The first one in the list sits on top. Combine a few semi-transparent radial gradients and you can replicate the "noise + gradient" aesthetic that's been everywhere in design tool exports lately, without a single exported image.
Three semi-transparent radial blobs (top-left, bottom-right, centre) that mix where they overlap. This is how most "mesh gradient" generators work under the hood.
Two wide, off-screen ellipses bleeding inward. You see this in basically every dark-mode SaaS landing page right now.
Three linear gradients stacked: one from the bottom, one from the top, one as the base. Each is opaque only at its end and transparent in the middle, so they blend into each other.
A 15% white diagonal sheen on top of a solid gradient. It's what gives glassmorphism cards that slightly lighter upper-left corner.
repeating-linear-gradient tiles automatically. Define a stripe once and it repeats forever. Layer it at 7% opacity and it reads as texture rather than pattern.
SVG turbulence filter base64'd into a url() and layered over the gradient at 8% opacity. Same grainy texture that design tools export, but no image files involved.
/* Multiple backgrounds - first listed is on top */
background:
radial-gradient(ellipse at top left, rgba(99,102,241,0.5) 0%, transparent 60%),
radial-gradient(ellipse at bottom right,rgba(168,85,247,0.5) 0%, transparent 60%),
radial-gradient(ellipse at center, rgba(236,72,153,0.3) 0%, transparent 70%),
#0f172a;
/* Glass sheen overlay */
background:
linear-gradient(135deg, rgba(255,255,255,0.15) 0%, rgba(255,255,255,0.02) 100%),
linear-gradient(135deg, #6366f1, #4f46e5);
/* Diagonal repeating stripes as texture */
background:
repeating-linear-gradient(
-45deg,
rgba(255,255,255,0.07) 0px,
rgba(255,255,255,0.07) 10px,
transparent 10px,
transparent 20px
),
linear-gradient(135deg, #6366f1, #4f46e5);6. Animated Gradients
Here's the awkward truth: CSS can't tween between two gradient definitions directly. You can't smoothly animate from one colour palette to another the way you'd animate a colour property. But there are a few clever workarounds: sliding an oversized gradient's position, rotating its hue with a filter, or using a pseudo-element as the moving part. Each has its place.
The go-to technique. Make the gradient 3× wider than the element and animate background-position back and forth. The visible window stays the same; the colours scroll underneath it.
One line of CSS, zero extra elements. The gradient itself never changes; hue-rotate just shifts all its colours through the wheel. Worth noting: it affects child elements too.
Same technique as above but faster and with fewer colours. 2s feels urgent rather than ambient, which works well for a CTA button you want people to click.
A thin white diagonal stripe in a ::after element slides from right to left continuously. This is the exact pattern used in skeleton loading screens.
Cheat: animate box-shadow spread instead. The gradient stays static, the glow around it breathes. Lighter on the browser than animating background properties.
/* Technique 1: animate background-position on oversized gradient */
.animated-gradient {
background: linear-gradient(270deg, #6366f1, #a855f7, #ec4899, #f59e0b, #6366f1);
background-size: 300% 300%; /* must be larger than element */
animation: gradientShift 6s ease infinite;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* Technique 2: hue-rotate filter - simplest approach */
.hue-animated {
background: linear-gradient(135deg, #6366f1, #06b6d4);
animation: hueRotate 4s linear infinite;
}
@keyframes hueRotate {
to { filter: hue-rotate(360deg); }
}
/* Technique 3: ::after sweep shimmer */
.shimmer-element {
position: relative;
overflow: hidden;
background: #1e1b4b;
}
.shimmer-element::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(105deg, transparent 40%, rgba(255,255,255,0.15) 50%, transparent 60%);
background-size: 200% 100%;
animation: sweep 2s linear infinite;
}
@keyframes sweep {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}7. Gradient Borders
There's no border-gradient property in CSS, so you have to be creative. Of the four approaches below, Method 2 (the ::before trick) is the one I'd reach for in most projects: it supports rounded corners, works in every browser, and the code is straightforward enough to understand at a glance.
One property, done. Catch: border-image and border-radius can't be used together. The spec forbids it. Square corners only.
The background element sits 2px outside on all sides, fully behind the main element. border-radius: inherit means they curve together automatically.
Two backgrounds in one declaration: a white one clipped to the padding area, and the gradient clipped all the way to the border edge. No extra elements needed, but the syntax takes a second read.
Requires the @property rule (well-supported, not IE). Without it the browser can't interpolate --angle and the animation jumps instead of spinning.
Not technically a gradient border, but on dark backgrounds the inset + outer box-shadow combo looks identical and requires zero tricks. Worth keeping in mind as a lightweight alternative.
A background-image gradient constrained to 2px tall, pinned to the bottom edge. Works with multi-line text, animates smoothly on hover, and degrades gracefully.
/* Method 1: border-image - no border-radius support */
.border-gradient {
border: 2px solid transparent;
border-image: linear-gradient(135deg, #6366f1, #ec4899) 1;
}
/* Method 2: ::before pseudo - supports border-radius */
.border-gradient-rounded {
position: relative;
background: white;
border-radius: 0.75rem;
}
.border-gradient-rounded::before {
content: '';
position: absolute;
inset: -2px; /* border thickness */
border-radius: inherit;
background: linear-gradient(135deg, #6366f1, #ec4899);
z-index: -1;
}
/* Method 3: background-clip - supports border-radius */
.border-gradient-clip {
background:
linear-gradient(white, white) padding-box,
linear-gradient(135deg, #f59e0b, #ef4444, #a855f7) border-box;
border: 2px solid transparent;
border-radius: 0.75rem;
}
/* Method 4: Animated rotating border */
@property --angle {
syntax: '';
initial-value: 0deg;
inherits: false;
}
.animated-border {
background:
linear-gradient(white, white) padding-box,
linear-gradient(var(--angle), #6366f1, #ec4899, #f59e0b, #6366f1) border-box;
border: 2px solid transparent;
animation: rotate-border 3s linear infinite;
}
@keyframes rotate-border {
to { --angle: 360deg; }
}
/* Gradient underline */
.grad-underline {
background-image: linear-gradient(135deg, #6366f1, #ec4899);
background-size: 100% 2px;
background-position: 0 100%;
background-repeat: no-repeat;
padding-bottom: 0.25rem;
}