# HTML Canvas Farbverlauf: createLinearGradient, radial und konisch

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

Canvas-Verläufe nehmen Koordinaten, wo CSS Winkel nimmt, und dieser eine Unterschied sorgt für die meiste Verwirrung. Hier ist jede Verlaufsmethode mit lauffähigem Code und eine Hilfsfunktion, die einen CSS-Winkel in Canvas-Punkte umrechnet.

## The short version

- Ein HTML Canvas Farbverlauf ist ein CanvasGradient-Objekt, das mit createLinearGradient, createRadialGradient oder createConicGradient erzeugt, mit addColorStop mit Farbstopps versehen und fillStyle oder strokeStyle zugewiesen wird.
- Canvas-Verläufe nutzen Koordinaten im Canvas-Raum statt Winkeln oder Prozentwerten, also braucht ein linearer Verlauf einen Start- und einen Endpunkt.
- Offsets der Farbstopps reichen von 0 bis 1, und jeder CSS-Farbstring wird akzeptiert, in aktuellen Browsern auch Hex, rgb(), hsl() und oklch().
- createConicGradient beginnt seinen Umlauf an einer nach rechts zeigenden Linie und misst den Winkel in Radiant, anders als CSS conic-gradient, das oben in Grad beginnt.
- Auf Bildschirmen mit hoher Pixeldichte musst du den Canvas-Puffer mit devicePixelRatio skalieren, sonst wirken Verläufe und Text weich.

Ein **HTML Canvas Farbverlauf** braucht drei Schritte: ein Verlaufsobjekt mit `ctx.createLinearGradient()`, `createRadialGradient()` oder `createConicGradient()` erzeugen, Farben mit `addColorStop(offset, colour)` hinzufügen, dann `ctx.fillStyle` zuweisen und zeichnen. Anders als in CSS wird ein Canvas-Verlauf durch Punkte in Pixeln definiert, du sagst ihm also genau, wo die Farbe beginnt und endet. Alles, was du mit dieser Füllung malst, übernimmt den Teil des Verlaufs, der darunter liegt.

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

Der kleinste funktionierende Canvas-Verlauf: eine Diagonale von der oberen linken in die untere rechte Ecke.

## Die drei Verlaufsmethoden

| Methode | Argumente | CSS-Entsprechung |
| --- | --- | --- |
| `createLinearGradient` | `x0, y0, x1, y1` | `linear-gradient()` |
| `createRadialGradient` | `x0, y0, r0, x1, y1, r1` | `radial-gradient()` |
| `createConicGradient` | `startAngle, x, y` | `conic-gradient()` |
| `addColorStop` | `offset` 0 bis 1, `colour` | Ein Farbstopp mit Prozentwert |

Jede Methode gibt ein CanvasGradient zurück. Du kannst es in einer Variable halten und für beliebig viele Formen wiederverwenden.

Der Verlauf ist am Canvas befestigt, nicht an der Form. Erzeugst du einen Verlauf von 0 bis 400 und füllst dann ein kleines Quadrat bei x 300, zeigt das Quadrat nur das pinke Ende. Das überrascht alle, die von CSS kommen, wo sich ein Verlauf immer auf das Element dehnt. Erzeuge den Verlauf mit den Koordinaten der Form selbst, wenn er passen soll.

## createLinearGradient und CSS-Winkel

In CSS schreibst du `135deg`. Canvas will zwei Punkte. Diese Hilfsfunktion rechnet einen CSS-Winkel in dieselben Start- und Endpunkte um, die CSS verwendet, sodass ein als [CSS linear-gradient](https://gradiently.design/de/guide/css-linear-gradient) geschriebenes Design auf dem Canvas identisch aussieht.

```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 zeigt 0deg nach oben und Winkel drehen im Uhrzeigersinn. Die Längenformel sorgt dafür, dass die Ecken genau auf die erste und letzte Farbe fallen, wie in CSS.

Derselbe Verlauf in CSS: `linear-gradient(135deg, #0f172a 0%, #0d9488 100%)`

Was die Hilfsfunktion oben auf einen Canvas mit 1200×630 zeichnet, die Größe eines [Open-Graph-Bildes](https://gradiently.design/de/guide/open-graph-tags). Wenn deine Winkel falsch wirken, erklärt [Verlaufswinkel](https://gradiently.design/de/guide/gradient-angle), wie CSS sie misst.

## createRadialGradient

Ein radialer Verlauf auf dem Canvas wird durch zwei Kreise definiert: einen Startkreis und einen Endkreis. Farbstopp 0 liegt auf dem ersten Kreis, Stopp 1 auf dem zweiten. Meist soll der erste Kreis ein Punkt sein, sein Radius ist also 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)
```

Wenn der letzte Stopp ins Transparente ausläuft, kannst du mehrere Lichter auf einem Grund stapeln, und so werden geschichtete Hintergründe gebaut.

Verschiebst du den Mittelpunkt des ersten Kreises weg vom zweiten, kippt das Licht, wie ein Spot, der schräg auf eine Wand fällt. CSS hat für diesen Versatz keine direkte Entsprechung. Für die CSS-Seite siehe [radiale Farbverläufe in CSS](https://gradiently.design/de/guide/css-radial-gradient).

## createConicGradient

`createConicGradient(startAngle, x, y)` lässt Farbe um einen Mittelpunkt kreisen. Zwei Details unterscheiden sich von CSS: Der Winkel ist in Radiant, und 0 zeigt nach rechts (drei Uhr), nicht nach oben. Um ein CSS `conic-gradient(from 0deg, ...)` nachzubilden, beginne bei `-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()
```

Die erste Farbe bei Offset 1 zu wiederholen versteckt die Naht. createConicGradient funktioniert in aktuellen Versionen von Chrome, Edge, Safari und 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)`

Die drei Beispiele aus diesem Artikel als ihre CSS-Zwillinge. [Konische Farbverläufe in CSS](https://gradiently.design/de/guide/css-conic-gradient) behandelt die konische Variante ausführlicher.

## Verlaufstext, Konturen und Animation

`fillStyle` und `strokeStyle` akzeptieren beide einen Verlauf, also funktionieren Text und Konturen genauso. Leg den Verlauf über den eigenen Kasten des Textes, gemessen mit `measureText()`, damit die ganze Farbskala innerhalb der Buchstaben erscheint.

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

Einen einmal hinzugefügten Stopp kannst du weder verschieben noch entfernen, also animierst du, indem du in jedem Frame einen neuen Verlauf erzeugst. Pausiere die Schleife für Nutzer, die reduzierte Bewegung bevorzugen.

## Den Canvas als Bild speichern

Ein häufiger Grund, Verläufe auf einen Canvas zu zeichnen, ist das Erzeugen eines Bildes: eine Share-Karte, ein Zertifikat, ein Cover. Ruf `canvas.toBlob()` mit `image/png` für Verläufe und Text auf, weil PNG weiche Übergänge intakt hält, und nimm JPEG nur, wenn das Bild überwiegend Foto ist. [PNG vs. JPG](https://gradiently.design/de/guide/png-vs-jpeg) erklärt den Unterschied. Zeichne in der echten Ausgabegröße, etwa 1200×630 für eine Linkvorschau, statt einen kleinen Canvas hochzuskalieren.

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

Lade den fertigen Canvas als PNG herunter. Auf einem Server läuft derselbe Zeichencode mit einer Canvas-Bibliothek für Node.

## Häufige Probleme mit Canvas-Verläufen

### Symptom

- Der Verlauf wirkt auf dem Handy unscharf
- In einer Form erscheint nur eine Farbe
- Sichtbare Streifen in einem dunklen Verlauf
- `IndexSizeError` von addColorStop
- Der konische Verlauf beginnt an der falschen Stelle

### Lösung

- Breite und Höhe des Canvas mit `devicePixelRatio` multiplizieren, dann mit `ctx.scale()` zurückskalieren
- Den Verlauf mit den Koordinaten der Form erzeugen, nicht mit denen des Canvas
- Leichtes Rauschen darüberlegen, siehe [Streifenbildung in Farbverläufen](https://gradiently.design/de/guide/gradient-banding)
- Offsets zwischen 0 und 1 halten
- Bei `-Math.PI / 2` beginnen, um CSS zu entsprechen

> **Größerer Farbraum auf fähigen Bildschirmen** Chrome und Safari akzeptieren `canvas.getContext('2d', { colorSpace: 'display-p3' })`, wodurch leuchtende Verläufe den größeren P3-Farbraum nutzen können. Browser ohne Unterstützung fallen auf sRGB zurück.

Wenn du Verläufe brauchst, die sich mit echtem Licht bewegen statt flacher Übergänge, stößt ein Canvas an seine Grenzen und WebGL übernimmt, beschrieben in [Shader-Farbverläufe](https://gradiently.design/de/guide/shader-gradients). Und wenn der Canvas nur Mittel zum Bild ist, etwa für eine Social-Media-Karte oder ein Poster, rendert Gradiently einen Mark in jeder Größe von 200 bis 8.000 px mit fertig angeordneten Wörtern, sodass du keinen Zeichencode pflegen musst.

## FAQ

### Wie erstelle ich einen Farbverlauf auf einem HTML Canvas?

Ruf `ctx.createLinearGradient(x0, y0, x1, y1)` auf, füge Farben mit `addColorStop(offset, colour)` hinzu, setz `ctx.fillStyle` auf den Verlauf und zeichne eine Form wie `fillRect`.

### Was ist der Unterschied zwischen createLinearGradient und CSS linear-gradient?

Canvas nutzt einen Start- und einen Endpunkt in Pixeln, CSS einen Winkel und dehnt den Verlauf auf das Element. Eine kleine Hilfsfunktion kann einen CSS-Winkel in Canvas-Punkte umrechnen.

### Kann ich oklch- oder hsl-Farben in addColorStop verwenden?

Ja. addColorStop akzeptiert jeden CSS-Farbstring, den der Browser versteht, darunter Hex, rgb(), hsl() und in aktuellen Browsern oklch().

### Warum zeigt mein Canvas-Verlauf nur eine Farbe?

Der Verlauf ist in Canvas-Koordinaten positioniert, also bekommt eine Form außerhalb seiner Start- und Endpunkte nur die nächstgelegene Endfarbe. Erzeuge den Verlauf mit Position und Größe der Form.

### Wie animiere ich einen Canvas-Verlauf?

Erzeuge in jedem Animationsframe einen neuen Verlauf mit aktualisierten Stopps oder Koordinaten und zeichne neu. Die Stopps eines Verlaufs lassen sich nach dem Hinzufügen weder verschieben noch entfernen.
