A versão curta
- Um gradiente de canvas HTML é um objeto CanvasGradient criado com createLinearGradient, createRadialGradient ou createConicGradient, ao qual se juntam paragens de cor com addColorStop e que se atribui a fillStyle ou strokeStyle.
- Os gradientes de canvas usam coordenadas no espaço do canvas, não ângulos nem percentagens, por isso um gradiente linear precisa de um ponto inicial e de um ponto final.
- Os desvios das paragens de cor vão de 0 a 1, e é aceite qualquer cadeia de cor CSS, incluindo hex, rgb(), hsl() e oklch() nos navegadores atuais.
- O createConicGradient começa a varredura numa linha que aponta 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 ecrãs de alta densidade, dimensione o buffer do canvas com devicePixelRatio, ou os gradientes e o texto parecem desfocados.
Nesta página
Um gradiente de canvas HTML faz-se em três passos: criar um objeto de gradiente com ctx.createLinearGradient(), createRadialGradient() ou createConicGradient(), juntar cores com addColorStop(offset, colour) e atribuí-lo a ctx.fillStyle e desenhar. Ao contrário do CSS, um gradiente de canvas define-se por pontos em píxeis, por isso diz-se-lhe exatamente onde a cor começa e acaba. Tudo o que pintar com esse preenchimento apanha a parte do gradiente que está por baixo.
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)Os três métodos de gradiente
createLinearGradientArgumentos
x0, y0, x1, y1Equivalente em CSS
linear-gradient()createRadialGradientArgumentos
x0, y0, r0, x1, y1, r1Equivalente em CSS
radial-gradient()createConicGradientArgumentos
startAngle, x, yEquivalente em CSS
conic-gradient()addColorStopArgumentos
offset de 0 a 1, colourEquivalente em CSS
O gradiente fica fixo ao canvas, não à forma. Se criar um gradiente de 0 a 400 e depois preencher um quadrado pequeno em x 300, o quadrado mostra apenas a ponta rosa. Isto surpreende quem vem do CSS, onde um gradiente se estica sempre ao elemento. Crie o gradiente com as coordenadas da própria forma quando quiser que se ajuste.
createLinearGradient e ângulos CSS
O CSS permite escrever 135deg. O canvas quer dois pontos. Esta função auxiliar converte um ângulo CSS nos mesmos pontos inicial e final que o CSS usa, para um design escrito como gradiente linear CSS ser desenhado de forma idêntica no canvas.
// 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)linear-gradient(135deg, #0f172a 0%, #0d9488 100%)createRadialGradient
Um gradiente radial no canvas define-se por dois círculos: um círculo inicial e um final. A paragem de cor 0 fica no primeiro círculo e a paragem 1 no segundo. Na maior parte das vezes quer que o primeiro círculo seja um ponto, por isso o seu raio é 0.
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)Afaste o centro do primeiro círculo do segundo e a luz inclina-se, como um foco a bater numa parede em ângulo. O CSS não tem equivalente direto desse desvio. Para o lado CSS, veja gradientes radiais CSS.
createConicGradient
createConicGradient(startAngle, x, y) varre a cor à volta de um ponto central. Dois pormenores diferem do CSS: o ângulo está em radianos e 0 aponta para a direita (as três horas), não para cima. Para igualar um conic-gradient(from 0deg, ...) do CSS, comece em -Math.PI / 2.
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()Texto, contornos e animação com gradiente
fillStyle e strokeStyle aceitam ambos um gradiente, por isso o texto e os contornos funcionam da mesma maneira. Defina o gradiente ao longo da própria caixa do texto, medida com measureText(), para toda a gama de cores aparecer dentro das letras.
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)Guardar o canvas como imagem
Um motivo comum para desenhar gradientes no canvas é gerar uma imagem: um cartão de partilha, um certificado, uma capa. Chame canvas.toBlob() com image/png para gradientes e texto, porque o PNG mantém intactas as misturas suaves, e use JPEG apenas quando a imagem for sobretudo fotografia. PNG vs JPG explica a troca. Desenhe no tamanho real de saída, como 1200×630 para uma pré-visualização de ligação, em vez de ampliar um canvas pequeno.
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')Problemas comuns com gradientes de canvas
Sintoma
- O gradiente parece desfocado num telemóvel
- Só se vê uma cor numa forma
- Riscas visíveis num gradiente escuro
IndexSizeErrorem addColorStop- O gradiente cónico começa no sítio errado
Correção
- Multiplique a largura e a altura do canvas por
devicePixelRatioe depois usectx.scale()para voltar - Crie o gradiente com as coordenadas da forma, não as do canvas
- Junte ruído leve por cima, veja bandas em gradientes
- Mantenha os desvios entre 0 e 1
- Comece em
-Math.PI / 2para igualar o CSS
Quando precisa de gradientes que se movem com iluminação real em vez de misturas planas, o canvas atinge os seus limites e o WebGL toma o seu lugar, tratado em gradientes com shaders. E quando o canvas é só um meio para chegar a uma imagem, como um cartão social ou um cartaz, o Gradiently desenha um Mark em qualquer tamanho de 200 a 8000 px com as palavras já compostas, por isso não há código de desenho para manter.
Perguntas frequentes
Como faço um gradiente num canvas HTML?
Chame ctx.createLinearGradient(x0, y0, x1, y1), junte 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 píxeis, enquanto o CSS usa um ângulo e estica o gradiente ao elemento. Uma pequena função auxiliar pode converter um ângulo CSS em pontos de canvas.
Posso usar cores oklch ou hsl em addColorStop?
Sim. O addColorStop aceita qualquer cadeia de cor CSS que o navegador entenda, incluindo hex, rgb(), hsl() e, nos navegadores atuais, oklch().
Porque é que o meu gradiente de canvas só mostra uma cor?
O gradiente está posicionado em coordenadas do canvas, por isso uma forma desenhada fora dos seus pontos inicial e final só apanha a cor da ponta mais próxima. Crie o gradiente com a posição e o tamanho da forma.
Como animo um gradiente de canvas?
Crie um novo gradiente a cada fotograma da animação, com paragens ou coordenadas atualizadas, e volte a desenhar. As paragens de um gradiente não podem ser movidas nem removidas depois de adicionadas.
Escrito pela Gradiently
A equipa por trás da Gradiently, uma ferramenta de design construída em torno dos Marks: gradientes vivos que fazem tudo o que crias parecer teu.
Ver o nosso perfil