CSS Gradient Generator
Build a linear, radial or conic gradient and see the colours in between — interpolated in sRGB, linear light or OKLab — then copy the CSS. Runs entirely in your browser.
About this tool
A gradient is two or more colours and a shape. The endpoints are yours to choose; what happens between them is decided by the browser, using a rule you never see unless a tool shows it to you. That rule is the colour space, and it is the whole reason this page exists: the same two stops produce visibly different midpoints depending on where the arithmetic happens.
sRGB is the default. It interpolates the numbers you would read off a hex code, which is why black to white lands on #808080 — a grey that looks darker than you might expect, because the encoding is not linear in light. Linear light interpolates the physically correct way: black to white at the halfway point is #bcbcbc, a much brighter grey, because half the photons is a lot more than half the code value. OKLab interpolates in a space built to be perceptually even, giving #636363 for the same pair — the midpoint that a human eye would call halfway.
Those three numbers are the same pair of colours. Which one you want depends on the job: linear light for glows and lighting, OKLab for anything where a muddy middle would look wrong, sRGB when you need the gradient to match a legacy design exactly. The tool reports both the CSS and the actual sampled colours every ten percent, so the choice is visible rather than guessed.
Two smaller decisions are worth knowing about. Every stop is written out with an explicit percentage, even the ones you left blank, so the browser has nothing to fill in on its own — the CSS you copy renders exactly what the samples show. And when a stop is transparent, the interpolation is premultiplied, which is why red fading to transparent passes through a bright half-red rather than a dark maroon: the colour is not dragged toward black just because its alpha is falling.
What happens when gradient stop positions run backwards
Positions are forced into non-decreasing order. If a stop sits before the one in front of it, it is pulled forward to that position, so the two share a point and the gradient shows a hard colour edge instead of raising an error.
CSS itself requires stop positions to be monotonic, so a list that reads 0%, 80%, 40% is not a gradient the browser can render the way the numbers suggest. Rather than rebuilding your list, the tool lifts each position to the largest value before it, which keeps the output valid CSS and keeps the two descriptions of the gradient — the declaration you copy and the colours the samples show — in agreement.
The effect is worth using on purpose. Two stops at the same position collapse the stretch between them to a point, which produces a crisp band edge rather than a fade. That is exactly how hard stops are written by hand: one colour at 50%, the next also at 50%.
Only the blanks are filled, and they are spread evenly between the typed positions on either side. Typed positions are never reordered to make the sequence look sensible; the tool heals the ordering, it does not reinterpret what you meant.
Stop positions outside 0% and 100% stay as you typed them
Explicit positions are written out verbatim, including negative values and values above 100%. The only geometric value that gets clamped is the centre of a radial or conic gradient, and the sample row reads only from 0% to 100%.
A stop at −20% or 140% is legal CSS. It means the first stretch of the line is already past that colour, or that the last colour is not reached until beyond the visible box, and browsers draw it without complaint. Because the tool writes every computed position into the declaration, an out-of-range value survives the trip exactly as entered.
The samples are a different matter. They read the gradient at 0%, 10%, 20% and so on up to 100%, and beyond the outermost stops the nearest endpoint colour is used — the same rule a browser applies when asked for a colour past the end of the line. The sample row therefore shows the visible stretch, not an extrapolated one.
The centre of a radial or conic gradient is the one value that is clamped, because a circle centred at −50% has its centre off the box entirely. Clamping keeps the preview and the samples describing the same picture.
Colour keywords, hsl() and short hex all come out as hex
A stop line accepts CSS colour keywords, rgb(), rgba(), hsl(), hsla() and 3, 4, 6 or 8 digit hex. All of them are parsed into one internal form, so the CSS you copy is always hexadecimal, with an alpha byte only when the colour is not opaque.
Red, tomato, rebeccapurple and the rest of the CSS colour keyword table are recognised, so a stop can be written the way you would say it out loud. An hsl() colour is converted through the standard formula before anything else happens, which means the gradient arithmetic never sees a hue angle.
The output is normalised rather than passed through. A colour with any transparency is written as eight hex digits and an opaque one as six, so the same stop is always spelled the same way. #F00 and #ff0000 describe one colour and both end up as #ff0000.
A line that cannot be parsed is reported with its line number instead of being skipped, because one typo among seven similar-looking colours is very hard to spot by eye.
Interpolating between translucent stops follows premultiplied alpha
When the two ends differ in opacity, colours cannot simply be averaged. CSS multiplies colour by alpha first, interpolates, then divides back out. Without that step the transparent end leaks its colour into the middle, and the usual symptom is a gradient that looks grey or dirty.
The failure is specific: going from red to fully transparent black, an unpremultiplied interpolation drags the middle towards black as if a grey film had been laid over it. Both ends look clean in the design file, so the suspicion lands on the browser or the tool.
The page therefore interpolates inside a stated colour space rather than adding hex strings together — string arithmetic must go wrong when alpha differs, and it goes wrong unpredictably. sRGB suits interfaces people are used to, linear light is closer to how light adds physically, and OKLab makes changes in lightness perceptually even.
Every stop states its percentage explicitly. Omit positions and the browser distributes them by its own rules, which have not always agreed across engines; stating them removes the ambiguity and keeps the result identical when pasted into a design tool.
Frequently asked questions
What is the difference between sRGB, linear light and OKLab?
They are three places to do the maths. sRGB interpolates the encoded values you see in a hex code, which is fast and is what browsers have always done. Linear light converts to physical light first, so equal steps in the numbers are equal steps in brightness — it is what you want for anything that should look like light. OKLab interpolates in a space designed so that equal steps look equal to the eye, which avoids the dull grey band that sRGB produces between saturated colours. Same endpoints, three different gradients.
Why is black to white #808080 in sRGB but #bcbcbc in linear light?
Because a hex value is not a measure of light. The sRGB transfer curve compresses the dark end to make better use of eight bits, so the code value 128 sits well below half the physical brightness. Interpolating in linear light and converting back gives the code value that really is half the photons, which is about 188 — #bcbcbc. Neither is wrong; they answer different questions, and the tool lets you pick which one you meant.
Why does every stop get a percentage when I did not type one?
Because CSS has its own rules for filling in missing positions, and if we left them out the browser would apply its rules while our sample row applied ours — the two could disagree, and the preview would stop matching the numbers. Writing every position explicitly removes the ambiguity. Your typed positions are always kept; only the blanks are filled, spread evenly between the stops on either side of them.
Why does red fading to transparent go bright pink instead of dark red?
Premultiplied alpha. Without it, the transparent endpoint is treated as black with zero alpha, and the midpoint is pulled toward that black, giving a muddy dark red — a well-known artefact of naive alpha blending. Premultiplying multiplies the colour by its alpha before interpolating and divides it back out afterwards, so the colour stays red while only the opacity falls. Browsers do the same thing, which is why the preview and the samples agree.
Can I paste the CSS straight into my stylesheet?
Yes — the CSS block is the complete declaration, including the interpolation space, e.g. a linear gradient in OKLab. It needs no preprocessing and no build step. If you are targeting older browsers, note that the interpolation keywords are recent; the plain sRGB option is the one that has always worked.
Related tools
Convert px to rem and back at any root font size — one value or a whole CSS block at once. Only the source unit is rewritten, and a reference table covers common sizes.
Fit a clip into a target aspect ratio and see exactly what gets cropped or letterboxed — for both cover and contain — with the crop rectangle and the loss in pixels. Runs entirely in your browser.
Generate names, emails, usernames, UUIDs, IP and MAC addresses, Luhn-valid card numbers and more — seeded so the same seed always yields the same rows, entirely in your browser.