# HTML canvas kleurverloop: linear, radiaal en conisch

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

Canvas-verlopen werken met coördinaten waar CSS hoeken gebruikt, en dat ene verschil veroorzaakt de meeste verwarring. Hier staat elke verloopmethode met code die werkt, plus een helper die een CSS-hoek omzet in canvaspunten.

## The short version

- Een HTML canvas kleurverloop is een CanvasGradient-object, gemaakt met createLinearGradient, createRadialGradient of createConicGradient, voorzien van kleurstops met addColorStop en toegewezen aan fillStyle of strokeStyle.
- Canvas-verlopen gebruiken coördinaten in de canvasruimte, geen hoeken of percentages, dus een lineair verloop heeft een beginpunt en een eindpunt nodig.
- Offsets van kleurstops lopen van 0 tot 1 en elke CSS-kleurtekst is toegestaan, ook hex, rgb(), hsl() en in actuele browsers oklch().
- createConicGradient begint zijn draai bij een lijn die naar rechts wijst en meet de hoek in radialen, anders dan CSS conic-gradient, dat bovenaan begint en graden gebruikt.
- Maak op schermen met hoge dichtheid de canvasbuffer groter met devicePixelRatio, anders ogen verlopen en tekst wazig.

Een **HTML canvas kleurverloop** vraagt drie stappen: maak een verloopobject met `ctx.createLinearGradient()`, `createRadialGradient()` of `createConicGradient()`, voeg kleuren toe met `addColorStop(offset, kleur)` en wijs het toe aan `ctx.fillStyle` om te tekenen. Anders dan in CSS wordt een canvas-verloop bepaald door punten in pixels, dus je geeft precies aan waar de kleur begint en eindigt. Alles wat je met die vulling schildert, pakt het deel van het verloop dat eronder ligt.

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

Het kleinste werkende canvas-verloop: een diagonaal van de linkerbovenhoek naar de rechteronderhoek.

## De drie verloopmethodes

| Methode | Argumenten | CSS-equivalent |
| --- | --- | --- |
| `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 tot 1, `kleur` | Een kleurstop met een percentage |

Elke methode geeft een CanvasGradient terug. Je kunt hem in een variabele bewaren en voor zoveel vormen hergebruiken als je wilt.

Het verloop zit vast aan het canvas, niet aan de vorm. Maak je een verloop van 0 tot 400 en vul je daarna een klein vierkant op x 300, dan zie je in het vierkant alleen het roze uiteinde. Dat verrast mensen die uit CSS komen, waar een verloop altijd over het hele element loopt. Maak het verloop met de eigen coördinaten van de vorm als je wilt dat het past.

## createLinearGradient en CSS-hoeken

In CSS schrijf je `135deg`. Canvas wil twee punten. Deze helper zet een CSS-hoek om in dezelfde begin- en eindpunten die CSS gebruikt, zodat een ontwerp dat is geschreven als [CSS lineair verloop](https://gradiently.design/nl/guide/css-linear-gradient) op canvas er identiek uitziet.

```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 wijst 0deg omhoog en draaien hoeken met de klok mee. Dankzij de lengteformule landen de hoeken precies op de eerste en laatste kleur, zoals in CSS.

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

Wat de helper hierboven tekent op een canvas van 1200×630, het formaat van een [Open Graph-afbeelding](https://gradiently.design/nl/guide/open-graph-tags). Kloppen je hoeken niet, dan legt [verloophoek](https://gradiently.design/nl/guide/gradient-angle) uit hoe CSS ze meet.

## createRadialGradient

Een radiaal verloop op canvas wordt bepaald door twee cirkels: een begincirkel en een eindcirkel. Kleurstop 0 ligt op de eerste cirkel en stop 1 op de tweede. Meestal wil je dat de eerste cirkel een punt is, dus met straal 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)
```

Door de laatste stop naar transparant te laten vervagen kun je meerdere lichten op één ondergrond stapelen, en zo bouw je lagen in achtergronden.

Schuif het middelpunt van de eerste cirkel weg van dat van de tweede en het licht kantelt, als een spot die schuin op een muur valt. CSS heeft daar geen directe tegenhanger voor. Voor de CSS-kant, zie [CSS radiale verlopen](https://gradiently.design/nl/guide/css-radial-gradient).

## createConicGradient

`createConicGradient(startAngle, x, y)` laat kleur rond een middelpunt draaien. Twee dingen verschillen van CSS: de hoek is in radialen en 0 wijst naar rechts (drie uur), niet naar boven. Om een CSS `conic-gradient(from 0deg, ...)` na te bootsen begin je bij `-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()
```

Door de eerste kleur bij offset 1 te herhalen verdwijnt de naad. createConicGradient werkt in actuele versies van Chrome, Edge, Safari en 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)`

De drie voorbeelden uit dit artikel, getoond als hun CSS-tweelingen. [CSS conische verlopen](https://gradiently.design/nl/guide/css-conic-gradient) behandelt de conische versie uitgebreider.

## Verlooptekst, lijnen en animatie

`fillStyle` en `strokeStyle` accepteren allebei een verloop, dus tekst en omtrekken werken op dezelfde manier. Zet het verloop over het eigen vak van de tekst, gemeten met `measureText()`, zodat het volledige kleurbereik in de letters verschijnt.

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

Een stop die is toegevoegd kun je niet meer verplaatsen of verwijderen, dus animeer door elk frame een nieuw verloop te maken. Zet de lus stil voor mensen die minder beweging verkiezen.

## Het canvas als afbeelding opslaan

Een veelvoorkomende reden om verlopen op canvas te tekenen is het genereren van een afbeelding: een deelkaart, een certificaat, een cover. Roep `canvas.toBlob()` aan met `image/png` voor verlopen en tekst, want PNG houdt vloeiende overgangen intact, en gebruik JPEG alleen als de afbeelding vooral een foto is. [PNG of JPG](https://gradiently.design/nl/guide/png-vs-jpeg) legt de afweging uit. Teken op het echte uitvoerformaat, zoals 1200×630 voor een linkvoorbeeld, in plaats van een klein canvas op te schalen.

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

Download het afgewerkte canvas als PNG. Op een server draait dezelfde tekencode met een canvasbibliotheek voor Node.

## Veelvoorkomende problemen met canvas-verlopen

### Symptoom

- Verloop ziet er wazig uit op een telefoon
- In een vorm zie je maar één kleur
- Zichtbare strepen in een donker verloop
- `IndexSizeError` van addColorStop
- Conisch verloop begint op de verkeerde plek

### Oplossing

- Vermenigvuldig breedte en hoogte van het canvas met `devicePixelRatio` en schaal met `ctx.scale()` terug
- Maak het verloop met de coördinaten van de vorm, niet van het canvas
- Leg lichte ruis eroverheen, zie [kleurverloop banding](https://gradiently.design/nl/guide/gradient-banding)
- Houd offsets tussen 0 en 1
- Begin bij `-Math.PI / 2` om CSS te evenaren

> **Bredere kleur op geschikte schermen** Chrome en Safari accepteren `canvas.getContext('2d', { colorSpace: 'display-p3' })`, waardoor felle verlopen het bredere P3-bereik kunnen gebruiken. Browsers die dat niet ondersteunen vallen terug op sRGB.

Heb je verlopen nodig die meebewegen met echt licht in plaats van vlakke overgangen, dan bereikt een canvas zijn grenzen en neemt WebGL het over, zie [shader-verlopen](https://gradiently.design/nl/guide/shader-gradients). En als het canvas slechts een middel is voor een afbeelding, zoals een social kaart of poster, rendert Gradiently een Mark op elk formaat van 200 tot 8.000 px met de woorden al netjes gezet, zodat er geen tekencode te onderhouden valt.

## FAQ

### Hoe maak ik een kleurverloop op een HTML canvas?

Roep `ctx.createLinearGradient(x0, y0, x1, y1)` aan, voeg kleuren toe met `addColorStop(offset, kleur)`, zet `ctx.fillStyle` op het verloop en teken een vorm zoals `fillRect`.

### Wat is het verschil tussen createLinearGradient en CSS linear-gradient?

Canvas gebruikt een beginpunt en een eindpunt in pixels, CSS gebruikt een hoek en rekt het verloop uit over het element. Een kleine helper kan een CSS-hoek omzetten in canvaspunten.

### Kan ik oklch- of hsl-kleuren gebruiken in addColorStop?

Ja. addColorStop accepteert elke CSS-kleurtekst die de browser begrijpt, ook hex, rgb(), hsl() en in actuele browsers oklch().

### Waarom toont mijn canvas-verloop maar één kleur?

Het verloop ligt vast in canvascoördinaten, dus een vorm buiten het begin- en eindpunt krijgt alleen de dichtstbijzijnde eindkleur. Maak het verloop met de positie en grootte van de vorm.

### Hoe animeer ik een canvas-verloop?

Maak bij elk animatieframe een nieuw verloop met bijgewerkte stops of coördinaten en teken opnieuw. Stops van een verloop kunnen na toevoeging niet worden verplaatst of verwijderd.
