# Fundos com gradiente animado em CSS, como deve ser

[Canonical HTML page](https://gradiently.design/pt-pt/guide/css-animated-gradient)

Os gradientes não se podem animar diretamente, mas tudo à volta deles pode. Quatro técnicas, o que cada uma custa ao navegador e como manter o movimento calmo e opcional.

## The short version

- Os navegadores não conseguem interpolar entre dois valores de gradiente, por isso um gradiente animado em CSS move, esbate ou transforma o gradiente em vez de o animar diretamente.
- A técnica clássica faz o fundo maior do que o elemento e anima o background-position, o que funciona em todo o lado mas volta a pintar a cada fotograma.
- Registar propriedades personalizadas com @property permite ao navegador animar cores, ângulos e posições individuais dentro de um gradiente.
- Animar o transform ou a opacity numa camada de gradiente separada costuma ser a opção mais barata, porque os navegadores muitas vezes conseguem compô-la sem voltar a pintar.
- Toda a animação de gradiente deve parar, ou ficar quase imóvel, quando o utilizador pediu movimento reduzido.

Um **gradiente animado em CSS** é um fundo em gradiente que muda de cor ou de posição ao longo do tempo. Há um senão: se escreveres dois gradientes diferentes numa regra `@keyframes`, os navegadores não os misturam, saltam. Por isso, todas as técnicas que funcionam animam outra coisa junto ao gradiente: a sua posição, as propriedades personalizadas lá dentro ou a camada em que é pintado. A que escolheres decide a suavidade do resultado e o trabalho que o navegador faz a cada fotograma.

- Fotograma 1: anoitecer: `linear-gradient(120deg, #1e1b4b, #7c3aed 45%, #f472b6)`
- Fotograma 2: mais tarde: `linear-gradient(160deg, #1e1b4b, #6d28d9 35%, #fb7185)`
- Fotograma 3: brasa: `linear-gradient(200deg, #1e1b4b, #4c1d95 30%, #fb923c)`

Três momentos de uma animação lenta. A direção e a cor movem-se, mas a paleta continua a ser de uma só família.

Para o lado do design, quando o movimento ajuda uma marca e como o ritmar, vê os [fundos com gradiente animado](https://gradiently.design/pt-pt/guide/animated-gradient-background). Este guia é o código.

## Técnica 1: move um fundo maior do que o elemento

Faz o gradiente duas a quatro vezes maior do que o elemento com `background-size` e depois anima o `background-position` para que uma parte diferente apareça ao longo do tempo. Funciona em todos os navegadores e não precisa de JavaScript. Usa `alternate` para que o movimento se inverta com suavidade em vez de saltar de volta ao início.

```css
.hero {
  background-color: #1e1b4b;
  background-image: linear-gradient(120deg, #1e1b4b, #7c3aed, #f472b6, #fb923c);
  background-size: 300% 300%;
  animation: pan 18s ease-in-out infinite alternate;
}

@keyframes pan {
  from { background-position: 0% 50%; }
  to   { background-position: 100% 50%; }
}
```

O gradiente animado clássico. Durações lentas de 12 a 30 segundos parecem ambiente e não agitação.

O custo: o `background-position` não é algo que os navegadores consigam mover só na placa gráfica, por isso o elemento é repintado a cada fotograma. Num botão isso não é nada. Num herói de ecrã inteiro é trabalho real que corre enquanto a página estiver aberta.

## Técnica 2: anima as paragens de cor com @property

As propriedades personalizadas são normalmente cadeias de texto, que não se podem interpolar. Registar uma com `@property` dá-lhe um tipo, como `<color>`, `<angle>` ou `<percentage>`, e as propriedades com tipo animam-se com suavidade. Usa-as dentro do gradiente e podes animar diretamente as cores, o ângulo ou a posição de uma paragem. O `@property` é suportado em todos os principais navegadores atuais; consulta o [caniuse](https://caniuse.com/mdn-css_at-rules_property) se suportares os mais antigos.

```css
@property --from {
  syntax: "<color>";
  inherits: false;
  initial-value: #7c3aed;
}
@property --to {
  syntax: "<color>";
  inherits: false;
  initial-value: #f472b6;
}
@property --angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 120deg;
}

.hero {
  background: linear-gradient(var(--angle), var(--from), var(--to));
  animation: shift 16s ease-in-out infinite alternate;
}

@keyframes shift {
  to {
    --from: #0891b2;
    --to: #fb923c;
    --angle: 200deg;
  }
}
```

Cores e ângulo a animar dentro do gradiente. As propriedades não registadas saltariam em vez de se misturarem.

- Início: violeta a rosa: `linear-gradient(120deg, #7c3aed, #f472b6)`
- Fim: ciano a laranja: `linear-gradient(200deg, #0891b2, #fb923c)`

As duas pontas da animação acima. O navegador mistura todos os fotogramas intermédios.

Esta técnica também volta a pintar a cada fotograma, como a primeira. A vantagem é o controlo: podes mover um só brilho num [gradiente de malha](https://gradiently.design/pt-pt/guide/css-mesh-gradient), rodar uma [borda cónica](https://gradiently.design/pt-pt/guide/css-gradient-border) ou deslocar um gradiente de marca para uma segunda paleta sem fundos sobredimensionados.

## Técnica 3: transforma uma camada de gradiente

Põe o gradiente num pseudoelemento muito maior do que o elemento e anima o seu `transform`, por exemplo uma rotação ou deriva lenta. Os navegadores costumam conseguir mover uma camada transformada na placa gráfica sem a repintar, por isso esta é a forma mais barata de animar um gradiente grande. O `will-change: transform` sugere que a camada seja promovida com antecedência.

```css
.hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.hero::before {
  content: "";
  position: absolute;
  inset: -50%;
  z-index: -1;
  background: conic-gradient(from 0deg, #1e1b4b, #7c3aed, #f472b6, #0891b2, #1e1b4b);
  animation: turn 40s linear infinite;
  will-change: transform;
}

@keyframes turn {
  to { transform: rotate(1turn); }
}
```

Um enorme gradiente cónico a rodar devagar atrás do conteúdo. O inset negativo mantém os cantos cobertos enquanto roda.

## Técnica 4: fusão entre dois gradientes

Empilha duas camadas de gradiente e anima a `opacity` da de cima. A opacidade também é uma propriedade amiga do compositor, por isso a transição é suave e barata. Serve para mudanças lentas de ambiente, como uma paleta de dia a esbater-se numa de noite, e permite que os dois gradientes sejam completamente diferentes na estrutura.

```css
.sky {
  position: relative;
  isolation: isolate;
  background: linear-gradient(180deg, #7dd3fc, #fde68a);
}

.sky::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, #0f172a, #7c3aed);
  animation: dusk 20s ease-in-out infinite alternate;
}

@keyframes dusk {
  from { opacity: 0; }
  to   { opacity: 1; }
}
```

O dia esbate-se em noite e volta. Só a opacidade muda, por isso nada é repintado.

## Escolher uma técnica

| Técnica | Trabalho do navegador por fotograma | Melhor para |
| --- | --- | --- |
| Mover o `background-position` | Repintar | Elementos pequenos, botões, texto |
| Cores e ângulos com `@property` | Repintar | Mudanças de cor precisas, bordas a rodar |
| `transform` numa camada | Normalmente só composição | Fundos grandes, de ecrã inteiro |
| Fusão de `opacity` | Normalmente só composição | Mudanças lentas de ambiente ou de paleta |

Repintar é aceitável em áreas pequenas. Para áreas grandes, prefere transform e opacity.

Mede em vez de adivinhar. Nas DevTools do Chrome, o painel Rendering com o paint flashing destaca as áreas repintadas a cada fotograma, e uma gravação no Performance mostra quanto de cada fotograma vai para a pintura. O guia sobre o [desempenho dos gradientes CSS](https://gradiently.design/pt-pt/guide/css-gradient-performance) percorre o processo.

## Movimento reduzido e boas maneiras

Algumas pessoas ficam tontas ou distraídas com o movimento de fundo, e os sistemas operativos permitem-lhes pedir menos. Respeita isso com uma consulta `prefers-reduced-motion` que pára a animação e deixa um fotograma imóvel e acabado. O guia sobre [movimento reduzido](https://gradiently.design/pt-pt/guide/reduced-motion) explica o que conta como movimento que vale a pena remover.

```css
@media (prefers-reduced-motion: reduce) {
  .hero,
  .hero::before,
  .sky::after {
    animation: none;
  }
}
```

Uma regra que pára todas as técnicas acima. Confirma que o fotograma que fica continua a parecer certo.

### Evita

- Ciclos mais rápidos do que cerca de 8 segundos em áreas grandes
- Rotação de matiz arco-íris por toda a página
- Movimento atrás de texto corrente que as pessoas precisam de ler
- Animações que continuam a correr quando o separador está parado durante minutos a fio

### Faz

- Movimento lento e ambiente dentro de uma família de cor
- Movimento no herói, quietude no conteúdo
- Um fotograma calmo e imóvel para movimento reduzido
- Testa num portátil modesto e num telemóvel, não só num computador rápido

## FAQ

### Pode animar-se um gradiente CSS?

Não diretamente: os navegadores saltam entre dois valores de gradiente nos keyframes. Anima antes o `background-position`, propriedades personalizadas registadas usadas dentro do gradiente, ou o transform e a opacity de uma camada de gradiente.

### Qual é a forma mais suave de animar um fundo com gradiente?

Animar o `transform` ou a `opacity` numa camada de gradiente separada, porque os navegadores costumam conseguir tratar disso sem repintar.

### Como animo as cores de um gradiente em CSS?

Regista cada cor com `@property` usando `syntax: "<color>"`, usa as propriedades no gradiente e altera-as nos `@keyframes`.

### Os gradientes animados tornam a página lenta?

Os pequenos raramente importam. Os fundos animados grandes que repintam a cada fotograma podem custar bateria e fluidez, por isso prefere transform ou opacity e mede com as DevTools.

### Como respeito o movimento reduzido nas animações de gradiente?

Põe uma regra `animation: none` dentro de `@media (prefers-reduced-motion: reduce)` para que os utilizadores que pedem menos movimento vejam um fotograma imóvel.
