Gradientes en Canvas
Los gradientes de HTML5 Canvas son patrones de color para rellenar círculos, rectángulos, líneas, texto y más. Aprende sobre gradientes lineales y radiales.
Un gradiente, en términos generales, es un patrón de colores que cambia suavemente de un color a otro. Los gradientes de HTML5 Canvas te permiten rellenar o trazar formas — círculos, rectángulos, líneas, texto, trazados arbitrarios — con este tipo de mezcla de múltiples colores en lugar de un único color sólido.
Este capítulo cubre los tres tipos de gradientes que puedes crear en un contexto de canvas 2D, cómo sus parámetros de coordenadas controlan la dirección y el tamaño, cómo addColorStop() coloca los colores a lo largo del gradiente, y varios ejemplos ejecutables (vertical, diagonal, rellenos de texto/trazados y un brillo radial). Si eres nuevo en la API de canvas, comienza con la introducción a HTML5 Canvas, luego dibujar formas y trazados, y revisa cómo funciona el sistema de coordenadas del canvas.
Cómo funcionan los gradientes en canvas
Trabajar con un gradiente siempre sigue los mismos cuatro pasos:
- Crear un objeto de gradiente con uno de los métodos de fábrica del contexto:
ctx.createLinearGradient(x0, y0, x1, y1)— un gradiente lineal (direccional).ctx.createRadialGradient(x0, y0, r0, x1, y1, r1)— un gradiente radial (circular).ctx.createConicGradient(startAngle, x, y)— un gradiente cónico (barrido angular).
- Añadir dos o más paradas de color con
gradient.addColorStop(offset, color). - Asignar el gradiente a
ctx.fillStyleoctx.strokeStyle. - Dibujar una forma (
fillRect,fill,stroke,fillText, …). El gradiente se muestrea donde sea que pintes.
Un aspecto clave que debes comprender: las coordenadas del gradiente están en el espacio del canvas (absoluto), no en relación a la forma que rellenas. Un gradiente creado de (0, 0) a (300, 0) siempre abarca esa región del canvas. Si dibujas un rectángulo fuera de ese rango, tomará el primer o último color del gradiente (el que esté más cercano), porque los colores antes del offset 0 y después del offset 1 se fijan en los extremos.
addColorStop(): colocación de colores
gradient.addColorStop(offset, color) añade una parada de color al gradiente.
offset— un número entre0.0(el inicio del gradiente) y1.0(el final). Los valores fuera de este rango generan un error.color— cualquier cadena de color CSS: un nombre ("green"), hexadecimal ("#14389c"),rgb()/rgba(), ohsl(). Usa el canal alfa (rgba(...)) para paradas transparentes.
Necesitas al menos dos paradas para una mezcla visible. El offset de cada parada controla dónde ocurre la transición — cuanto menor sea la distancia entre dos offsets, más brusco será el cambio de color entre ellos. Un espaciado uniforme produce una mezcla suave; agrupar los offsets crea bandas bien definidas.
<!DOCTYPE html>
<html>
<head>
<title>Three color stops</title>
<style>
canvas { border: 1px solid #cccccc; }
</style>
</head>
<body>
<canvas id="stopsCanvas" width="300" height="120"></canvas>
<script>
const ctx = document.getElementById("stopsCanvas").getContext("2d");
const grd = ctx.createLinearGradient(0, 0, 300, 0);
grd.addColorStop(0, "red"); // start
grd.addColorStop(0.5, "yellow"); // exact middle
grd.addColorStop(1, "green"); // end
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 300, 120);
</script>
</body>
</html>Si mueves la parada del medio de 0.5 a 0.85, la banda amarilla se desplaza hacia la derecha, dejando la mayor parte de la barra con una mezcla de rojo a amarillo — eso es el offset controlando la posición.
Gradiente lineal
ctx.createLinearGradient(x0, y0, x1, y1) devuelve un gradiente cuyo color cambia a lo largo de una línea recta — el vector de gradiente que va desde el punto inicial (x0, y0) hasta el punto final (x1, y1):
x0, y0— el punto inicial del gradiente. La parada de color en el offset0se pinta aquí.x1, y1— el punto final del gradiente. La parada de color en el offset1se pinta aquí.
La dirección de la línea entre esos dos puntos establece la dirección del gradiente, y la distancia entre ellos determina cuánto se extiende la mezcla. Las líneas perpendiculares al vector tienen un único color sólido.
- Un gradiente horizontal mantiene
yigual:createLinearGradient(0, 0, 300, 0). - Un gradiente vertical mantiene
xigual:createLinearGradient(0, 0, 0, 200). - Un gradiente diagonal cambia ambos:
createLinearGradient(0, 0, 300, 200).
Recuerda el sistema de coordenadas del canvas: (0, 0) es la esquina superior izquierda, x aumenta hacia la derecha y y aumenta hacia abajo.
Ejemplo de un gradiente lineal horizontal usando fillStyle
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
canvas {
border: 1px solid #cccccc;
}
</style>
</head>
<body>
<canvas id="exampleCanvas" width="300" height="150">
Your browser doesn't support the HTML5 canvas tag.
</canvas>
<script>
var c = document.getElementById("exampleCanvas");
var ctx = c.getContext("2d");
var grd = ctx.createLinearGradient(0, 0, 300, 0);
grd.addColorStop(0, "green");
grd.addColorStop(1, "whitesmoke");
ctx.fillStyle = grd;
ctx.fillRect(20, 20, 260, 110);
</script>
</body>
</html>Como el vector va de (0, 0) a (300, 0), la mezcla es puramente horizontal: el borde izquierdo es verde y el borde derecho es whitesmoke.
Ejemplo de un gradiente lineal vertical
Mantén x igual en ambos puntos (aquí 0) y cambia solo y para mezclar de arriba hacia abajo:
<!DOCTYPE html>
<html>
<head>
<title>Vertical gradient</title>
<style>
canvas { border: 1px solid #cccccc; }
</style>
</head>
<body>
<canvas id="verticalCanvas" width="300" height="200"></canvas>
<script>
const ctx = document.getElementById("verticalCanvas").getContext("2d");
// Same x (0), different y → top-to-bottom blend.
const grd = ctx.createLinearGradient(0, 0, 0, 200);
grd.addColorStop(0, "#1e3c72"); // top
grd.addColorStop(1, "#2a5298"); // bottom
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 300, 200);
</script>
</body>
</html>Ejemplo de un gradiente lineal diagonal
Cambia tanto x como y para que el vector vaya de esquina a esquina:
<!DOCTYPE html>
<html>
<head>
<title>Diagonal gradient</title>
<style>
canvas { border: 1px solid #cccccc; }
</style>
</head>
<body>
<canvas id="diagonalCanvas" width="300" height="200"></canvas>
<script>
const ctx = document.getElementById("diagonalCanvas").getContext("2d");
// Vector from the top-left corner to the bottom-right corner.
const grd = ctx.createLinearGradient(0, 0, 300, 200);
grd.addColorStop(0, "#ff512f");
grd.addColorStop(0.5, "#f09819");
grd.addColorStop(1, "#ffd452");
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 300, 200);
</script>
</body>
</html>Ejemplo de un gradiente lineal usando fillStyle con diferentes colores:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
canvas {
border: 2px solid #202131;
}
</style>
</head>
<body>
<canvas id="exampleCanvas" width="500" height="200"></canvas>
<script>
var canvas = document.getElementById('exampleCanvas');
var context = canvas.getContext('2d');
context.rect(0, 0, 500, 200);
var linear = context.createLinearGradient(0, 0, 500, 200);
linear.addColorStop(0, '#297979');
linear.addColorStop(1, '#2ee035');
context.fillStyle = linear;
context.fill();
</script>
</body>
</html>Ejemplo de un gradiente lineal usando fillStyle y strokeStyle:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
canvas {
border: 5px solid #cccccc;
}
</style>
<script>
function drawShape() {
var canvas = document.getElementById('canvasGradient');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var lgrad1 = ctx.createLinearGradient(0, 0, 0, 300);
lgrad1.addColorStop(0, 'blue');
lgrad1.addColorStop(0.4, 'lightpink');
lgrad1.addColorStop(0.5, 'purple');
lgrad1.addColorStop(1, 'lightsalmon');
var lgrad2 = ctx.createLinearGradient(0, 50, 0, 150);
lgrad2.addColorStop(0, '#7afff3');
lgrad2.addColorStop(0.5, '#191918');
lgrad2.addColorStop(1, '#7afff3');
ctx.fillStyle = lgrad1;
ctx.strokeStyle = lgrad2;
ctx.fillRect(15, 15, 120, 120);
ctx.strokeRect(100, 50, 100, 50);
} else {
alert('Your browser does not support');
}
}
</script>
</head>
<body onload="drawShape();">
<canvas id="canvasGradient" width="300" height="300"></canvas>
</body>
</html>Ejemplo de un gradiente sobre texto y un trazado
Un gradiente no se limita a los rectángulos — funciona con cualquier relleno o trazo, incluyendo texto y trazados personalizados. Establécelo como fillStyle antes de fillText() (ver dibujar texto en canvas), o antes de fill()/stroke() sobre un trazado que hayas construido (ver dibujar en canvas).
<!DOCTYPE html>
<html>
<head>
<title>Gradient text and path</title>
<style>
canvas { border: 1px solid #cccccc; }
</style>
</head>
<body>
<canvas id="textCanvas" width="400" height="160"></canvas>
<script>
const ctx = document.getElementById("textCanvas").getContext("2d");
// A gradient spanning the canvas width.
const grd = ctx.createLinearGradient(0, 0, 400, 0);
grd.addColorStop(0, "#8e2de2");
grd.addColorStop(1, "#4a00e0");
// Fill text with the gradient.
ctx.font = "bold 48px sans-serif";
ctx.fillStyle = grd;
ctx.fillText("Gradient", 30, 70);
// Stroke a triangular path with the same gradient.
ctx.beginPath();
ctx.moveTo(40, 100);
ctx.lineTo(360, 100);
ctx.lineTo(200, 145);
ctx.closePath();
ctx.lineWidth = 6;
ctx.strokeStyle = grd;
ctx.stroke();
</script>
</body>
</html>Gradiente radial
ctx.createRadialGradient(x0, y0, r0, x1, y1, r1) define un gradiente entre dos círculos. El color se mezcla hacia afuera desde el círculo inicial hasta el círculo final:
x0, y0, r0— el centro(x0, y0)y el radior0del círculo inicial (interior). La parada de color en el offset0rellena este círculo.x1, y1, r1— el centro(x1, y1)y el radior1del círculo final (exterior). La parada de color en el offset1se alcanza en el borde de este círculo.
Cuando ambos círculos comparten el mismo centro, se obtiene un brillo perfectamente concéntrico. Cuando el centro del círculo interior está desplazado respecto al exterior, el punto brillante se mueve hacia un lado — así es exactamente como se simula una fuente de luz o un destello brillante (el ejemplo a continuación usa centros desplazados). Hacer que r0 sea mayor que 0 produce un núcleo sólido del primer color antes de que comience la mezcla.
Ejemplo de un gradiente radial con centros desplazados
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<style>
canvas {
border: 2px solid #cccccc;
}
</style>
</head>
<body>
<canvas id="exampleCanvas" width="300" height="150">
Your browser doesn't support the HTML5 canvas tag.
</canvas>
<script>
var c = document.getElementById("exampleCanvas");
var ctx = c.getContext("2d");
var grd = ctx.createRadialGradient(155, 80, 20, 130, 40, 190);
grd.addColorStop(0, "#14389c");
grd.addColorStop(1, "white");
ctx.fillStyle = grd;
ctx.fillRect(15, 15, 270, 120);
</script>
</body>
</html>Aquí el círculo interior está centrado en (155, 80) con radio 20, mientras que el círculo exterior está centrado en (130, 40) con radio 190. Como los centros difieren, el núcleo azul oscuro queda hacia la parte inferior derecha y se desvanece hacia blanco fuera del centro, dando al relleno un aspecto tridimensional, como iluminado desde un lado.
Ejemplo de un brillo radial
Una parada exterior completamente transparente sobre una región transparente del canvas crea un brillo suave que se puede superponer sobre otros dibujos. Nota el uso de rgba() para que el borde se desvanezca hasta nada en lugar de hasta blanco:
<!DOCTYPE html>
<html>
<head>
<title>Radial glow</title>
<style>
canvas { border: 1px solid #cccccc; background: #11131f; }
</style>
</head>
<body>
<canvas id="glowCanvas" width="300" height="200"></canvas>
<script>
const ctx = document.getElementById("glowCanvas").getContext("2d");
// Concentric circles: solid core at (150,100), fading out to radius 110.
const grd = ctx.createRadialGradient(150, 100, 5, 150, 100, 110);
grd.addColorStop(0, "rgba(255, 214, 102, 1)"); // bright core
grd.addColorStop(0.4, "rgba(255, 154, 0, 0.6)"); // warm mid
grd.addColorStop(1, "rgba(255, 154, 0, 0)"); // transparent edge
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 300, 200);
</script>
</body>
</html>Gradiente cónico
ctx.createConicGradient(startAngle, x, y) crea un gradiente que barre los colores alrededor de un punto central, como una rueda de colores o un gráfico circular, en lugar de a lo largo de una línea o entre círculos:
startAngle— el ángulo en radianes en el que comienza el offset0, medido en sentido horario desde el eje x positivo.x, y— el punto central de la rotación.
Las paradas de color se distribuyen alrededor de la vuelta completa, de modo que el offset 0 y el offset 1 se encuentran de nuevo en startAngle. Para evitar una costura visible, dale al primer y último stop el mismo color.
<!DOCTYPE html>
<html>
<head>
<title>Conic gradient</title>
<style>
canvas { border: 1px solid #cccccc; }
</style>
</head>
<body>
<canvas id="conicCanvas" width="200" height="200"></canvas>
<script>
const ctx = document.getElementById("conicCanvas").getContext("2d");
// Sweep starting at the top (-90° = -Math.PI/2), centered at (100,100).
const grd = ctx.createConicGradient(-Math.PI / 2, 100, 100);
grd.addColorStop(0, "red");
grd.addColorStop(0.25, "yellow");
grd.addColorStop(0.5, "lime");
grd.addColorStop(0.75, "blue");
grd.addColorStop(1, "red"); // matches stop 0 → seamless wheel
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 200, 200);
</script>
</body>
</html>createConicGradient() está soportado en las versiones actuales de todos los navegadores principales (Chrome, Edge, Firefox y Safari). Proporciona un color sólido de respaldo para navegadores muy antiguos si necesitas darles soporte.