A versão curta
- 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.
Nesta página
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.
Para o lado do design, quando o movimento ajuda uma marca e como o ritmar, vê os fundos com gradiente animado. 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.
.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 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 se suportares os mais antigos.
@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;
}
}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, rodar uma borda cónica 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.
.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); }
}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.
.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; }
}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 |
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 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 explica o que conta como movimento que vale a pena remover.
@media (prefers-reduced-motion: reduce) {
.hero,
.hero::before,
.sky::after {
animation: none;
}
}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
Perguntas frequentes
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.
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


