CSS et web

Les shaders de dégradé WebGL, expliqués aux designers

Certains dégradés du web dérivent, rayonnent et scintillent comme aucune image ni aucune règle CSS ne le peut. Ce sont des shaders. Voici comment ils fonctionnent, avec des mots qu’un designer peut utiliser.

GradientlyCompte Gradiently vérifié··8 min de lecture
Couverture : Thistle Mosaic · GR·2BAQ·CR

L’essentiel en bref

  • Un dégradé WebGL est dessiné par un shader : un petit programme qui tourne sur la puce graphique et décide de la couleur de chaque pixel, souvent plusieurs fois par seconde.
  • Comme un shader calcule la couleur à partir de mathématiques au lieu de lire une image stockée, il peut ajouter mouvement, bruit, grain et lumière à n’importe quelle taille sans alourdir le fichier.
  • Les dégradés en shader coûtent plus cher à faire tourner que les dégradés CSS : un bon shader se met en pause hors de l’écran, respecte la réduction des animations et prévoit une solution de repli en CSS simple.
  • Utilisez le CSS pour les fondus statiques et les mouvements simples, et passez au shader quand la texture, la profondeur ou le mouvement sont le cœur de la création.
Sur cette page

Un dégradé WebGL est un dégradé que votre navigateur peint avec un shader : un court programme qui tourne sur la puce graphique (le GPU) et répond à une seule question pour chaque pixel de l’écran : « de quelle couleur es-tu en ce moment ? » Un dégradé CSS est une recette figée de couleurs et de positions. Un shader est une formule : il peut courber la couleur, lui donner du grain, la faire rayonner et bouger, et recommencer soixante fois par seconde, sans télécharger la moindre image.

Pas besoin d’écrire des shaders pour concevoir avec eux, mais savoir ce qu’ils peuvent et ne peuvent pas faire aide à briefer un développeur, à juger un outil et à décider quand un simple dégradé CSS est le meilleur choix.

Ce qu’est un shader, en termes simples

WebGL est la façon dont le navigateur parle au GPU, et chaque dessin WebGL utilise deux types de shader. Le vertex shader place les formes ; pour un dégradé plein écran, il s’agit d’un simple rectangle couvrant le canevas. Le fragment shader fait le travail intéressant : il s’exécute une fois par pixel, reçoit la position de ce pixel et le temps écoulé, et renvoie une couleur.

Comme le GPU exécute des milliers de ces minuscules programmes en parallèle, une formule qui serait lente en code ordinaire devient assez légère pour être redessinée à chaque image. Voici un fragment shader complet pour un dégradé à trois couleurs dont la limite ondule doucement dans le temps, avec une ligne de grain par-dessus.

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);
}
Un fragment shader WebGL2 en GLSL. smoothstep adoucit chaque transition, la sinusoïde déplace la limite, et les dernières lignes ajoutent un grain qui masque aussi le banding.
Les trois couleurs du shader. GLSL écrit la couleur de 0 à 1 par couche : #7c3aed devient donc 124, 58 et 237 divisés par 255.

En quoi un dégradé en shader diffère d’un dégradé CSS

Un dégradé CSS est déclaratif : vous listez des couleurs et des positions, et le navigateur les peint. C’est le bon outil la plupart du temps. Un shader est procédural : vous décrivez le comportement de la couleur, et les mathématiques la produisent. Cette différence se voit dans ce que chacun sait faire et dans ce qu’il coûte.

AspectDégradé CSSDégradé en shader
Défini parDes couleurs, des arrêts et une directionUne formule exécutée par pixel
MouvementPosition, taille ou propriétés personnalisées animéesTout ce qui s’exprime en mathématiques, à chaque image
Texture et grainDemande un calque en plus, comme un bruit SVGIntégrés, et ils peuvent bouger
Coût d’exécutionTrès faible une fois peintOccupe le GPU tant qu’il s’anime
Fonctionne sans JavaScriptOuiNon : un script prépare le canevas
Fonctionne dans un emailEn partie, selon le clientNon
Aucun n’est meilleur en général. Chacun gagne dans un rôle différent.
La solution de repli CSSlinear-gradient(180deg, #120a2e 0%, #4c1d95 40%, #7c3aed 62%, #fa7373 100%)
La même palette en dégradé CSS fixe. Tout fond en shader devrait livrer une solution de repli comme celle-ci, affichée avant le démarrage du shader et chaque fois qu’il ne peut pas tourner.

Pourquoi les dégradés en shader paraissent vivants

Trois techniques font l’essentiel du travail, et vous entendrez les développeurs les nommer. Le bruit est un aléatoire doux : au lieu d’un fondu rectiligne, la couleur suit un paysage de collines douces, d’où l’aspect organique plutôt que géométrique des dégradés en shader. Le domain warping réinjecte le bruit dans lui-même, si bien que la couleur se plie et tourbillonne comme de l’encre dans l’eau. Le temps fait glisser tout le paysage, ce qui transforme un champ fixe en dérive.

  • Le grain peut être généré par pixel et par image : il scintille comme de la pellicule au lieu de rester figé comme une texture posée par-dessus. Voyez les dégradés granuleux.
  • La lumière s’imite en quelques lignes : un reflet qui suit le bruit se lit comme le lustre de la soie ou du verre.
  • La résolution est gratuite. La formule s’exécute à la taille de l’écran, quelle qu’elle soit : un dégradé en shader reste net sur un téléphone comme sur un écran 4K avec le même code.
  • Le banding est plus facile à vaincre, car le shader peut ajouter un léger tramage avant que la couleur soit arrondie sur 8 bits. Le banding des dégradés explique pourquoi c’est important.

Choisissez le CSS quand

  • Le dégradé est fixe, ou bouge d’une seule façon simple
  • Il se trouve derrière beaucoup de texte sur une longue page
  • Il doit fonctionner sans scripts, ou dans un email
  • Vous en avez besoin en une ligne de code

Choisissez un shader quand

  • Le mouvement ou la texture sont le cœur de la création
  • Il s’agit d’une zone phare, pas de chaque section
  • Vous voulez un grain, un lustre ou un flux que le CSS ne sait pas imiter
  • Vous pouvez prévoir une solution de repli CSS et une pause

Le coût d’un fond WebGL animé

Un shader animé fait travailler le GPU tant qu’il est à l’écran. Sur un ordinateur de bureau, cela se remarque à peine. Sur un téléphone ancien, cela peut vouloir dire des mains chaudes, une batterie qui fond et une page qui défile moins bien. Le coût augmente avec le nombre de pixels et la complexité de la formule : un shader plein écran sur un écran haute densité est le cas le plus lourd. Les dégradés ralentissent-ils un site explique comment le mesurer.

  1. 1

    Affichez d’abord la solution de repli CSS

    Peignez immédiatement le dégradé fixe, puis faites apparaître le canevas en fondu une fois que le shader a dessiné sa première image. Personne ne doit voir une boîte vide.

  2. 2

    Vérifiez que WebGL est disponible

    Certains navigateurs, appareils et réglages de confidentialité le désactivent. Si le contexte ne peut pas être créé, gardez la solution de repli.

  3. 3

    Respectez la réduction des animations

    Si le visiteur demande moins de mouvement, dessinez une seule image et arrêtez-vous. La réduction des animations explique ce réglage.

  4. 4

    Mettez en pause quand il n’est pas visible

    Arrêtez la boucle d’animation quand le canevas sort de l’écran ou que l’onglet est masqué.

  5. 5

    Dessinez à une résolution raisonnable

    Les dégradés doux ont rarement besoin de chaque pixel de l’appareil. Dessiner à mi-résolution et laisser le navigateur agrandir peut réduire nettement le travail, pour un flou indiscernable.

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)
}
Les garde-fous en quelques lignes : une solution de repli si WebGL manque, une seule image en cas de réduction des animations, et aucun dessin hors de l’écran ou dans un onglet masqué.

Pour référence, l’API WebGL sur MDN documente chaque appel utilisé ici, et caniuse suit la prise en charge de WebGL2 selon les navigateurs.

Concevoir un dégradé en shader : que mettre dans le brief

Vous pouvez diriger un shader sans lire le GLSL. Briefez-le comme une matière, pas comme un nuancier. Donnez la couleur de fond et les trois à cinq couleurs qui y vivent, en hexadécimal. Décrivez la structure : des flaques douces, de longues bandes, de la soie pliée. Indiquez la vitesse en secondes par cycle plutôt que « lent », car lent ne veut pas dire la même chose pour tout le monde. Précisez la quantité de grain, et s’il bouge. Enfin, dites où se placera le texte, pour que la partie la plus chargée du champ reste à l’écart.

Comment Gradiently dessine les Marks avec des shaders

Les Marks de Gradiently sont des dégradés en shader. Chaque Mark est une recette de couleurs, jusqu’à trois matières empilées, de lumière, de grain et de mouvement, et le Studio la dessine en direct avec WebGL2 derrière tout ce que vous concevez. Comme il est calculé plutôt que stocké, un même Mark s’affiche net à n’importe quelle taille de plateforme et bouge quand vous exportez une vidéo en boucle. Le moteur de rendu sait aussi où sont vos mots, et peut donc déplacer la partie la plus calme du champ derrière eux. Qu’est-ce qu’un Mark explique la recette en détail.

Thistle Mosaic

GR·2BAQ·CR

Thistle Mosaic

Voir ce Mark
Un Mark est une recette de shader avec un nom, un code et un seul propriétaire. Sa page le montre en rendu direct.

Les questions qu’on nous pose

Qu’est-ce qu’un dégradé WebGL ?

C’est un dégradé dessiné par un shader, un petit programme qui tourne sur la puce graphique et calcule la couleur de chaque pixel. Comme c’est une formule, il peut bouger, ajouter du grain et s’afficher à n’importe quelle taille.

Un dégradé en shader nuit-il aux performances ?

Un shader fixe ou en pause coûte peu, mais un shader animé occupe le GPU tant qu’il est à l’écran. Mettez-le en pause hors de l’écran, dessinez à une résolution raisonnable et gardez une solution de repli CSS.

Peut-on créer un dégradé en shader sans coder ?

Oui. Plusieurs outils de design génèrent des fonds en shader à partir de réglages, et la Forge de Gradiently construit des Marks, qui sont des dégradés en shader, à partir d’une phrase ou réglage par réglage.

Les dégradés en shader respectent-ils la réduction des animations ?

Seulement s’ils sont conçus pour. Vérifiez la media query prefers-reduced-motion en JavaScript et dessinez une seule image fixe quand elle est activée.

Qu’est-ce que le GLSL ?

Le GLSL est le langage de shading qu’utilise WebGL. Les fragment shaders écrits dans ce langage décident de la couleur de chaque pixel, et le navigateur les compile pour la puce graphique.

Partager ce guide

Écrit par GradientlyCompte Gradiently vérifié

L’équipe derrière Gradiently, un outil de création construit autour des Marks : des dégradés vivants qui donnent à tout ce que vous créez votre propre signature.

Voir notre profil
Tous les guides : CSS et web