codr.tools
Tools

CSS gradient generator

Build linear, radial and conic CSS gradients visually: any angle, shape, size and centre, colour stops with their own position and opacity, repeating variants and an interpolation colour space, with the background declaration ready to copy.

Start from a preset

Gradient type and geometry

Type
Gradient type
Direction
How the gradient line is aimed
deg

0deg points up and the angle runs clockwise, so 90deg is the same as to right.

Left alone, hex and rgb() stops blend in gamma-encoded sRGB, which is what browsers have always done.

Colour stops

  • %
    %
  • %
    %
  • %
    %

Preview

CSS
background: linear-gradient(160deg, #f8b26a 0%, #b8437f 52%, #1c2b63 100%);

Build linear, radial and conic CSS gradients visually: any angle, shape, size and centre, colour stops with their own position and opacity, repeating variants and an interpolation colour space, with the background declaration ready to copy.

How to use this tool#

  1. Pick a preset or press Random to start from something, then change it. Every control updates the preview and the CSS as you move it.
  2. Choose the type. Linear runs along a line, radial spreads out from a point, conic sweeps around one. Repeating turns the stops into a pattern that tiles.
  3. Aim it. A linear gradient takes an angle or a to keyword. A radial gradient takes a shape, a size keyword and a centre. A conic gradient takes a start angle and a centre.
  4. Edit the stops. Each one has a colour picker, a hex field, a position along the gradient and its own opacity. Add up to twelve, reorder them with the arrows, and use Distribute to space them evenly.
  5. Copy the CSS. The output box holds a finishedbackground declaration. Paste it straight into a rule.

Nothing you pick is sent anywhere. The preview is the browser painting the same value you are about to copy, so what you see is what the CSS does.

What a CSS gradient is#

A gradient is an image the browser draws for you. It is not a colour and not an effect: it is a value of type <image>, which is why it goes inbackground-image (or the background shorthand) and works anywhere else an image does, such as border-image or mask-image.

Because it is generated rather than loaded, it costs no request, scales to any size without blurring and can be changed from a single custom property. CSS has three functions for it, each with a repeating twin:

  • linear-gradient(): colours change along a straight line at an angle you choose.
  • radial-gradient(): colours spread outwards from a point, in a circle or an ellipse.
  • conic-gradient(): colours sweep around a point like a clock hand, which is what makes pie charts and colour wheels.
css
/* Two colours, top to bottom. The direction is optional. */
background: linear-gradient(#2457c5, #ffcf00);

/* Same thing, aimed across instead of down. */
background: linear-gradient(to right, #2457c5, #ffcf00);
background: linear-gradient(90deg, #2457c5, #ffcf00);

The direction is optional. Leave it out of a linear gradient and it runs top to bottom; leave the shape and position out of a radial one and you get an ellipse centred in the box.

Angles and the gradient line#

A linear gradient is painted along a gradient line that passes through the centre of the box. 0deg points up and the angle turns clockwise, so90deg points right and 180deg points down. That is the opposite of the convention used in most maths, and the usual reason a gradient comes out mirrored.

The to keywords say the same thing in words. Four of them map onto an exact angle; the corner keywords do not:

Direction keywords and their angle equivalents
KeywordAngleWhat it does
to top0degColours run upwards.
to right90degThe usual left-to-right ramp.
to bottom180degThe default when nothing is given.
to left270degThe mirror of to right.
to top rightdepends on the boxTilted so the top left and bottom right corners both sit on the halfway colour.
to bottom rightdepends on the boxSame rule, aimed into the bottom right quadrant.

The corner keywords are the interesting ones. The specification does not give them a fixed angle: it says the gradient line must point into the same quadrant as the named corner and be perpendicular to the line joining the two neighbouring corners, which makes a stop at 50% pass exactly through both of them. On a square that works out at 45 degrees. On a wide box it does not, and to bottom right and 45deg are visibly different gradients. Switch the tool above to Keyword and watch the preview to see it.

The length of the gradient line follows from the angle and the box:abs(W × sin(A)) + abs(H × cos(A)), where W and H are the width and height of the box. That is why the same percentage stop lands in a different place when an element is resized, and why 100% is the far end of the line rather than the far edge of the box.

Radial gradients: shape, size and centre#

A radial gradient needs three things, and all three have defaults you can leave out. Theending shape is circle or ellipse; without one you get an ellipse, unless you give a single length as the size, which forces a circle. Thesize says where the last stop lands. The position, writtenat <x> <y>, is the same syntax as background-position and defaults to the centre.

The four radial gradient size keywords
Size keywordWhere the gradient ends
farthest-cornerThe default. The shape ends at the corner furthest from the centre, so the whole box is covered.
farthest-sideEnds at the furthest side. The corners lie past the last stop and take the last colour flat.
closest-cornerEnds at the nearest corner.
closest-sideEnds at the nearest side: the tightest of the four, and the one that makes a true circle inside a wide box.

Instead of a keyword you can give explicit lengths. One length is the radius of a circle, and a percentage is not allowed there, because it would be ambiguous about which axis it refers to. Two values are the horizontal and vertical radii of an ellipse, and percentages are fine in that form.

Conic gradients#

A conic gradient sweeps its colours around the centre. from <angle> rotates the whole sweep and defaults to 0deg, which points up;at <position> moves the centre. Stops are placed by angle or by percentage, where 100% is a full turn, so 90deg and 25% are the same place.

css
/* A position smaller than the one before it is pulled up to match,
   so 0 reads as "start where the last slice ended". */
.chart {
  width: 180px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(#2457c5 0 35%, #b3246f 0 70%, #ffcf00 0);
}

There is no wrap-around smoothing between the last stop and the start of the sweep. If the first and last colours differ you get a visible seam at the start angle, which is fine for a pie chart and wrong for a colour wheel. The fix is to repeat the first colour as the last stop, which is what the Colour wheel preset above does.

Colour stops, hints and hard stops#

A stop is a colour and, optionally, where it sits. The browser fills in the rest with a small set of rules worth knowing, because they are what makes several popular tricks work:

  • An unplaced first stop becomes 0%, an unplaced last stop becomes100%.
  • Unplaced stops in between are spread evenly across the gap they sit in.
  • A stop whose position is smaller than the one before it in the list is pulled forward to match, rather than being treated as an error. That is what makes 0 mean "start where the last one ended" in the pie chart above.
  • A stop may carry two positions. #2457c5 0 50% is exactly the same as writing that colour twice, at 0 and at 50%, and is the tidiest way to write a flat band.
css
/* Positions in percent or in any length unit. */
background: linear-gradient(90deg, #2457c5 0%, #b3246f 30%, #ffcf00 100%);

/* A stop with two positions is the same colour written twice,
   which is how you get a hard edge. */
background: linear-gradient(90deg, #2457c5 0 50%, #ffcf00 50% 100%);

/* A bare length between two stops is a hint: it moves the
   halfway colour without adding a stop of its own. */
background: linear-gradient(90deg, #2457c5, 25%, #ffcf00);

Hard stops come out of those rules for free: put two stops at the same position and the colour changes with no blend at all. That is how stripes, tapes, pie slices and fake borders are made, and it is the reason a gradient is often the cheapest way to draw a shape.

A bare length or percentage between two stops is a colour hint. It does not add a colour: it moves the halfway blend of its two neighbours to that point, and the browser bends the interpolation curve around it. A hint at the midpoint is the same as no hint at all. Pulled towards one end, it makes a fade that lingers longer on one colour, which is often what you want when fading an image out to nothing.

Repeating gradients#

repeating-linear-gradient(), repeating-radial-gradient() andrepeating-conic-gradient() take exactly the same arguments as their plain twins. The difference is that the stop list is tiled: the distance between the first and last stop becomes one period, repeated to fill the box.

css
/* 6px of ink, 6px of paper, forever, at 45 degrees. */
.tape {
  background: repeating-linear-gradient(45deg, #15191e 0 6px, #f3f4f1 6px 12px);
}

/* The same idea around a centre instead of along a line. */
.dial {
  background: repeating-conic-gradient(from 0deg, #15191e 0 5deg, #f3f4f1 5deg 10deg);
}

Two things go wrong with repeating gradients. If the last stop sits at 100% there is nothing left to repeat and you get one ordinary gradient. And if the last colour is not the same as the first, every period ends in a hard line where the ramp jumps back, which looks like a rendering bug rather than a pattern. Either match the ends, or make the jump deliberate, as the stripes above do.

Transparency, and the grey band#

Every stop can carry an alpha, and fading a gradient to nothing is one of its most useful jobs. There is one pitfall with a long history: transparent is not "the same colour, invisible". It is defined as transparent black, rgb(0 0 0 / 0).

The specification says gradients interpolate with premultiplied alpha, which makes the black in that value irrelevant and the fade clean. Engines did not always do it: Firefox fixed this in version 36, and WebKit only in Safari 15.4, released in March 2022, in a post that calls the old result "muddy". Until then a yellow that faded totransparent went grey through the middle in Safari.

css
/* Fades to grey in engines that interpolate naively,
   because "transparent" means transparent black. */
background: linear-gradient(#ffcf00, transparent);

/* Says the same thing in a way no engine can get wrong. */
background: linear-gradient(#ffcf00, rgb(255 207 0 / 0));

Current browsers get the first line right. Writing the second costs nothing, reads more clearly, and is still the safer habit on old embedded web views. The tool above does this for you: set a stop's opacity to 0 and it prints the stop's own colour with a zero alpha.

Interpolation colour spaces#

By default, a gradient between hex colours or rgb() values blends in gamma-encoded sRGB, the way CSS has always done it. That legacy rule is written into CSS Color 4 for compatibility; a gradient whose stops use a modern colour syntax such as oklch()blends in Oklab instead. Either way you can ask for a specific space by puttingin <space> next to the direction:

css
.hero {
  /* Any browser that does not understand the second line keeps this one. */
  background: linear-gradient(90deg, #2457c5, #ffcf00);
  background: linear-gradient(90deg in oklch, #2457c5, #ffcf00);
}

The space is either rectangular (srgb, srgb-linear, lab,oklab and the wide-gamut ones) or polar (hsl, hwb,lch, oklch). A polar space also takes a hue path:shorter hue is the default and goes the short way round the colour wheel,longer hue takes the other way round and produces a rainbow,increasing hue and decreasing hue force a direction.

The practical reason to reach for this is the muddy middle. Blending blue to yellow in sRGB passes through a dull grey, because sRGB is not perceptually even. In oklab oroklch the midpoint keeps its brightness and the ramp looks like the two colours meeting rather than fading out and back in.

Support arrived in Safari 16.2 in December 2022, Chrome 111 in March 2023 and Firefox 127 in June 2024. That is every current engine, but the fallback line is what covers the ones that have not been updated.

Banding, and what helps#

A large, low-contrast gradient often shows visible steps rather than a smooth ramp. The cause is not CSS: a screen stores eight bits per channel, so there are only 256 levels to go round, and a slow fade across 800 pixels has to hold the same value for several pixels at a time. Dark blues and greys show it worst.

Three things help, in the order worth trying them:

  • Make the ramp shorter or higher in contrast. Banding is a function of how little the colour changes per pixel.
  • Add intermediate stops to break one long, slow ramp into shorter and steeper ones, which moves the quantisation steps closer together.
  • Lay a faint noise texture over it. A few percent of grain breaks the flat bands into something the eye reads as continuous. The specification also permits browsers to dither gradients themselves, but it does not require it, so it is not something to count on.
css
/* An SVG noise tile over the gradient hides most 8-bit banding. */
.hero {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E"),
    linear-gradient(160deg, #1c2b63, #b8437f);
}

Layering several gradients#

background-image takes a comma-separated list, and the first layer is the one nearest the viewer. Each later one sits behind it, andbackground-color is painted below all of them. Since gradients can be partly transparent, stacking two or three is how the soft multi-colour backgrounds on landing pages are made, without a single image file.

css
/* The first layer is the one closest to the viewer.
   The colour always sits underneath the lot. */
.page {
  background:
    radial-gradient(circle closest-side at 15% 20%, rgb(36 87 197 / 0.55), transparent),
    radial-gradient(circle closest-side at 85% 30%, rgb(179 36 111 / 0.45), transparent),
    #15191e;
}

The same trick at a smaller scale gives a control its lift: one nearly invisible white ramp over a flat colour.

css
.button {
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.18), rgb(255 255 255 / 0) 60%),
    #2457c5;
}

Note what the shorthand does here. background resetsbackground-position, background-size andbackground-repeat to their initial values before applying what you wrote. If another rule set a background size you meant to keep, use background-image on its own.

Browser support#

Gradients themselves are as old as the browsers you support: the unprefixedlinear-gradient() and radial-gradient() have been in every engine since Chrome 26, Firefox 16 and Safari 7, and the -webkit-, -moz- and-o- forms are long dead. Do not ship them: they only add bytes, and several of them used a different angle convention.

  • conic-gradient(): Chrome 69 (2018), Safari 12.1 (2019), Firefox 83 (2020).
  • Double-position stops such as #2457c5 0 50%: Chrome 71, Firefox 64 and Safari 12.1, all within a few months of each other over the 2018 to 2019 winter.
  • Interpolation colour spaces (in oklch and friends): Safari 16.2, Chrome 111, Firefox 127.

Only the last of those is recent enough to plan a fallback for, and the two-declaration pattern above handles it.

Gotchas worth knowing#

  • A gradient is not a border. border-color does not take an image. To get a gradient edge, use border-image, or layer a gradient background under an inset one, or draw the border as a gradient with hard stops.
  • Gradients do not animate between each other. They are images, not colours, so a transition from one gradient to another is a swap, not a fade. Animate a custom property, move a background-position on an oversized gradient, or cross-fade two layers.
  • Percentages are relative to the gradient line, not to the element, and for a radial gradient they are relative to the ending shape. Resizing the box moves them.
  • Text on a gradient still needs contrast. Check the worst point of the ramp, not the average. The colour contrast checker takes the two colours and gives you the ratio.
  • A repeating period under a pixel or two aliases badly, and on a scaled or rotated element it moires. Keep band sizes to whole pixels where you can.

Nothing here leaves your browser#

The gradient is built, previewed and turned into CSS on your machine, by your browser, after the page has loaded. Nothing is uploaded and there is nowhere to upload it to: this site is static files with no backend. Disconnect from the network and the generator keeps working.

The preview is not a picture of a gradient. It is the browser painting the exact value in the output box, so if the preview is right, the CSS is right. If your browser does not understand something you chose, the preview goes empty and the tool says so rather than showing you a result you would not get.

Questions people ask#

How do I make a gradient go diagonally?

Give it an angle between the axes, such as linear-gradient(135deg, ...), or use a corner keyword like to bottom right. They are not the same on a non-square element: the keyword stays anchored to the corners whatever the box does, the angle does not.

Why does my gradient look grey in the middle?

Two common causes. If one end is transparent, an older engine blends towards transparent black; write rgb(R G B / 0) with the other end's colour instead. If both ends are saturated and far apart, such as blue to yellow, sRGB interpolation genuinely passes through a dull midpoint; add in oklab or put a stop in the middle to steer it.

How do I get a hard edge instead of a blend?

Put two stops at the same position.linear-gradient(90deg, #2457c5 50%, #ffcf00 50%) gives two flat halves, and the double-position form, #2457c5 0 50%, says the same thing with one stop.

Can I animate a CSS gradient?

Not directly between two gradients. What does work is animating the values that feed it: a custom property registered with @property so the browser knows how to interpolate it, thebackground-position of a gradient made larger than its box, or the opacity of a second gradient layered over the first.

Which is better, hex or rgb() in a gradient?

Neither renders differently. Hex is shorter for opaque colours and this tool prints it; a stop with an opacity has to be written as rgb(R G B / A), which is the CSS Color 4 form of rgba(). If you prefer the older comma form, both are valid and mean the same thing.

How many colour stops can a gradient have?

CSS sets no limit. This tool stops at twelve, which is past the point where more stops stop helping: a long list is usually a sign that the ramp wants a different interpolation space rather than more waypoints.

Do I still need vendor prefixes?

No. Every gradient function is supported unprefixed everywhere, and the prefixed versions used an older syntax where the angle was measured differently, so copying an old snippet can leave you with two gradients pointing in opposite directions.

Can I use a gradient as a border or on text?

Not through border-color or color, which take colours rather than images. The usual routes are border-image for an edge, and a gradient background clipped to the glyphs with background-clip: text for text, which also needs the text colour set to transparent. Keep the prefixed-webkit-background-clip: text line alongside it for older engines.

  • Build a CSS Grid layout visually: set the columns, rows, track sizes and gaps, drag items across cells to place them, and copy the generated CSS and the matching HTML.

  • Build a CSS box-shadow visually, with as many layers as you need: offsets, blur, spread, colour with opacity and inset, over a preview whose box colour, background and border radius you set yourself.

  • Check a foreground and background pair against the WCAG 2 contrast thresholds, composite transparency the way a browser does, find the nearest passing colour, and build a tint, shade and harmony palette with the contrast of every swatch.

  • Build a CSS border-radius visually: one radius per corner or the elliptical slash syntax for organic blob shapes, with presets, a live preview, the shortest correct shorthand and the corner longhands.