Gradient Generator
Linear, radial and conic gradients, with the CSS ready to copy.
Preview
Fills the panel at its real sizeThe preview is a real element at a real size, not a scaled-down thumbnail — a gradient that bands here will band in your hero section too.
Code
Three ways to ship itStops are written in position order whatever order you typed them in, so the output is always a valid declaration.
This generator stops at sRGB. Every value here is written in the plain form,
with no in oklch keyword and no
color-mix() in the output, because both need a browser
newer than the ones plenty of people still ship to. The moment you need a
mid-gradient blend computed in a perceptual space, this tool has nothing more to
offer — add the middle stop by hand and write the interpolation keyword yourself.
- Shape
- —
- Angle
- —
- Stops
- —
- Widest gap
- —
Shape
0° runs bottom-to-top, 90° left-to-right, 180° top-to-bottom. A diagonal between 120° and 160° reads as deliberate; 90° reads as a default nobody changed.
A radial gradient has no direction to set — its centre is fixed at 50% 50% and it is sized to the farthest corner.
Stops
Two stops is the minimum and eight is the ceiling — past that you are hand-tuning something that wants to be an image. Stops are written in position order whatever order you set them in, so the declaration is always valid. A stop at 50% that repeats the colour on either side of it is the standard fix for a gradient that bands.
Presets
Each preset loads its stops, angle and shape into the controls above, so you can take one apart rather than starting from it.
A transparent stop is black with zero alpha , not "no colour". Mixing it into
a gradient drags the midpoint toward black in browsers that do not premultiply, and
modern ones do, so the same declaration renders two different ways across your
support matrix. The dependable form names the colour twice:
rgb(255 107 53 / 0) rather than
transparent.
Text over a gradient sits over its worst stop
A contrast ratio describes two colours. A heading laid across a gradient is over a different colour at every point, so the measurement that matters is the one at the point where the two colours come closest — usually one end, sometimes a mid stop that was added to hold a hue. The middle of the ramp is the one place the number will always look acceptable, and it is the place people test.
Three fixes, in the order they are worth trying. Move the type: a heading that sits over the flattest third of the ramp is solving the problem by not having it. Put a scrim underneath — a solid or gently graded overlay between the gradient and the text, which costs a stop and buys a predictable band. Or narrow the ramp so its ends are closer together, which is the same idea as the scrim applied to the background instead of the foreground.
What does not work is relying on the gradient's direction. A ramp that is light at the top and dark at the bottom reads fine in the design tool at the size the design tool draws it, and falls apart the moment the text wraps onto an extra line or the container is narrower than expected and the paragraph pushes down into the pale end. Where the layout can reflow, the background has to clear the threshold at every point the text can reach.
A transparency stop is a colour with zero alpha, not an absence of colour. The keyword transparent is black with nothing showing, so a browser that blends the colour channels before it touches alpha is blending your stop with black and dragging the middle of the ramp toward it. Current browsers premultiply and arrive somewhere else entirely. Writing the colour twice — rgb(255 107 53 / 0) — pins the behaviour down and renders the same way everywhere.
Hard stops are drawn, not blended
Two stops at the same position leave nothing to interpolate, and the browser draws a crisp edge between them. That turns a gradient function into a banding tool, which is what a progress meter, a chart fill or a striped divider actually wants:
linear-gradient(90deg,
#1F6FEB 0% 38%,
#E8EAED 38% 100%)
both stops sit at 38%, so the change is instant.
no fade, no anti-aliased seam, no one-pixel blur.
The alternative — two stops a fraction of a percent apart — produces a slightly soft edge, which looks like a rendering accident rather than a decision. Where the bands are deliberate, share the position exactly; where the seam looks too hard at small sizes, the honest fix is a hairline divider element rather than a squeezed gradient.
A smooth blend also implies something the data may not say. A bar that fades from one colour to another reads as a value passing continuously from the first to the second, and if the underlying quantity is categorical — two states, not a range — the fade is a claim that is not true. Stepped bands say the same thing without the implication, which is why they show up on meters and not on hero sections.
What is underneath matters
A gradient is a background image, and a background image is optional. Declaring a solid background-color in the same rule as the gradient gives every browser something to paint if the gradient declaration is dropped, and it costs nothing where the gradient renders — the image sits on top of the colour. This is the difference between a section that loses its tint on an old browser and one that comes out with black text on a white page, which is a legible page rather than a broken one.
Two other places the background disappears. A browser set to high-contrast or forced-colours mode replaces backgrounds with its own palette, so a gradient behind text can be removed while the text stays — anything relying on the contrast between a light ramp and dark type needs to hold up when the ramp is gone. And printing drops background images by default, in every browser, because they are usually decoration; a gradient that was carrying meaning rather than decoration has to survive on border colours, text weight or an actual element instead.
The conic one is doing something different
A conic gradient sweeps its stop positions around a centre point rather than along a line, so every stop is an angle. It has a starting direction of its own and a position for the centre, and the two together decide where the first colour begins and where the sweep is anchored. Change the centre and the whole ramp moves: the same stops centred off to one side produce bands that curve around a point outside the box.
That makes it the right tool for anything organised by direction rather than by distance — a colour wheel, a compass, a gauge, a sweep that highlights a segment of a ring. The hard-stop technique gets much further here than it does in a linear ramp: a long list of same-position pairs turns the function into a wheel of wedges, which is how a pure-CSS pie chart exists at all. It is a poor substitute for a linear gradient with three stops, which is what people reach for it as when what they wanted was a diagonal.
Where the two ends of a ramp come from matters more than how the ramp is drawn. The Palette Generator produces a family whose ends already belong together, and the Contrast Checker settles whether the type laid over the result can be read.
Reference
The interpolation space, and what it does to your ramp
| Space | What it interpolates through | Good for | Where it goes wrong |
|---|---|---|---|
| sRGB | Each gamma-encoded channel on its own, straight from one value to the other. The default when nothing else is asked for. | Short ramps between colours that already sit close, and anything that has to render identically everywhere. | Complementary or widely spaced hues meet in the middle at grey or brown, and a long ramp is duller at its centre than at either end. |
| srgb-linear | The same three channels with the transfer function undone first, so the numbers are proportional to light, and alpha premultiplied before the blend. | Ramps that cross a lot of brightness, and fades from a colour to a transparent stop. | Midpoints come out lighter than the sRGB blend, and the result leans on the browser premultiplying alpha, which older ones did not. |
| hsl | Hue, saturation and lightness as separate numbers, so the hue angle rotates from one value to the other. | Two colours that already sit near each other on the wheel, or a ramp you want to travel through the spectrum. | The rotation takes the long way round unless the shorter hue path is asked for, and a ramp between opposite hues can pass through an unrelated colour on the way. |
| lab / lch | CIE lightness and two opponent axes, against a D50 white point. | Ramps where both ends should read as equally light, which an sRGB blend gets wrong. | Hue is spaced unevenly around the wheel, so blue ramps drift toward purple — the fault oklab was designed to fix. |
| oklab / oklch | A perceptual lightness axis and two opponent axes, tuned so equal numeric steps are equal visual steps. | Long ramps, dark ramps, and any pair whose sRGB midpoint is muddy. | Recent syntax. A browser that does not understand the keyword drops the declaration instead of blending in sRGB. |
| hard stop / stepped | Nothing at all. Two stops share a position and the colour changes between them. | Flags, charts, progress meters, and anywhere a smooth blend would imply a value that is not there. | Each band has to be written as its own pair of stops, so a bar with a lot of bands is a long declaration. |
The space decides what the middle of a ramp looks like, which the two colours at its ends do not. sRGB is the default and the least flattering of these for anything that travels far across the wheel.
Blend a saturated red with a saturated green in the space every browser defaults to and the middle comes out olive-brown, not yellow. The browser is averaging three gamma-encoded numbers, and half a large red plus half a large green is a small amount of both. A midpoint is a question about light, and gamma-encoded numbers are not proportional to light.
The hue wheel makes the next difference. Red to green is a short turn one way and a long turn the other, so two ramps built from the same pair can pass through different colours depending on which way the space travels. A blue to a yellow arrives at a colour neither end predicts.
Reach for the perceptual spaces when the ramp is long, or ends dark. Equal numeric steps in oklab look like equal visual steps, so a long ramp stops feeling weighted toward one end and the muddy middle goes away.
Support is the other half of the trade. A browser that does not know the in oklab keyword does not blend in sRGB instead — it drops the declaration, so what renders is the plain gradient written above it, if there is one. Check a design that leans on the perceptual midpoint in the browsers your visitors run, rather than assuming it from a support table.
Questions
Gradients, answered plainly
Can I interpolate in oklab or oklch instead?
Yes, in CSS — linear-gradient(in oklch, #FF0000, #00FFFF) is valid, and so is color-mix(in oklab, …) inside a stop. This generator does not emit either, deliberately: support is recent, older Safari falls back to a hard stop rather than to sRGB, and a fallback that fails loudly is worse than a blend that is slightly muddy. Write it by hand, test it in the browsers you actually support, and keep the plain declaration as the fallback line above it.
Why did a transparent stop turn the gradient dark?
Because transparent is rgba(0, 0, 0, 0). A browser that blends the red, green and blue channels before it touches alpha is blending your colour with black; one that premultiplies is blending with nothing at all. Every current browser premultiplies, but the same declaration used to render differently and the source gives no clue which behaviour you are relying on. Writing rgb(255 107 53 / 0) pins it down.
What does 0deg point at?
Straight up. Angles run clockwise from north, so 90deg points right, 180deg points down and 270deg points left — which is the same as the to top, to right and to bottom keywords. The angle form is worth preferring: it survives a change to the box's proportions, where a keyword does not.
How many stops can a gradient take?
Browsers will accept dozens. This tool caps the list at eight, because past that you are no longer designing a gradient, you are hand-placing colours that will drift the moment someone changes a palette token. If you need more than eight, the honest answer is usually an image, or a mid-stop pair placed close together to hold a colour band steady.
Can I get an SVG for a conic gradient?
No, and neither can anyone else. SVG 1.1 has exactly two gradient elements, both of them linear or radial, and SVG 2 adds no conic form. The usual workaround is a very large number of small stops, which produces a bigger file than the raster image you were trying to avoid. Ship the CSS instead; every browser that renders a conic gradient also renders the declaration.
Why is the middle of my gradient grey?
Because the blend is numeric and happens in sRGB. Take #FF0000 and #00FF00 and the halfway point is #808000 — half the red channel and half the green, which is olive, not yellow. You have a choice: put a third stop at 50% holding the colour you actually want there, which works in every browser and is what this generator can write for you, or declare the gradient in oklab and let the blend find the hue itself, accepting that a browser without the keyword drops the line.
Why does my gradient look banded?
A wide, low-contrast ramp runs out of colours to draw with. Each sRGB channel holds 256 values, so stretched across a big element the browser steps from one to the next every few pixels and you see the edge of each step — worst on dark ramps, where the eye is most sensitive to small differences. Push the two ends further apart so the ramp spans more levels, keep the element smaller, or lay a faint noise texture over it, since a few percent of random grain breaks the steps up. This tool does not add noise; that part belongs in an image or an SVG filter.
Can I animate a gradient?
Not the gradient itself. background-image is not an animatable property, so there is no halfway value between two linear-gradient() functions — a transition on it either does nothing or jumps at the end. Animate something on top instead: fade a second element carrying the other gradient with opacity, or move a transform across a gradient bigger than the box. Both run on the compositor, which a repainted gradient does not.