CSS und Web

WebGL-Farbverläufe mit Shadern, erklärt für Designer

Manche Farbverläufe im Web treiben, leuchten und schimmern auf eine Art, die kein Bild und keine CSS-Regel schafft. Das sind Shader. So funktionieren sie, in Worten, mit denen Designer arbeiten können.

GradientlyVerifiziertes Gradiently-Konto··6 Min. Lesezeit
Cover: Thistle Mosaic · GR·2BAQ·CR

Die Kurzfassung

  • Ein WebGL-Farbverlauf wird von einem Shader gezeichnet: einem kleinen Programm, das auf dem Grafikchip läuft und die Farbe jedes Pixels festlegt, oft viele Male pro Sekunde.
  • Weil ein Shader Farbe aus Mathematik berechnet, statt ein gespeichertes Bild zu lesen, kann er Bewegung, Rauschen, Körnung und Licht in jeder Größe hinzufügen, ohne dass die Datei wächst.
  • Shader-Farbverläufe kosten mehr Rechenleistung als CSS-Farbverläufe, also pausiert ein guter Shader außerhalb des sichtbaren Bereichs, respektiert reduzierte Bewegung und hat einen schlichten CSS-Fallback.
  • Nutze CSS für ruhende Übergänge und einfache Bewegung, und greif zum Shader, wenn Textur, Tiefe oder Bewegung der Kern des Designs sind.
Auf dieser Seite

Ein WebGL-Farbverlauf ist ein Farbverlauf, den dein Browser mit einem Shader malt: einem kurzen Programm, das auf dem Grafikchip (der GPU) läuft und für jedes Pixel auf dem Bildschirm eine Frage beantwortet: „Welche Farbe hast du gerade?“ Ein CSS-Farbverlauf ist ein festes Rezept aus Farben und Positionen. Ein Shader ist eine Formel, also kann er die Farbe biegen, körnen, leuchten lassen und bewegen, und das sechzigmal pro Sekunde, ohne dass ein Bild heruntergeladen wird.

Du musst keine Shader schreiben, um mit ihnen zu gestalten, aber zu wissen, was sie können und was nicht, hilft dir, Entwickler zu briefen, ein Tool zu beurteilen und zu entscheiden, wann ein schlichter CSS-Farbverlauf die bessere Wahl ist.

Was ein Shader ist, in einfachen Worten

WebGL ist der Weg des Browsers, mit der GPU zu sprechen, und jede WebGL-Zeichnung nutzt zwei Arten von Shadern. Der Vertex-Shader platziert Formen, bei einem bildschirmfüllenden Farbverlauf ist das nur ein Rechteck über dem Canvas. Der Fragment-Shader erledigt die spannende Arbeit: Er läuft einmal pro Pixel, erhält dessen Position und die aktuelle Zeit und gibt eine Farbe zurück.

Weil die GPU Tausende dieser winzigen Programme parallel ausführt, wird eine Formel, die in normalem Code langsam wäre, günstig genug, um jedes Frame neu zu zeichnen. Hier ist ein vollständiger Fragment-Shader für einen dreifarbigen Farbverlauf, dessen Grenze sich mit der Zeit sanft wiegt, mit einer Zeile Körnung obendrauf.

text
#version 300 es
precision highp float;

uniform vec2 u_resolution;   // canvas size in pixels
uniform float u_time;        // seconds since start
out vec4 outColor;

void main() {
  vec2 uv = gl_FragCoord.xy / u_resolution;   // 0 to 1 across the canvas

  vec3 night  = vec3(0.07, 0.04, 0.18);  // #120a2e
  vec3 violet = vec3(0.49, 0.23, 0.93);  // #7c3aed
  vec3 coral  = vec3(0.98, 0.45, 0.45);  // #fa7373

  // A slow wave bends the blend so the colours drift.
  float wave = sin(u_time * 0.3 + uv.x * 3.0) * 0.08;
  float t = clamp(uv.y + wave, 0.0, 1.0);

  vec3 color = mix(night, violet, smoothstep(0.0, 0.6, t));
  color = mix(color, coral, smoothstep(0.55, 1.0, t));

  // Fine grain: a different random value per pixel, per frame.
  float n = fract(sin(dot(gl_FragCoord.xy + u_time, vec2(12.9898, 78.233))) * 43758.5453);
  color += (n - 0.5) * 0.04;

  outColor = vec4(color, 1.0);
}
Ein WebGL2-Fragment-Shader in GLSL. smoothstep macht jeden Übergang weich, die Sinuswelle bewegt die Grenze, und die letzten Zeilen fügen Körnung hinzu, die zugleich Banding versteckt.
Die drei Farben im Shader. GLSL schreibt Farbe als 0 bis 1 pro Kanal, also wird #7c3aed zu 124, 58 und 237, jeweils geteilt durch 255.

Wie sich ein Shader-Farbverlauf von einem CSS-Farbverlauf unterscheidet

Ein CSS-Farbverlauf ist deklarativ: Du listest Farben und Positionen auf, und der Browser malt sie. Meistens ist das das richtige Werkzeug. Ein Shader ist prozedural: Du beschreibst, wie sich Farbe verhalten soll, und die Mathematik erzeugt sie. Dieser Unterschied zeigt sich darin, was beide können und was beide kosten.

AspektCSS-FarbverlaufShader-Farbverlauf
Definiert durchFarben, Stopps und eine RichtungEine Formel, die pro Pixel läuft
BewegungPosition, Größe oder animierte Custom PropertiesAlles, was sich mathematisch ausdrücken lässt, in jedem Frame
Textur und KörnungBraucht eine zusätzliche Ebene, etwa SVG-RauschenEingebaut, und sie kann sich bewegen
Laufende KostenSehr gering, sobald gemaltHält die GPU beschäftigt, solange er animiert
Funktioniert ohne JavaScriptJaNein: Ein Skript richtet den Canvas ein
Funktioniert in E-MailsTeilweise, je nach MailprogrammNein
Keiner ist grundsätzlich besser. Jeder gewinnt bei einer anderen Aufgabe.
Der CSS-Fallbacklinear-gradient(180deg, #120a2e 0%, #4c1d95 40%, #7c3aed 62%, #fa7373 100%)
Dieselbe Palette als ruhender CSS-Farbverlauf. Jeder Shader-Hintergrund sollte so einen Fallback mitbringen, sichtbar bevor der Shader startet und immer dann, wenn er nicht laufen kann.

Warum Shader-Farbverläufe lebendig wirken

Drei Techniken leisten den Großteil der Arbeit, und du wirst hören, wie Entwickler sie nennen. Noise ist weicher Zufall: Statt eines geraden Übergangs folgt die Farbe einer Landschaft aus sanften Hügeln, deshalb wirken Shader-Farbverläufe organisch statt geometrisch. Domain Warping speist das Rauschen in sich selbst zurück, sodass sich die Farbe faltet und wirbelt wie Tinte im Wasser. Zeit schiebt die ganze Landschaft weiter und macht aus einer ruhenden Fläche ein Treiben.

  • Körnung lässt sich pro Pixel und pro Frame erzeugen, also schimmert sie wie Film, statt stillzuliegen wie eine aufgelegte Textur. Siehe körnige Farbverläufe.
  • Licht lässt sich mit wenigen Zeilen vortäuschen: Ein Glanzlicht, das dem Rauschen folgt, wirkt wie Schimmer auf Seide oder Glas.
  • Auflösung gibt es gratis. Die Formel läuft in jeder Bildschirmgröße, also bleibt ein Shader-Farbverlauf mit demselben Code auf einem Handy und auf einem 4K-Monitor scharf.
  • Banding ist leichter zu besiegen, weil der Shader etwas Dithering hinzufügen kann, bevor die Farbe auf 8 Bit gerundet wird. Banding bei Farbverläufen erklärt, warum das zählt.

Nimm CSS, wenn

  • Der Farbverlauf ruht oder sich auf eine einfache Art bewegt
  • Er auf einer langen Seite hinter viel Text liegt
  • Er ohne Skripte oder in E-Mails funktionieren muss
  • Du ihn in einer Codezeile brauchst

Nimm einen Shader, wenn

  • Bewegung oder Textur der Kern des Designs sind
  • Es um einen Hero-Bereich geht, nicht um jeden Abschnitt
  • Du Körnung, Glanz oder Fluss willst, den CSS nicht vortäuschen kann
  • Du einen CSS-Fallback und eine Pause liefern kannst

Was ein bewegter WebGL-Hintergrund kostet

Ein animierender Shader lässt die GPU arbeiten, solange er auf dem Bildschirm ist. Auf einem Desktop merkt man das kaum. Auf einem älteren Handy kann es warme Hände, einen leeren Akku und eine Seite bedeuten, die weniger flüssig scrollt. Die Kosten wachsen mit der Zahl der Pixel und der Komplexität der Formel, also ist ein bildschirmfüllender Shader auf einem hochauflösenden Display der schwerste Fall. Machen Farbverläufe eine Website langsam zeigt, wie du das misst.

  1. 1

    Zeig zuerst den CSS-Fallback

    Mal den ruhenden Farbverlauf sofort und blende den Canvas ein, sobald der Shader sein erstes Frame gezeichnet hat. Niemand sollte eine leere Box sehen.

  2. 2

    Prüf, ob WebGL verfügbar ist

    Manche Browser, Geräte und Datenschutzeinstellungen schalten es ab. Lässt sich der Kontext nicht erzeugen, behalte den Fallback.

  3. 3

    Respektiere reduzierte Bewegung

    Bittet die Person um weniger Bewegung, zeichne ein Frame und stoppe. Reduzierte Bewegung erklärt die Einstellung.

  4. 4

    Pausiere, wenn er nicht sichtbar ist

    Stoppe die Animationsschleife, wenn der Canvas aus dem Blick scrollt oder der Tab im Hintergrund ist.

  5. 5

    Render in sinnvoller Auflösung

    Weiche Farbverläufe brauchen selten jedes Gerätepixel. In halber Auflösung zu zeichnen und den Browser hochskalieren zu lassen, kann viel Arbeit sparen, bei einer Unschärfe, die du nicht unterscheiden kannst.

js
const canvas = document.querySelector('#hero-canvas')
const gl = canvas.getContext('webgl2')
const still = matchMedia('(prefers-reduced-motion: reduce)').matches
let visible = true

if (!gl) {
  canvas.remove() // the CSS gradient behind it stays
} else {
  new IntersectionObserver(([entry]) => {
    visible = entry.isIntersecting
  }).observe(canvas)

  const frame = (ms) => {
    if (visible && !document.hidden) draw(gl, ms / 1000) // your draw call
    if (!still) requestAnimationFrame(frame)
  }
  requestAnimationFrame(frame)
}
Die Leitplanken in wenigen Zeilen: ein Fallback, wenn WebGL fehlt, nur ein Frame bei reduzierter Bewegung und kein Zeichnen außerhalb des sichtbaren Bereichs oder in einem verborgenen Tab.

Zum Nachschlagen dokumentiert die WebGL-API bei MDN jeden hier genutzten Aufruf, und caniuse verfolgt die Unterstützung von WebGL2 in den Browsern.

Einen Shader-Farbverlauf gestalten: was ins Briefing gehört

Du kannst einen Shader lenken, ohne GLSL zu lesen. Brief ihn wie ein Material, nicht wie ein Farbmuster. Nenn die Grundfarbe und die drei bis fünf Farben, die darauf leben, in Hex. Beschreib die Struktur: weiche Pfützen, lange Bänder, gefaltete Seide. Gib das Tempo in Sekunden pro Zyklus an statt „langsam“, denn langsam heißt für jeden etwas anderes. Sag, wie viel Körnung und ob sie sich bewegt. Und sag zuletzt, wo Text sitzen wird, damit der unruhigste Teil der Fläche davon fernbleibt.

Wie Gradiently Marks mit Shadern zeichnet

Die Marks von Gradiently sind Shader-Farbverläufe. Jeder Mark ist ein Rezept aus Farben, bis zu drei gestapelten Materialien, Licht, Körnung und Bewegung, und das Studio zeichnet ihn live mit WebGL2 hinter alles, was du gestaltest. Weil er berechnet statt gespeichert wird, rendert derselbe Mark in jeder Plattformgröße scharf und bewegt sich, wenn du ein Loop-Video exportierst. Der Renderer weiß außerdem, wo deine Worte stehen, und kann den ruhigsten Teil der Fläche dahinter schieben. Was ist ein Mark erklärt das Rezept vollständig.

Thistle Mosaic

GR·2BAQ·CR

Thistle Mosaic

Diesen Mark ansehen
Ein Mark ist ein Shader-Rezept mit einem Namen, einem Code und einem Besitzer. Seine Seite zeigt ihn live gerendert.

Häufige Fragen

Was ist ein WebGL-Farbverlauf?

Ein Farbverlauf, den ein Shader zeichnet, ein kleines Programm auf dem Grafikchip, das die Farbe jedes Pixels berechnet. Weil er eine Formel ist, kann er sich bewegen, Körnung hinzufügen und in jeder Größe rendern.

Ist ein Shader-Farbverlauf schlecht für die Performance?

Ein ruhender oder pausierter Shader kostet wenig, ein animierender hält die GPU beschäftigt, solange er sichtbar ist. Pausiere ihn außerhalb des Blickfelds, zeichne in sinnvoller Auflösung und behalte einen CSS-Fallback.

Kann ich einen Shader-Farbverlauf ohne Programmieren erstellen?

Ja. Mehrere Design-Tools erzeugen Shader-Hintergründe über Regler, und die Forge von Gradiently baut Marks, also Shader-Farbverläufe, aus einem Satz oder Regler für Regler.

Respektieren Shader-Farbverläufe die Einstellung für reduzierte Bewegung?

Nur, wenn sie dafür gebaut sind. Prüf die Media Query prefers-reduced-motion in JavaScript und zeichne ein einzelnes Standbild, wenn sie gesetzt ist.

Was ist GLSL?

GLSL ist die Shader-Sprache, die WebGL nutzt. Darin geschriebene Fragment-Shader legen die Farbe jedes Pixels fest, und der Browser kompiliert sie für den Grafikchip.

Diesen Artikel teilen

Geschrieben von GradientlyVerifiziertes Gradiently-Konto

Das Team hinter Gradiently, einem Designtool rund um Marks: lebendige Farbverläufe, durch die alles, was du gestaltest, nach dir aussieht.

Unser Profil ansehen