# Shaders de gradiente em WebGL, explicados para designers

[Canonical HTML page](https://gradiently.design/pt-br/guide/shader-gradients)

Alguns gradientes na web derivam, brilham e cintilam de um jeito que nenhuma imagem ou regra CSS consegue. São shaders. Veja como funcionam, em palavras que um designer pode usar.

## The short version

- Um gradiente WebGL é desenhado por um shader: um pequeno programa que roda no chip gráfico e decide a cor de cada pixel, muitas vezes várias vezes por segundo.
- Como o shader calcula a cor com matemática em vez de ler uma imagem armazenada, ele pode acrescentar movimento, ruído, grão e luz em qualquer tamanho sem que o arquivo cresça.
- Gradientes shader custam mais para rodar do que gradientes CSS, então um bom shader pausa quando está fora da tela, respeita o movimento reduzido e tem uma alternativa simples em CSS.
- Use CSS para misturas paradas e movimentos simples, e recorra a um shader quando a textura, a profundidade ou o movimento forem o centro do design.

Um **gradiente WebGL** é um gradiente que o seu navegador pinta com um shader: um programa curto que roda no chip gráfico (a GPU) e responde a uma pergunta para cada pixel da tela, “de que cor você é agora?”. Um gradiente CSS é uma receita fixa de cores e posições. Um shader é uma fórmula, então pode curvar, granular, iluminar e mover a cor, e fazer tudo de novo sessenta vezes por segundo, sem baixar nenhuma imagem.

Você não precisa escrever shaders para criar com eles, mas saber o que eles fazem e o que não fazem ajuda a orientar um desenvolvedor, avaliar uma ferramenta e decidir quando um simples [gradiente CSS](https://gradiently.design/pt-br/guide/css-linear-gradient) é a melhor escolha.

## O que é um shader, em palavras simples

O WebGL é o jeito de o navegador conversar com a GPU, e todo desenho em WebGL usa dois tipos de shader. O **vertex shader** posiciona as formas; num gradiente de tela cheia, é só um retângulo cobrindo o canvas. O **fragment shader** faz o trabalho interessante: roda uma vez por pixel, recebe a posição desse pixel e o tempo atual e devolve uma cor.

Como a GPU roda milhares desses programinhas em paralelo, uma fórmula que seria lenta num código comum fica barata o bastante para ser redesenhada a cada quadro. Aqui está um fragment shader completo para um gradiente de três cores cuja fronteira balança suavemente com o tempo, com uma linha de grão por cima.

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

Um fragment shader WebGL2 em GLSL. `smoothstep` suaviza cada transição, a onda senoidal move a fronteira e as últimas linhas acrescentam um grão que também esconde as faixas.

- Fundo noturno: #120a2e
- Violeta: #7c3aed
- Coral: #fa7373

As três cores do shader. O GLSL escreve a cor de 0 a 1 por canal, então #7c3aed vira 124, 58 e 237 divididos por 255.

## Como um gradiente shader difere de um gradiente CSS

Um gradiente CSS é declarativo: você lista cores e posições, e o navegador as pinta. É a ferramenta certa na maior parte do tempo. Um shader é procedural: você descreve como a cor deve se comportar, e a matemática a produz. Essa diferença aparece no que cada um consegue fazer e no quanto cada um custa.

| Aspecto | Gradiente CSS | Gradiente shader |
| --- | --- | --- |
| Definido por | Cores, paradas e uma direção | Uma fórmula executada por pixel |
| Movimento | Posição ou tamanho em movimento, ou propriedades personalizadas animadas | Tudo o que você conseguir expressar em matemática, a cada quadro |
| Textura e grão | Precisa de uma camada extra, como ruído em SVG | Embutidos, e podem se mover |
| Custo para rodar | Muito baixo depois de pintado | Mantém a GPU ocupada enquanto anima |
| Funciona sem JavaScript | Sim | Não: um script prepara o canvas |
| Funciona em e-mail | Em parte, dependendo do cliente | Não |

Nenhum é melhor em geral. Cada um vence num trabalho diferente.

A alternativa em CSS: `linear-gradient(180deg, #120a2e 0%, #4c1d95 40%, #7c3aed 62%, #fa7373 100%)`

A mesma paleta como um gradiente CSS parado. Todo fundo shader deve vir com uma alternativa assim, mostrada antes de o shader começar e sempre que ele não puder rodar.

## Por que os gradientes shader parecem vivos

Três técnicas fazem a maior parte do trabalho, e você vai ouvir os desenvolvedores falarem delas. O **ruído** é uma aleatoriedade suave: em vez de uma mistura reta, a cor segue uma paisagem de colinas suaves, e é por isso que os gradientes shader parecem orgânicos, e não geométricos. O **domain warping** realimenta o ruído nele mesmo, e a cor se dobra e rodopia 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 pixel e por quadro, então cintila como filme em vez de ficar parado como uma textura colocada por cima. Veja [gradientes com grão](https://gradiently.design/pt-br/guide/grainy-gradients).
- **A luz** pode ser simulada com poucas linhas: um reflexo que acompanha o ruído parece o brilho da seda ou do vidro.
- **A resolução** sai de graça. A fórmula roda no tamanho que a tela tiver, então um gradiente shader fica nítido num celular e num monitor 4K com o mesmo código.
- **As faixas** são mais fáceis de vencer, porque o shader pode acrescentar um pouco de dithering antes de a cor ser arredondada para 8 bits. O guia de [banding em gradientes](https://gradiently.design/pt-br/guide/gradient-banding) explica por que isso importa.

### Use CSS quando

- O gradiente é parado, ou se move de um jeito simples
- Ele fica atrás de muito texto numa página longa
- Precisa funcionar sem scripts, ou em e-mail
- Você precisa dele numa linha de código

### Use um shader quando

- O movimento ou a textura são o centro do design
- É uma área principal, não todas as seções
- Você quer grão, brilho ou fluxo que o CSS não simula
- Você pode oferecer uma alternativa em CSS e uma pausa

## O custo de um fundo WebGL em movimento

Um shader que anima mantém a GPU trabalhando enquanto está na tela. Num computador de mesa, mal se nota. Num celular mais antigo, pode significar mãos quentes, bateria acabando e uma página que rola com menos suavidade. O custo cresce com o número de pixels e a complexidade da fórmula, então um shader em tela cheia numa tela de alta densidade é o caso mais pesado. O guia [gradientes deixam um site lento?](https://gradiently.design/pt-br/guide/css-gradient-performance) mostra como medir.

1. **Mostre primeiro a alternativa em CSS** Pinte o gradiente parado na hora e faça o canvas aparecer com um esmaecimento quando o shader tiver desenhado o primeiro quadro. Ninguém deve ver uma caixa vazia.
2. **Verifique se o WebGL está disponível** Alguns navegadores, aparelhos e configurações de privacidade o desativam. Se o contexto não puder ser criado, mantenha a alternativa.
3. **Respeite o movimento reduzido** Se a pessoa pede menos movimento, desenhe um quadro e pare. O guia de [movimento reduzido](https://gradiently.design/pt-br/guide/reduced-motion) explica a configuração.
4. **Pause quando não puder ser visto** Pare o loop de animação quando o canvas sair da área visível ou a aba estiver oculta.
5. **Renderize numa resolução sensata** Gradientes suaves raramente precisam de todos os pixels do aparelho. Desenhar na metade da resolução e deixar o navegador ampliar pode reduzir muito o trabalho, com um desfoque impossível de notar.

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

As proteções em poucas linhas: uma alternativa quando falta WebGL, um único quadro para o movimento reduzido e nada de desenhar fora da tela ou com a aba oculta.

Para referência, a [API WebGL na MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API) documenta cada chamada usada aqui, e o [caniuse](https://caniuse.com/webgl2) acompanha o suporte ao WebGL2 nos navegadores.

## Como criar um gradiente shader: o que colocar no briefing

Você pode dirigir um shader sem ler GLSL. Faça o briefing como faria de um material, e não de uma amostra de cor. Informe a cor de fundo e as três a cinco cores que vivem sobre ela, em hex. Descreva a estrutura: poças suaves, faixas longas, seda dobrada. Diga a velocidade em segundos por ciclo em vez de “devagar”, porque devagar significa coisas diferentes para pessoas diferentes. Diga quanto grão e se ele se move. Por fim, diga onde o texto vai ficar, para que a parte mais agitada do campo fique longe dele.

> **Avalie parado primeiro** Pause o shader num quadro aleatório e olhe para ele como uma imagem estática. Se um quadro parado não fica bonito, o movimento não vai salvá-lo. O movimento deve somar a um design que já funciona.

## Como o Gradiently desenha os Marks com shaders

Os Marks do Gradiently são gradientes shader. Cada Mark é uma receita de cores, até três materiais sobrepostos, luz, grão e movimento, e o Studio o desenha ao vivo com WebGL2 atrás de tudo o que você cria. Como é calculado, e não armazenado, o mesmo Mark é renderizado com nitidez em qualquer tamanho de plataforma e se move quando você exporta um vídeo em loop. O renderizador também sabe onde estão as suas palavras, então consegue mover a parte mais calma do campo para trás delas. O guia [o que é um Mark](https://gradiently.design/pt-br/guide/what-is-a-mark) explica a receita por completo.

Um Mark é uma receita de shader com nome, código e um único dono. A página dele o mostra sendo renderizado ao vivo.

## FAQ

### O que é um gradiente WebGL?

É um gradiente desenhado por um shader, um pequeno programa que roda no chip gráfico e calcula a cor de cada pixel. Como é uma fórmula, ele pode se mover, ganhar grão e ser renderizado em qualquer tamanho.

### Um gradiente shader prejudica o desempenho?

Um shader parado ou pausado custa pouco, mas um que anima mantém a GPU ocupada enquanto está na tela. Pause-o quando estiver fora da área visível, desenhe numa resolução sensata e mantenha uma alternativa em CSS.

### Dá para fazer um gradiente shader sem programar?

Sim. Várias ferramentas de design geram fundos shader a partir de controles, e a Forge do Gradiently cria Marks, que são gradientes shader, a partir de uma frase ou controle por controle.

### Os gradientes shader respeitam a configuração de movimento reduzido?

Só se forem feitos para isso. Verifique a media query prefers-reduced-motion em JavaScript e desenhe um único quadro parado quando ela estiver ativa.

### O que é GLSL?

GLSL é a linguagem de shaders que o WebGL usa. Os fragment shaders escritos nela decidem a cor de cada pixel, e o navegador os compila para o chip gráfico.
