# Gradiente no canvas HTML: createLinearGradient, radial e cônico

[Canonical HTML page](https://gradiently.design/pt-br/guide/canvas-gradient)

Gradientes no canvas usam coordenadas onde o CSS usa ângulos, e essa única diferença causa a maior parte da confusão. Aqui estão todos os métodos de gradiente com código que funciona e uma função que transforma um ângulo CSS em pontos no canvas.

## The short version

- Um gradiente no canvas HTML é um objeto CanvasGradient criado com createLinearGradient, createRadialGradient ou createConicGradient, que recebe paradas de cor com addColorStop e é atribuído a fillStyle ou strokeStyle.
- Gradientes no canvas usam coordenadas no espaço do canvas, não ângulos nem porcentagens, então um gradiente linear precisa de um ponto inicial e um ponto final.
- Os offsets das paradas de cor vão de 0 a 1, e qualquer string de cor CSS é aceita, incluindo hex, rgb(), hsl() e oklch() nos navegadores atuais.
- O createConicGradient começa a varredura a partir de uma linha apontando para a direita e mede o ângulo em radianos, ao contrário do conic-gradient do CSS, que começa no topo e usa graus.
- Em telas de alta densidade, dimensione o buffer do canvas pelo devicePixelRatio, ou gradientes e textos ficam borrados.

Um **gradiente no canvas HTML** leva três passos: crie um objeto de gradiente com `ctx.createLinearGradient()`, `createRadialGradient()` ou `createConicGradient()`, adicione cores com `addColorStop(offset, colour)` e depois atribua a `ctx.fillStyle` e desenhe. Ao contrário do CSS, um gradiente no canvas é definido por pontos em pixels, então você diz exatamente onde a cor começa e termina. Tudo o que você pinta com esse preenchimento pega a parte do gradiente que está por baixo.

```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)
```

O menor gradiente funcional no canvas: uma diagonal do canto superior esquerdo ao canto inferior direito.

## Os três métodos de gradiente

| Método | Argumentos | Equivalente em CSS |
| --- | --- | --- |
| `createLinearGradient` | `x0, y0, x1, y1` | `linear-gradient()` |
| `createRadialGradient` | `x0, y0, r0, x1, y1, r1` | `radial-gradient()` |
| `createConicGradient` | `startAngle, x, y` | `conic-gradient()` |
| `addColorStop` | `offset` de 0 a 1, `colour` | Uma parada de cor com porcentagem |

Todo método retorna um CanvasGradient. Você pode guardá-lo em uma variável e reutilizá-lo em quantas formas quiser.

O gradiente fica preso ao canvas, não à forma. Se você cria um gradiente de 0 a 400 e depois preenche um quadradinho em x 300, o quadrado mostra só a ponta rosa. Isso surpreende quem vem do CSS, em que um gradiente sempre se estica até o tamanho do elemento. Crie o gradiente com as coordenadas da própria forma quando quiser que ele se encaixe.

## createLinearGradient e ângulos CSS

O CSS deixa você escrever `135deg`. O canvas quer dois pontos. Esta função converte um ângulo CSS nos mesmos pontos inicial e final que o CSS usa, para que um design escrito como [gradiente linear em CSS](https://gradiently.design/pt-br/guide/css-linear-gradient) apareça idêntico no 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)
```

No CSS, 0deg aponta para cima e os ângulos giram no sentido horário. A fórmula do comprimento faz os cantos caírem exatamente na primeira e na última cor, como no CSS.

O mesmo gradiente em CSS: `linear-gradient(135deg, #0f172a 0%, #0d9488 100%)`

O que a função acima desenha em um canvas de 1200×630, o tamanho de uma [imagem Open Graph](https://gradiently.design/pt-br/guide/open-graph-tags). Se os ângulos parecerem errados, [ângulo do gradiente](https://gradiently.design/pt-br/guide/gradient-angle) explica como o CSS os mede.

## createRadialGradient

Um gradiente radial no canvas é definido por dois círculos: um círculo inicial e um círculo final. A parada de cor 0 fica no primeiro círculo e a parada 1, no segundo. Na maioria das vezes você quer que o primeiro círculo seja um ponto, então o raio dele é 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)
```

Esmaecer a última parada até a transparência permite empilhar várias luzes sobre um mesmo fundo, que é como se constroem fundos em camadas.

Afaste o centro do primeiro círculo do segundo e a luz se inclina, como um holofote batendo em uma parede de lado. O CSS não tem um equivalente direto desse deslocamento. Para o lado do CSS, veja [gradientes radiais em CSS](https://gradiently.design/pt-br/guide/css-radial-gradient).

## createConicGradient

`createConicGradient(startAngle, x, y)` varre a cor em volta de um ponto central. Dois detalhes diferem do CSS: o ângulo é em radianos, e 0 aponta para a direita (três horas), não para cima. Para igualar um `conic-gradient(from 0deg, ...)` do CSS, comece em `-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()
```

Repetir a primeira cor no offset 1 esconde a emenda. O createConicGradient funciona nas versões atuais de Chrome, Edge, Safari e Firefox.

- createLinearGradient: `linear-gradient(135deg, #1e1b4b 0%, #7c3aed 55%, #f472b6 100%)`
- createRadialGradient: `radial-gradient(circle at 75% 20%, #7c3aed 0%, #2e1065 30%, #0c0a1d 60%)`
- createConicGradient: `conic-gradient(from 0deg, #22d3ee, #7c3aed, #f472b6, #22d3ee)`

Os três exemplos deste artigo, mostrados como seus gêmeos em CSS. [Gradientes cônicos em CSS](https://gradiently.design/pt-br/guide/css-conic-gradient) trata da versão cônica com mais profundidade.

## Texto com gradiente, contornos e animação

`fillStyle` e `strokeStyle` aceitam gradientes, então textos e contornos funcionam do mesmo jeito. Posicione o gradiente sobre a caixa do próprio texto, medida com `measureText()`, para que toda a faixa de cores apareça dentro das letras.

```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)
```

Não dá para mover nem remover uma parada depois de adicionada, então anime criando um gradiente novo a cada quadro. Pause o loop para quem prefere movimento reduzido.

## Salvar o canvas como imagem

Um motivo comum para desenhar gradientes no canvas é gerar uma imagem: um card de compartilhamento, um certificado, uma capa. Chame `canvas.toBlob()` com `image/png` para gradientes e texto, porque o PNG mantém as transições suaves intactas, e use JPEG só quando a imagem for quase toda fotografia. [PNG ou JPG](https://gradiently.design/pt-br/guide/png-vs-jpeg) explica a troca. Desenhe no tamanho real de saída, como 1200×630 para a prévia de um link, em vez de ampliar um canvas pequeno.

```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')
```

Baixe o canvas pronto como PNG. Em um servidor, o mesmo código de desenho roda com uma biblioteca de canvas para Node.

## Problemas comuns com gradientes no canvas

### Sintoma

- O gradiente fica borrado no celular
- Só aparece uma cor em uma forma
- Faixas visíveis em um gradiente escuro
- `IndexSizeError` vindo do addColorStop
- O gradiente cônico começa no lugar errado

### Solução

- Multiplique a largura e a altura do canvas por `devicePixelRatio` e volte com `ctx.scale()`
- Crie o gradiente com as coordenadas da forma, não do canvas
- Adicione um ruído leve por cima; veja [banding em gradientes](https://gradiently.design/pt-br/guide/gradient-banding)
- Mantenha os offsets entre 0 e 1
- Comece em `-Math.PI / 2` para igualar o CSS

> **Cores mais amplas em telas compatíveis** Chrome e Safari aceitam `canvas.getContext('2d', { colorSpace: 'display-p3' })`, o que permite que gradientes vivos usem a faixa P3, mais ampla. Navegadores sem suporte voltam para sRGB.

Quando você precisa de gradientes que se movem com iluminação real em vez de transições chapadas, o canvas chega ao limite e o WebGL assume, assunto de [gradientes com shader](https://gradiently.design/pt-br/guide/shader-gradients). E quando o canvas é só um meio para chegar a uma imagem, como um card social ou um cartaz, o Gradiently renderiza um Mark em qualquer tamanho de 200 a 8.000 px com as palavras já diagramadas, então não há código de desenho para manter.

## FAQ

### Como faço um gradiente em um canvas HTML?

Chame `ctx.createLinearGradient(x0, y0, x1, y1)`, adicione cores com `addColorStop(offset, colour)`, defina `ctx.fillStyle` como o gradiente e desenhe uma forma, como `fillRect`.

### Qual a diferença entre createLinearGradient e o linear-gradient do CSS?

O canvas usa um ponto inicial e um ponto final em pixels, enquanto o CSS usa um ângulo e estica o gradiente até o elemento. Uma pequena função converte um ângulo CSS em pontos no canvas.

### Posso usar cores oklch ou hsl no addColorStop?

Sim. O addColorStop aceita qualquer string de cor CSS que o navegador entenda, incluindo hex, rgb(), hsl() e, nos navegadores atuais, oklch().

### Por que o meu gradiente no canvas mostra só uma cor?

O gradiente é posicionado em coordenadas do canvas, então uma forma desenhada fora dos pontos inicial e final pega só a cor da ponta mais próxima. Crie o gradiente usando a posição e o tamanho da forma.

### Como animo um gradiente no canvas?

Crie um gradiente novo a cada quadro da animação, com paradas ou coordenadas atualizadas, e redesenhe. As paradas de um gradiente não podem ser movidas nem removidas depois de adicionadas.
