Market
Pricing
Sign inStart
Field GuideCSS and web
CSS and web

HTML canvas gradient: createLinearGradient, radial and conic

Canvas gradients take coordinates where CSS takes angles, and that one difference causes most of the confusion. Here is every gradient method with code that runs, and a helper that turns a CSS angle into canvas points.

GradientlyVerified Gradiently account·October 1, 2026·5 min read
Cover: Citron Valley · GR·XXAV·HJ

The short version

  • An HTML canvas gradient is a CanvasGradient object made with createLinearGradient, createRadialGradient or createConicGradient, given colour stops with addColorStop, and assigned to fillStyle or strokeStyle.
  • Canvas gradients use coordinates in canvas space, not angles or percentages, so a linear gradient needs a start point and an end point.
  • Colour stop offsets run from 0 to 1, and any CSS colour string is accepted, including hex, rgb(), hsl() and oklch() in current browsers.
  • createConicGradient starts its sweep from a line pointing right and measures the angle in radians, unlike CSS conic-gradient, which starts at the top in degrees.
  • On high density screens, size the canvas buffer by devicePixelRatio, or gradients and text look soft.
On this page
The three gradient methodscreateLinearGradient and CSS anglescreateRadialGradientcreateConicGradientGradient text, strokes and animationSaving the canvas as an imageCommon canvas gradient problems

An HTML canvas gradient takes three steps: create a gradient object with ctx.createLinearGradient(), createRadialGradient() or createConicGradient(), add colours with addColorStop(offset, colour), then assign it to ctx.fillStyle and draw. Unlike CSS, a canvas gradient is defined by points in pixels, so you tell it exactly where the colour starts and ends. Everything you paint with that fill picks up the part of the gradient underneath it.

js
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')

const g = ctx.createLinearGradient(0, 0, canvas.width, canvas.height)
g.addColorStop(0, '#1e1b4b')
g.addColorStop(0.55, '#7c3aed')
g.addColorStop(1, '#f472b6')

ctx.fillStyle = g
ctx.fillRect(0, 0, canvas.width, canvas.height)
The smallest working canvas gradient: a diagonal from the top left corner to the bottom right.

The three gradient methods

createLinearGradient

Arguments

x0, y0, x1, y1

CSS equivalent

linear-gradient()
createRadialGradient

Arguments

x0, y0, r0, x1, y1, r1

CSS equivalent

radial-gradient()
createConicGradient

Arguments

startAngle, x, y

CSS equivalent

conic-gradient()
addColorStop

Arguments

offset 0 to 1, colour

CSS equivalent

A colour stop with a percentage
MethodArgumentsCSS equivalent
createLinearGradientx0, y0, x1, y1linear-gradient()
createRadialGradientx0, y0, r0, x1, y1, r1radial-gradient()
createConicGradientstartAngle, x, yconic-gradient()
addColorStopoffset 0 to 1, colourA colour stop with a percentage
Every method returns a CanvasGradient. You can keep it in a variable and reuse it for as many shapes as you like.

The gradient is fixed to the canvas, not to the shape. If you create a gradient from 0 to 400 and then fill a small square at x 300, the square shows only the pink end. That surprises people coming from CSS, where a gradient always stretches to the element. Create the gradient with the shape's own coordinates when you want it to fit.

createLinearGradient and CSS angles

CSS lets you write 135deg. Canvas wants two points. This helper converts a CSS angle into the same start and end points CSS uses, so a design written as a CSS linear gradient renders identically on canvas.

js
// Match CSS linear-gradient(angle) on a w by h rectangle
function cssAngleGradient(ctx, angleDeg, x, y, w, h) {
  const a = (angleDeg * Math.PI) / 180
  const len = Math.abs(w * Math.sin(a)) + Math.abs(h * Math.cos(a))
  const cx = x + w / 2
  const cy = y + h / 2
  const dx = (Math.sin(a) * len) / 2
  const dy = (-Math.cos(a) * len) / 2
  return ctx.createLinearGradient(cx - dx, cy - dy, cx + dx, cy + dy)
}

const g = cssAngleGradient(ctx, 135, 0, 0, 1200, 630)
g.addColorStop(0, '#0f172a')
g.addColorStop(1, '#0d9488')
ctx.fillStyle = g
ctx.fillRect(0, 0, 1200, 630)
In CSS, 0deg points up and angles turn clockwise. The length formula makes the corners land exactly on the first and last colours, as CSS does.
The same gradient in CSSlinear-gradient(135deg, #0f172a 0%, #0d9488 100%)
What the helper above draws on a 1200×630 canvas, the size of an Open Graph image. If your angles look off, gradient angle explains how CSS measures them.

createRadialGradient

A radial gradient on canvas is defined by two circles: a start circle and an end circle. Colour stop 0 sits on the first circle and stop 1 on the second. Most of the time you want the first circle to be a point, so its radius is 0.

js
const w = canvas.width
const h = canvas.height

// A soft light in the top right corner of a dark ground
ctx.fillStyle = '#0c0a1d'
ctx.fillRect(0, 0, w, h)

const glow = ctx.createRadialGradient(w * 0.75, h * 0.2, 0, w * 0.75, h * 0.2, w * 0.6)
glow.addColorStop(0, 'rgb(124 58 237 / 0.9)')
glow.addColorStop(0.5, 'rgb(46 16 101 / 0.5)')
glow.addColorStop(1, 'rgb(12 10 29 / 0)')

ctx.fillStyle = glow
ctx.fillRect(0, 0, w, h)
Fading the last stop to transparent lets you stack several lights on one ground, which is how layered backgrounds are built.

Move the centre of the first circle away from the second and the light tilts, like a spotlight hitting a wall at an angle. CSS has no direct equivalent of that offset. For the CSS side, see CSS radial gradients.

createConicGradient

createConicGradient(startAngle, x, y) sweeps colour around a centre point. Two details differ from CSS: the angle is in radians, and 0 points to the right (three o'clock), not to the top. To match a CSS conic-gradient(from 0deg, ...), start at -Math.PI / 2.

js
const cx = canvas.width / 2
const cy = canvas.height / 2

const ring = ctx.createConicGradient(-Math.PI / 2, cx, cy)
ring.addColorStop(0, '#22d3ee')
ring.addColorStop(0.33, '#7c3aed')
ring.addColorStop(0.66, '#f472b6')
ring.addColorStop(1, '#22d3ee')

ctx.fillStyle = ring
ctx.beginPath()
ctx.arc(cx, cy, 160, 0, Math.PI * 2)
ctx.fill()
Repeating the first colour at offset 1 hides the seam. createConicGradient works in current Chrome, Edge, Safari and Firefox.
The three examples from this article, shown as their CSS twins. CSS conic gradients covers the conic version in more depth.

Gradient text, strokes and animation

fillStyle and strokeStyle both accept a gradient, so text and outlines work the same way. Set the gradient across the text's own box, measured with measureText(), so the full range of colours appears inside the letters.

js
ctx.font = '700 96px Inter, system-ui, sans-serif'
const text = 'Open late'
const width = ctx.measureText(text).width

const tg = ctx.createLinearGradient(80, 0, 80 + width, 0)
tg.addColorStop(0, '#fde68a')
tg.addColorStop(1, '#fb7185')
ctx.fillStyle = tg
ctx.fillText(text, 80, 200)

// Animation: rebuild the gradient each frame, it is cheap
function frame(t) {
  const shift = (Math.sin(t / 2000) + 1) / 2
  const g = ctx.createLinearGradient(0, 0, canvas.width, 0)
  g.addColorStop(0, '#1e1b4b')
  g.addColorStop(0.2 + shift * 0.6, '#7c3aed')
  g.addColorStop(1, '#0f172a')
  ctx.fillStyle = g
  ctx.fillRect(0, 0, canvas.width, canvas.height)
  requestAnimationFrame(frame)
}
requestAnimationFrame(frame)
You cannot move or remove a stop once it is added, so animate by creating a new gradient each frame. Pause the loop for users who prefer reduced motion.

Saving the canvas as an image

A common reason to draw gradients on canvas is to generate an image: a share card, a certificate, a cover. Call canvas.toBlob() with image/png for gradients and text, because PNG keeps smooth blends intact, and use JPEG only when the image is mostly photograph. PNG vs JPG explains the trade. Draw at the real output size, such as 1200×630 for a link preview, rather than scaling a small canvas up.

js
canvas.toBlob((blob) => {
  const a = document.createElement('a')
  a.href = URL.createObjectURL(blob)
  a.download = 'card.png'
  a.click()
  setTimeout(() => URL.revokeObjectURL(a.href), 1000)
}, 'image/png')
Download the finished canvas as a PNG. On a server, the same drawing code runs with a canvas library for Node.

Common canvas gradient problems

Symptom

  • Gradient looks blurry on a phone
  • Only one colour shows in a shape
  • Visible stripes in a dark gradient
  • IndexSizeError from addColorStop
  • Conic gradient starts in the wrong place

Fix

  • Multiply canvas width and height by devicePixelRatio, then ctx.scale() back
  • Create the gradient with the shape's coordinates, not the canvas's
  • Add light noise over the top, see gradient banding
  • Keep offsets between 0 and 1
  • Start at -Math.PI / 2 to match CSS

Wider colour on capable screens

Chrome and Safari accept canvas.getContext('2d', { colorSpace: 'display-p3' }), which lets vivid gradients use the wider P3 range. Browsers that do not support it fall back to sRGB.

When you need gradients that move with real lighting rather than flat blends, a canvas reaches its limits and WebGL takes over, covered in shader gradients. And when the canvas is only a means to an image, such as a social card or poster, Gradiently renders a Mark at any size from 200 to 8,000 px with the words laid out for you, so there is no drawing code to maintain.

Design with a living gradient

Posts, stories, slides and banners in every size, with text that always reads.

Start designing, free

Questions people ask

How do I make a gradient on an HTML canvas?

Call ctx.createLinearGradient(x0, y0, x1, y1), add colours with addColorStop(offset, colour), set ctx.fillStyle to the gradient and draw a shape such as fillRect.

What is the difference between createLinearGradient and CSS linear-gradient?

Canvas uses a start point and an end point in pixels, while CSS uses an angle and stretches the gradient to the element. A small helper can convert a CSS angle into canvas points.

Can I use oklch or hsl colours in addColorStop?

Yes. addColorStop accepts any CSS colour string the browser understands, including hex, rgb(), hsl() and, in current browsers, oklch().

Why does my canvas gradient only show one colour?

The gradient is positioned in canvas coordinates, so a shape drawn outside its start and end points only picks up the nearest end colour. Create the gradient using the shape's position and size.

How do I animate a canvas gradient?

Create a new gradient on each animation frame with updated stops or coordinates, and redraw. A gradient's stops cannot be moved or removed once added.

Share this guide

Written by GradientlyVerified Gradiently account

The team behind Gradiently, a design tool built around Marks: living gradients that make everything you design look like yours.

See our profile

On this page

The three gradient methodscreateLinearGradient and CSS anglescreateRadialGradientcreateConicGradientGradient text, strokes and animationSaving the canvas as an imageCommon canvas gradient problems

Share this guide

Next in CSS and web

SVG feTurbulence: noise, grain and texture filters

Keep reading

All CSS and web guides
CSS and web

CSS linear gradient: the complete guide to linear-gradient()

6 min read

Every part of linear-gradient() explained with a live example beside its code, from the default direction to hard stops, layered sheens and smoother OKLCH blends.

CSS and web

CSS conic gradient: wheels, pie charts and sheen

4 min read

conic-gradient() sweeps colour around a point like the hand of a clock. That one idea draws colour wheels, pie charts, donut charts, metallic sheen and starbursts.

Gradients

Why your gradient has stripes, and how to fix banding

5 min read

You made a smooth gradient and it came back striped. That is banding, and it has a simple cause and a handful of reliable fixes. Here is the arithmetic, then the cures.

Find the look that’s only yours.

Every Mark is a living background with one owner. Try an unclaimed Mark, and claim yours when it feels right.

Start designing

Check a certificate

Type a certificate number or a Mark’s code to see who owns it.

Works with ChatGPT and Claude

Ask your AI for a design. It makes it in your Mark, ready to edit.

ChatGPTClaude
How to connect

Product

  • Market
  • Explore
  • Pricing
  • Certificates

Learn

  • Field Guide
  • Help centre
  • What’s new

Developers

  • Overview
  • ChatGPT and Claude
  • API reference
  • API keys

Company

  • About
  • Contact us
  • Sign in

Legal

  • Terms
  • Privacy
  • Refunds
  • Mark protection
  • Cookies
  • All policies
Move through the letters. Each one wears a real Mark.Touch a letter to see its Mark.One name. Ten Marks inside it.
© 2026 Gradiently