Color Palette and Gradient Generator Output Quality and the Modern CSS Replacement
What CSS gradient generators emit: legacy WebKit syntax and hsl() stops, with modern oklch interpolation replacements and paint-cost warnings for animated gradients.
You pasted a gradient from a generator. It gave you background: -webkit-linear-gradient(left, rgba(255,0,0,1) 0%, rgba(255,255,0,1) 100%). You know something is off but not what. The output is a legacy artifact: vendor-prefixed WebKit syntax, comma-separated rgba() stops, and no interpolation method at all. The browser defaults to sRGB. Your colors muddy in the middle. The fix is a hand-written linear-gradient(in oklch, ...) with space-separated modern color syntax, plus a @supports safety net that delivers a flat background. This article gives you the three code samples, tells you what each costs in paint, and names the traps a generator never mentions.
What A Generator Emits
Here is what a typical generator emits. It is complete. It runs in every engine that ever shipped a -webkit- prefix, which is why it still appears. But it carries three problems. The -webkit-linear-gradient prefix is dead weight on any engine that supports the unprefixed property. rgba(255,0,0,1) is the legacy comma-separated syntax that current CSS discourages. And there is no in <color-space> keyword, so the gradient interpolates in sRGB, the default. sRGB interpolation makes a red-to-yellow gradient pass through a grayish orange, because the midway point in sRGB is not perceptually halfway. The generator output looks fine on a saturated screen and wrong on a wide-gamut display.
/* Generator output: legacy syntax, no interpolation space */
.gradient-box {
background: -webkit-linear-gradient(left, rgba(255,0,0,1) 0%, rgba(255,255,0,1) 100%);
background: linear-gradient(to right, rgba(255, 0, 0, 1) 0%, rgba(255, 255, 0, 1) 100%);
}
The Modern Replacement
The modern replacement drops every vendor prefix, uses space-separated rgb() with a slash for alpha, and declares the interpolation color space with the in oklch keyword. oklch() is perceptually uniform: the same numerical change looks like the same visual change. A red-to-yellow gradient passes through a color the eye actually reads as midway, not through a grayish blend. The in keyword is the interpolation method declaration. Without it, you get sRGB by default. That is the single biggest upgrade you can make to any gradient. This version runs in every Baseline Widely Available browser since 2023-09 for the interpolation keyword; oklch() itself is Baseline Widely Available since 2023-05.
/* Modern replacement: oklch interpolation, space-separated syntax */
.gradient-box {
background: linear-gradient(in oklch, rgb(255 0 0), rgb(255 255 0));
}
The Fallback You Need
You need a safety net for engines that do not support in oklch or oklch() at all. The @supports guard tests the exact property:value pair, not a vague feature. The pattern: declare a solid background first. Then, inside @supports (background: linear-gradient(in oklch, red, blue)), declare the gradient. The solid color is not a gradient. It is a deliberate hard stop that prevents a blank or broken background. Do not use @supports (color: oklch(0 0 0)) to test gradients. The two features shipped on different schedules, and an engine can support one and not the other. The gap is small but real. Check caniuse for the current numbers on device-locked iOS Safari and old Android WebView. Ignoring the gap means an invisible gradient.
/* Fallback: solid color when gradient interpolation is unsupported */
.gradient-box {
background: #ffcc00;
}
@supports (background: linear-gradient(in oklch, red, blue)) {
.gradient-box {
background: linear-gradient(in oklch, rgb(255 0 0), rgb(255 255 0));
}
}
Gradient Generator Review: What a Good Tool Should Emit
A gradient generator review is a checklist, not an opinion. A good tool gives you space-separated modern syntax. Never comma-separated legacy forms. It offers in oklch as the default interpolation method, with in srgb as an optional legacy mode. It lets you pick hsl() or oklch() for each color stop. No forced hex. It never emits a vendor prefix unless you explicitly target Safari 5. If the tool emits -webkit-linear-gradient, delete it and use the unprefixed property. The best generators also show the @supports fallback block automatically. A tool that cannot do that is a color picker with a save button, not a CSS generator.
Modern CSS Gradient Syntax: What Changed and Why
Modern CSS gradient syntax is not a stylistic preference. It is a functional upgrade. The linear-gradient() function now accepts an optional in <color-space> clause before the first color stop, and that clause changes how the middle colors get computed. The color spaces you can choose are srgb, hsl, lch, oklch, oklab, and srgb-linear. oklch is the one you want for most work because it is perceptually uniform. The old syntax, comma-separated colors with no space declaration, forced sRGB. sRGB is a narrow gamut and perceptually uneven. The new syntax also allows color stops written as modern rgb(255 0 0 / 0.5) with space separation and a slash for alpha. This is the CSS Images Module Level 4 specification, and it is Baseline Widely Available since 2023-09. The color-mix() function, which lets you mix two colors in a specified space, uses the same in keyword. Learning one teaches you the other.
Oklch Gradient Interpolation: Why It Looks Better
The Midpoint Problem
Oklch gradient interpolation is the difference between a gradient that passes through a muddy gray and one that passes through a vivid midpoint. sRGB interpolation computes the midpoint in a gamma-encoded space. A red-to-blue gradient goes through a desaturated purple that looks like a bruise. oklch() computes the midpoint in a perceptually uniform space. The same gradient passes through a true violet. The math is defined in CSS Color Module Level 4. The practical effect: you can use oklch() for systematic color work, palettes, scales, and gradients, and trust that the in-between values are what the eye expects.
Oklch Versus Oklab
The same is true for oklab(), the rectangular coordinate version. oklch() is the cylindrical version. Choose oklch() when you want to control lightness and chroma independently, which is most of the time.
Gradient Performance Paint Cost: What a Declaration Actually Costs
Static Gradients Are Free
Gradient performance paint cost is not a myth, but it is often overstated. A static gradient, one that never changes, is painted once and cached as a bitmap. It costs nothing per frame.
Animated Gradients Are Expensive
An animated gradient, one that changes a color stop, a position, or the angle on every frame, triggers a repaint on the main thread. That is the paint cost, and it is high. The CSS compositor can promote properties that change layout or paint on the compositor thread. background is not one of them. transform and opacity are compositor-eligible. background is not. Animate a gradient by changing its background-position, and you force a repaint of the entire element every frame, on the main thread. The animation will jank on low-end devices. The fix: animate a transform on an overlay element that has a static gradient, or use opacity to fade between two static gradients. Never animate the gradient itself. The rule: keep gradients static, and animate transform or opacity.
Gradient Color Stop and Hard Stop Syntax: The Traps
Hard Stops
A gradient color stop is a color followed by an optional position, like red 0% or blue 100%. The trap is the hard stop. A hard stop is two identical positions on adjacent stops, like red 50%, blue 50%. It creates a sharp line with no transition. Generators rarely emit these because they assume you want a smooth blend. Hard stops are essential for banded patterns, progress bars, and stripes. The syntax: linear-gradient(in oklch, red 0%, red 50%, blue 50%, blue 100%).
Interpolation Hints
Another trap is the interpolation hint, a percentage between two stops that controls the midpoint of the transition. A hint of 25% means the color change happens faster at the start and slower at the end. Generators ignore hints entirely. Add them by hand. The hint syntax is red, 25%, blue. It changes the visual weight of the gradient without adding a stop.
Conic Gradient Starting Angle
For a conic-gradient, the default starting angle is 0deg from top, clockwise. Set it explicitly with from 45deg.
Radial and Conic Gradients: When to Use Them and How to Shape Them
Radial Gradients
Radial and conic gradients are the other two functions in the family, each with a specific job. radial-gradient() shapes a circle or ellipse from a center point. Its size keywords are closest-side, farthest-side, closest-corner, and farthest-corner. The default is farthest-corner, usually wrong for a spotlight effect. closest-side is the one you want.
Conic Gradients
conic-gradient() sweeps a color transition around a point. It is the replacement for pie charts built from multiple linear-gradient() segments or SVG. The old technique of stacking linear-gradient() at different angles to fake a color wheel is brittle and unreadable. conic-gradient() does it in one line. Both gradients accept the in oklch interpolation keyword, and both are Baseline Widely Available. A common mistake: using radial-gradient() for something linear-gradient() does better, like a stripe pattern. A repeating-linear-gradient is the right tool for stripes. The repeating- prefix exists for all three functions.
Legacy Color Syntax vs Modern Color Functions
Legacy color syntax is the comma-separated form you see in old code: rgba(255, 0, 0, 0.5) and hsla(120, 50%, 50%, 0.5). Modern color syntax is space-separated with a slash for alpha: rgb(255 0 0 / 0.5) and hsl(120 50% 50% / 0.5). Both are valid today. The legacy form is deprecated in spirit. The modern form is required for oklch(), oklab(), and color(). The color() function lets you specify any color space, including display-p3, which is wider than sRGB. A generator that still emits rgba() with commas learned CSS in 2012. Write rgb(255 0 0 / 0.5) and move on. The hwb() function is also modern and useful for defining colors by hue, whiteness, and blackness, though less common than oklch(). The rule: if you write a color by hand, use modern syntax. If a tool gives you legacy syntax, replace it.
Browser Support and Baseline Status: What You Can Trust
Browser support is not a single number. It is a rolling window called Baseline status. A feature is newly available when it ships in the current version of all major engines, and widely available when that same support has existed for 30 months. oklch() is Baseline Widely Available since 2023-05. Use it without a fallback in any engine released after early 2023. The gradient interpolation keyword in oklch is Baseline Widely Available since 2023-09. The real-world gap is not the fraction of users on obscure browsers. It is the users on device-locked iOS Safari or Android WebView that cannot update. For those, the @supports safety net is the answer. Do not trust a caniuse percentage that claims 100% support. The percentage is rounded and the gap is never zero. The @supports test is the only reliable way to know what a browser can do. Pair a modern declaration with a solid fallback.
FAQ: Four Answers You Need
Does a gradient generator output ever include @supports?
Almost never. Generators assume a modern engine and emit only the gradient line. Write the @supports safety net yourself. A solid background color is always safe, and the @supports guard ensures the gradient only appears when the engine supports it.
Can I animate a gradient without jank?
Yes, but not by animating the gradient. Animate a transform on an overlay element with a static gradient, or fade between two static gradients using opacity. Both are compositor-eligible. Animating background-position forces a main-thread repaint every frame.
Is hsl() still worth using?
For quick one-off colors, yes. For systematic color work, scales, palettes, and gradients, use oklch(). hsl() is not perceptually uniform. A hue shift by 30 degrees is not the same visual change at every lightness. oklch() is.
What is a hard stop and when do I need it?
A hard stop is two identical positions on adjacent stops, like red 50%, blue 50%. It creates a sharp line. Use it for stripes, progress bars, and banded patterns where you want no transition. Generators never emit these. Write them by hand.
What a Generator Will Never Tell You
The honest caveat: a CSS gradient generator output is a starting point, not a deliverable. No tool can know your performance budget, your browser support target, or your design intent. The generator gives you a color transition. You give it the in oklch keyword, the @supports safety net, and the discipline to never animate the background. The one sentence on this page that no competitor will write is: “Any generator that emits -webkit-linear-gradient in 2026 is a tool that will teach you bad habits, and you should delete its output before you paste it.” That is the line that separates a working front-end developer from someone who copies and pastes. Use the modern syntax, test the fallback, and keep your gradients static. That is the whole page.