A versão curta
- Um gradiente WebGL é desenhado por um shader: um pequeno programa que corre no chip gráfico e decide a cor de cada píxel, muitas vezes várias vezes por segundo.
- Como um shader calcula a cor com matemática em vez de ler uma imagem guardada, pode juntar movimento, ruído, grão e luz em qualquer tamanho sem o ficheiro crescer.
- Os gradientes com shaders custam mais a correr do que os gradientes CSS, por isso um bom shader pausa quando está fora do ecrã, respeita a redução de movimento e tem uma alternativa em CSS simples.
- Usa CSS para transições paradas e movimento simples, e recorre a um shader quando a textura, a profundidade ou o movimento são o objetivo do design.
Nesta página
Um gradiente WebGL é um gradiente que o teu browser pinta com um shader: um programa curto que corre no chip gráfico (a GPU) e responde a uma pergunta para cada píxel do ecrã: “que cor tens agora?” Um gradiente CSS é uma receita fixa de cores e posições. Um shader é uma fórmula, por isso pode dobrar, granular, iluminar e mover a cor, e voltar a fazê-lo sessenta vezes por segundo, sem descarregar nenhuma imagem.
Não precisas de escrever shaders para desenhar com eles, mas saber o que conseguem e não conseguem fazer ajuda-te a preparar um briefing para um programador, a avaliar uma ferramenta e a decidir quando um simples gradiente CSS é a melhor escolha.
O que é um shader, em palavras simples
O WebGL é a forma de o browser falar com a GPU, e cada desenho em WebGL usa dois tipos de shader. O vertex shader posiciona as formas; num gradiente de ecrã inteiro, é só um retângulo a cobrir o canvas. O fragment shader faz o trabalho interessante: corre uma vez por píxel, recebe a posição desse píxel e o tempo atual, e devolve uma cor.
Como a GPU corre milhares destes pequenos programas em paralelo, uma fórmula que seria lenta em código comum fica barata o suficiente para ser redesenhada a cada fotograma. Eis um fragment shader completo para um gradiente de três cores cuja fronteira ondula suavemente ao longo do tempo, com uma linha de grão por cima.
#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);
}smoothstep suaviza cada transição, a onda sinusoidal move a fronteira e as últimas linhas juntam grão, que também disfarça as bandas.Em que difere um gradiente com shader de um gradiente CSS
Um gradiente CSS é declarativo: listas cores e posições e o browser pinta-as. É a ferramenta certa na maior parte das vezes. Um shader é procedimental: descreves como a cor se deve comportar e a matemática produ-la. Essa diferença nota-se no que cada um consegue fazer e no que cada um custa.
| Aspeto | Gradiente CSS | Gradiente com shader |
|---|---|---|
| Definido por | Cores, paragens e uma direção | Uma fórmula corrida por píxel |
| Movimento | Mover posição, tamanho ou propriedades personalizadas animadas | Tudo o que consigas exprimir em matemática, a cada fotograma |
| Textura e grão | Precisa de uma camada extra, como ruído SVG | Incluídos, e podem mover-se |
| Custo de execução | Muito baixo depois de pintado | Mantém a GPU ocupada enquanto anima |
| Funciona sem JavaScript | Sim | Não: é um script que prepara o canvas |
| Funciona em email | Em parte, consoante o cliente | Não |
linear-gradient(180deg, #120a2e 0%, #4c1d95 40%, #7c3aed 62%, #fa7373 100%)Porque é que os gradientes com shaders parecem vivos
Três técnicas fazem quase todo o trabalho, e vais ouvir os programadores referi-las. O ruído é aleatoriedade suave: em vez de uma transição reta, a cor segue uma paisagem de colinas suaves, e é por isso que os gradientes com shaders parecem orgânicos e não geométricos. O domain warping volta a alimentar o ruído com ele próprio, para a cor se dobrar e rodopiar como tinta na água. O tempo desliza a paisagem inteira, o que transforma um campo parado numa deriva.
- O grão pode ser gerado por píxel e por fotograma, por isso cintila como película em vez de ficar parado como uma textura posta por cima. Vê os gradientes com grão.
- A luz pode ser simulada com poucas linhas: um reflexo que segue o ruído lê-se como brilho em seda ou vidro.
- A resolução é gratuita. A fórmula corre no tamanho que o ecrã tiver, por isso um gradiente com shader mantém-se nítido num telemóvel e num monitor 4K com o mesmo código.
- As bandas são mais fáceis de vencer, porque o shader pode juntar um pouco de dithering antes de a cor ser arredondada a 8 bits. As bandas em gradientes explicam porque é que isso conta.
Usa CSS quando
- O gradiente está parado, ou move-se de uma forma simples
- Fica por trás de muito texto numa página longa
- Tem de funcionar sem scripts, ou em email
- Precisas dele numa linha de código
Usa um shader quando
- O movimento ou a textura são o objetivo do design
- É uma zona de destaque, não todas as secções
- Queres grão, brilho ou fluxo que o CSS não consegue imitar
- Consegues dar uma alternativa em CSS e uma pausa
O custo de um fundo WebGL em movimento
Um shader animado mantém a GPU a trabalhar enquanto estiver no ecrã. Num computador de secretária, quase não se nota. Num telemóvel mais antigo, pode significar mãos quentes, bateria a descer e uma página que desliza com menos fluidez. O custo cresce com o número de píxeis e com a complexidade da fórmula, por isso um shader de ecrã inteiro num ecrã de alta densidade é o caso mais pesado. O guia os gradientes abrandam um site? explica como medir.
- 1
Mostra primeiro a alternativa em CSS
Pinta o gradiente parado de imediato e depois faz aparecer o canvas quando o shader tiver desenhado o primeiro fotograma. Ninguém deve ver uma caixa vazia.
- 2
Verifica se o WebGL está disponível
Alguns browsers, dispositivos e definições de privacidade desativam-no. Se o contexto não puder ser criado, mantém a alternativa.
- 3
Respeita a redução de movimento
Se o visitante pedir menos movimento, desenha um fotograma e para. A redução de movimento explica a definição.
- 4
Pausa quando não se vê
Para o ciclo de animação quando o canvas sai do ecrã ou o separador fica oculto.
- 5
Renderiza numa resolução sensata
Os gradientes suaves raramente precisam de todos os píxeis do dispositivo. Desenhar a meia resolução e deixar o browser ampliar pode reduzir muito o trabalho, com uma desfocagem que não se distingue.
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)
}Como referência, a API WebGL no MDN documenta todas as chamadas usadas aqui, e o caniuse acompanha o suporte do WebGL2 nos vários browsers.
Desenhar um gradiente com shader: o que pôr no briefing
Podes dirigir um shader sem ler GLSL. Faz o briefing como farias o de uma matéria, não o de uma amostra de cor. Indica a cor de fundo e as três a cinco cores que vivem sobre ela, em hex. Descreve a estrutura: poças suaves, faixas longas, seda dobrada. Indica a velocidade em segundos por ciclo em vez de “lento”, porque lento significa coisas diferentes para pessoas diferentes. Diz quanto grão queres e se se move. Por fim, diz onde vai ficar o texto, para a parte mais agitada do campo se manter longe dele.
Como a Gradiently desenha os Marks com shaders
Os Marks da Gradiently são gradientes com shaders. Cada Mark é uma receita de cores, até três matérias sobrepostas, luz, grão e movimento, e o Studio desenha-o ao vivo com WebGL2 por trás de tudo o que desenhas. Como é calculado e não guardado, o mesmo Mark é renderizado com nitidez em qualquer tamanho de plataforma e move-se quando exportas um vídeo em loop. O renderizador também sabe onde estão as tuas palavras, por isso consegue deslocar a parte mais calma do campo para trás delas. O guia o que é um Mark explica a receita por inteiro.

GR·2BAQ·CR
Thistle Mosaic
Ver este MarkPerguntas frequentes
O que é um gradiente WebGL?
É um gradiente desenhado por um shader, um pequeno programa que corre no chip gráfico e calcula a cor de cada píxel. Como é uma fórmula, pode mover-se, juntar grão e ser renderizado em qualquer tamanho.
Um gradiente com shader prejudica o desempenho?
Um shader parado ou em pausa custa pouco, mas um animado mantém a GPU ocupada enquanto está no ecrã. Pausa-o quando está fora de vista, desenha numa resolução sensata e mantém uma alternativa em CSS.
Posso fazer um gradiente com shader sem programar?
Sim. Várias ferramentas de design geram fundos com shaders a partir de controlos, e a Forge da Gradiently constrói Marks, que são gradientes com shaders, a partir de uma frase ou controlo a controlo.
Os gradientes com shaders respeitam as definições de redução de movimento?
Só se forem construídos para isso. Verifica a media query prefers-reduced-motion em JavaScript e desenha um único fotograma parado quando estiver ativa.
O que é o GLSL?
O GLSL é a linguagem de shading que o WebGL usa. Os fragment shaders escritos nela decidem a cor de cada píxel, e o browser compila-os para o chip gráfico.
Escrito pela Gradiently
A equipa por trás da Gradiently, uma ferramenta de design construída em torno dos Marks: gradientes vivos que fazem tudo o que crias parecer teu.
Ver o nosso perfil


