How to Create CSS Gradients from Scratch (A Visual Guide)
Learn how CSS gradients work — linear, radial, and conic — and use visual tools to create beautiful gradients without memorizing the syntax.
Try it yourself — free & instant
Every tool mentioned in this article is available on Xevon Tools. No sign-up, no uploads, no watermarks.
Browse all free toolsWhat a CSS gradient really is
A CSS gradient is not an image file — it is an instruction the browser renders on the fly: "blend from this color to that color, in this direction." Because it is generated, it is resolution-independent (crisp on any screen), weighs zero bytes as an asset, and can animate and adapt in ways a baked PNG never could.
Three gradient types cover almost everything you will ever build: linear, radial, and conic. Our gradient generator lets you build all three visually and copy the exact CSS.
Linear gradients: the workhorse
background: linear-gradient(135deg, #FF7A1A, #101828);
The first argument is the direction. 135deg runs top-left to bottom-right; to right and to bottom are readable keyword alternatives. Then come the color stops, in order.
Controlling where colors sit. Each stop can take a position:
background: linear-gradient(90deg, #FF7A1A 0%, #FF7A1A 40%, #101828 100%);
Holding the first color until 40% creates a solid band before the blend begins. Two stops at the same position create a hard edge — the trick behind CSS-only stripes and color-split layouts:
/* sharp diagonal split, no image needed */
background: linear-gradient(120deg, #FF7A1A 50%, #101828 50%);
Radial and conic gradients
Radial gradients bloom outward from a point — the classic soft spotlight behind hero text:
background: radial-gradient(circle at 30% 20%, rgba(255,122,26,0.35), transparent 60%);
Conic gradients sweep around a center point like a clock hand. They make pie-chart shapes and color wheels possible in pure CSS:
background: conic-gradient(#FF7A1A 0 25%, #101828 25% 100%);
Why some gradients look muddy (and how to fix it)
Blend two saturated, distant hues — say pure blue to pure orange — and the midpoint passes through desaturated gray. That gray dead zone is the number-one reason homemade gradients look dirty.
Three fixes:
- Blend neighbors, not opposites. Orange to pink, blue to violet, teal to green — hues near each other on the color wheel blend cleanly.
- Add a middle stop that routes the blend around gray: orange → coral → magenta reads far richer than orange → magenta directly.
- Blend lightness, not just hue. A gradient from a light tint to a dark shade of the same hue (see our color shades generator) always looks intentional.
Layering: where gradients get powerful
background accepts multiple comma-separated layers, top first:
background:
radial-gradient(circle at 80% 0%, rgba(255,176,122,0.4), transparent 50%),
linear-gradient(180deg, #FAF6EE, #F2EBDE);
A subtle radial glow over a soft vertical wash — this two-layer pattern is the backbone of countless modern hero sections, and it costs no image request.
Two practical cautions: gradients layered over text need a contrast check (run the combination through our contrast checker), and text over a mid-gradient area can pass at one end and fail at the other — test the worst point, not the average.
Text gradients
h1 {
background: linear-gradient(90deg, #FF7A1A, #D95F00);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
The gradient is painted as the element's background, then clipped to the glyph shapes. Keep a solid color fallback in mind for very old browsers.
FAQ
Do gradients hurt performance? No — they render faster than downloading an equivalent image and re-render crisply at any size. Extremely large blurred layers can cost paint time, but ordinary use is effectively free.
Can I animate a gradient?
You cannot transition background-image smoothly, but you can animate background-position on an oversized gradient, or crossfade two layered pseudo-elements — both standard techniques.
How do I get the exact CSS without hand-typing stops? Build it visually in the CSS gradient generator and copy the output — it produces the full, valid declaration.
