# Degradado en canvas HTML: createLinearGradient, radial y cónico

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

Los degradados de canvas usan coordenadas donde CSS usa ángulos, y esa única diferencia causa casi toda la confusión. Aquí tienes cada método de degradado con código que funciona y una función que convierte un ángulo CSS en puntos de canvas.

## The short version

- Un degradado en canvas HTML es un objeto CanvasGradient creado con createLinearGradient, createRadialGradient o createConicGradient, al que se dan paradas de color con addColorStop y que se asigna a fillStyle o strokeStyle.
- Los degradados de canvas usan coordenadas en el espacio del canvas, no ángulos ni porcentajes, así que un degradado lineal necesita un punto inicial y un punto final.
- Los desplazamientos de las paradas de color van de 0 a 1, y se acepta cualquier cadena de color CSS, incluidos hex, rgb(), hsl() y oklch() en los navegadores actuales.
- createConicGradient empieza su barrido desde una línea que apunta a la derecha y mide el ángulo en radianes, a diferencia de conic-gradient en CSS, que empieza arriba y en grados.
- En pantallas de alta densidad, dimensiona el búfer del canvas según devicePixelRatio, o los degradados y el texto se verán borrosos.

Un **degradado en canvas HTML** se hace en tres pasos: crea un objeto de degradado con `ctx.createLinearGradient()`, `createRadialGradient()` o `createConicGradient()`, añade colores con `addColorStop(offset, colour)` y asígnalo a `ctx.fillStyle` antes de dibujar. A diferencia de CSS, un degradado de canvas se define con puntos en píxeles, así que le dices exactamente dónde empieza y dónde acaba el color. Todo lo que pintes con ese relleno toma la parte del degradado que tiene debajo.

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

El degradado de canvas más pequeño que funciona: una diagonal desde la esquina superior izquierda hasta la inferior derecha.

## Los tres métodos de degradado

| Método | Argumentos | Equivalente en 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` | Una parada de color con un porcentaje |

Cada método devuelve un CanvasGradient. Puedes guardarlo en una variable y reutilizarlo en tantas formas como quieras.

El degradado está fijado al canvas, no a la forma. Si creas un degradado de 0 a 400 y luego rellenas un cuadrado pequeño en x 300, el cuadrado solo muestra el extremo rosa. Eso sorprende a quien viene de CSS, donde un degradado siempre se estira al elemento. Crea el degradado con las coordenadas de la propia forma cuando quieras que encaje.

## createLinearGradient y los ángulos de CSS

CSS te deja escribir `135deg`. Canvas quiere dos puntos. Esta función convierte un ángulo CSS en los mismos puntos de inicio y fin que usa CSS, así que un diseño escrito como [degradado lineal en CSS](https://gradiently.design/es/guide/css-linear-gradient) se dibuja idéntico en 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)
```

En CSS, 0deg apunta hacia arriba y los ángulos giran en el sentido de las agujas del reloj. La fórmula de la longitud hace que las esquinas caigan justo en el primer y el último color, como en CSS.

El mismo degradado en CSS: `linear-gradient(135deg, #0f172a 0%, #0d9488 100%)`

Lo que dibuja la función de arriba en un canvas de 1200×630, el tamaño de una [imagen Open Graph](https://gradiently.design/es/guide/open-graph-tags). Si tus ángulos no cuadran, [el ángulo del degradado](https://gradiently.design/es/guide/gradient-angle) explica cómo los mide CSS.

## createRadialGradient

Un degradado radial en canvas se define con dos círculos: uno inicial y uno final. La parada de color 0 está en el primer círculo y la parada 1 en el segundo. Casi siempre querrás que el primer círculo sea un punto, así que su radio es 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)
```

Llevar la última parada a transparente te permite apilar varias luces sobre un mismo fondo, que es como se construyen los fondos en capas.

Aleja el centro del primer círculo del segundo y la luz se inclina, como un foco que da en una pared en ángulo. CSS no tiene un equivalente directo de ese desplazamiento. Para la parte de CSS, mira [degradados radiales en CSS](https://gradiently.design/es/guide/css-radial-gradient).

## createConicGradient

`createConicGradient(startAngle, x, y)` hace girar el color alrededor de un punto central. Hay dos diferencias con CSS: el ángulo va en radianes, y 0 apunta a la derecha (las tres en punto), no hacia arriba. Para igualar un `conic-gradient(from 0deg, ...)` de CSS, empieza en `-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 el primer color en el desplazamiento 1 oculta la costura. createConicGradient funciona en las versiones actuales de Chrome, Edge, Safari y 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)`

Los tres ejemplos de este artículo, mostrados como sus gemelos en CSS. [Degradados cónicos en CSS](https://gradiently.design/es/guide/css-conic-gradient) trata la versión cónica más a fondo.

## Texto degradado, trazos y animación

`fillStyle` y `strokeStyle` aceptan los dos un degradado, así que el texto y los contornos funcionan igual. Coloca el degradado sobre la caja del propio texto, medida con `measureText()`, para que toda la gama de colores aparezca dentro de las 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)
```

No puedes mover ni quitar una parada una vez añadida, así que anima creando un degradado nuevo en cada fotograma. Pausa el bucle para quien prefiera reducir el movimiento.

## Guardar el canvas como imagen

Un motivo habitual para dibujar degradados en canvas es generar una imagen: una tarjeta para compartir, un certificado, una portada. Llama a `canvas.toBlob()` con `image/png` para degradados y texto, porque PNG conserva intactas las mezclas suaves, y usa JPEG solo cuando la imagen sea sobre todo fotografía. [PNG o JPG](https://gradiently.design/es/guide/png-vs-jpeg) explica el equilibrio. Dibuja al tamaño real de salida, como 1200×630 para una vista previa de enlace, en lugar de ampliar un canvas pequeño.

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

Descarga el canvas terminado como PNG. En un servidor, el mismo código de dibujo funciona con una librería de canvas para Node.

## Problemas habituales con los degradados de canvas

### Síntoma

- El degradado se ve borroso en el móvil
- Solo aparece un color en una forma
- Bandas visibles en un degradado oscuro
- `IndexSizeError` en addColorStop
- El degradado cónico empieza en el sitio equivocado

### Solución

- Multiplica el ancho y el alto del canvas por `devicePixelRatio` y compensa con `ctx.scale()`
- Crea el degradado con las coordenadas de la forma, no las del canvas
- Añade un ruido suave por encima, mira [bandas en degradados](https://gradiently.design/es/guide/gradient-banding)
- Mantén los desplazamientos entre 0 y 1
- Empieza en `-Math.PI / 2` para igualar CSS

> **Más color en las pantallas que lo admiten** Chrome y Safari aceptan `canvas.getContext('2d', { colorSpace: 'display-p3' })`, que permite a los degradados intensos usar la gama P3, más amplia. Los navegadores que no lo admiten vuelven a sRGB.

Cuando necesitas degradados que se muevan con iluminación real en lugar de mezclas planas, el canvas llega a su límite y toma el relevo WebGL, como se explica en [degradados con shaders](https://gradiently.design/es/guide/shader-gradients). Y cuando el canvas es solo un medio para obtener una imagen, como una tarjeta para redes o un cartel, Gradiently renderiza un Mark a cualquier tamaño entre 200 y 8.000 px con las palabras ya maquetadas, así que no hay código de dibujo que mantener.

## FAQ

### ¿Cómo hago un degradado en un canvas HTML?

Llama a `ctx.createLinearGradient(x0, y0, x1, y1)`, añade colores con `addColorStop(offset, colour)`, asigna el degradado a `ctx.fillStyle` y dibuja una forma, por ejemplo con `fillRect`.

### ¿Qué diferencia hay entre createLinearGradient y linear-gradient de CSS?

Canvas usa un punto inicial y un punto final en píxeles, mientras que CSS usa un ángulo y estira el degradado al elemento. Una pequeña función puede convertir un ángulo CSS en puntos de canvas.

### ¿Puedo usar colores oklch o hsl en addColorStop?

Sí. addColorStop acepta cualquier cadena de color CSS que entienda el navegador, incluidos hex, rgb(), hsl() y, en los navegadores actuales, oklch().

### ¿Por qué mi degradado de canvas solo muestra un color?

El degradado se sitúa en coordenadas del canvas, así que una forma dibujada fuera de sus puntos inicial y final solo toma el color del extremo más cercano. Crea el degradado con la posición y el tamaño de la forma.

### ¿Cómo animo un degradado de canvas?

Crea un degradado nuevo en cada fotograma de la animación con paradas o coordenadas actualizadas, y vuelve a dibujar. Las paradas de un degradado no se pueden mover ni quitar una vez añadidas.
