Resumindo
- Os navegadores não conseguem interpolar entre dois valores de gradiente, então um gradiente animado em CSS move, esmaece ou transforma o gradiente em vez de animá-lo diretamente.
- A técnica clássica deixa o fundo maior que o elemento e anima o background-position, o que funciona em todo lugar, mas repinta a cada quadro.
- Registrar propriedades personalizadas com @property permite que o navegador anime cores, ângulos e posições individuais dentro de um gradiente.
- Animar transform ou opacity em uma camada de gradiente separada costuma ser a opção mais barata, porque os navegadores muitas vezes conseguem compô-la sem repintar.
- Toda animação de gradiente deve parar, ou ficar quase parada, quando o usuário pediu movimento reduzido.
Nesta página
Um gradiente animado em CSS é um fundo em gradiente que muda de cor ou de posição com o tempo. Há uma pegadinha: se você escrever dois gradientes diferentes em uma regra @keyframes, os navegadores não os misturam, eles pulam. Por isso, toda técnica que funciona anima outra coisa ao lado do gradiente: sua posição, as propriedades personalizadas dentro dele ou a camada em que ele é pintado. Qual você escolhe decide o quanto a animação fica suave e quanto trabalho o navegador faz a cada quadro.
Para o lado do design, quando o movimento ajuda uma marca e como dar o ritmo, veja fundos com gradiente animado. Este guia é o código.
Técnica 1: mova um fundo superdimensionado
Deixe o gradiente de duas a quatro vezes maior que o elemento com background-size e depois anime o background-position para que uma parte diferente apareça com o tempo. Funciona em todos os navegadores e não precisa de JavaScript. Use alternate para que o movimento se inverta suavemente em vez de pular 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 de vídeo, então o elemento é repintado a cada quadro. Em um botão, isso não é nada. Em um hero de tela cheia, é trabalho de verdade que roda enquanto a página estiver aberta.
Técnica 2: anime as paradas de cor com @property
As propriedades personalizadas normalmente são textos, que não podem ser interpolados. Registrar uma com @property dá a ela um tipo, como <color>, <angle> ou <percentage>, e propriedades tipadas animam de forma suave. Use-as dentro do gradiente e você pode animar diretamente as cores, o ângulo ou a posição de uma parada. O @property é aceito em todos os principais navegadores atuais; confira o caniuse se você oferece suporte a navegadores 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;
}
}Essa técnica ainda repinta a cada quadro, como a primeira. A vantagem dela é o controle: você pode mover um único brilho em um gradiente de malha, girar uma borda cônica ou levar um gradiente da marca para uma segunda paleta sem fundos superdimensionados.
Técnica 3: transforme uma camada de gradiente
Coloque o gradiente em um pseudoelemento bem maior que o elemento e anime o transform dele, por exemplo uma rotação ou deriva lenta. Os navegadores costumam conseguir mover uma camada transformada na placa de vídeo sem repintá-la, então esse é o jeito mais barato de animar um gradiente grande. O will-change: transform avisa que a camada deve ser 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: faça um fade cruzado entre dois gradientes
Empilhe duas camadas de gradiente e anime a opacity da de cima. A opacidade também é uma propriedade amigável ao compositor, então o fade é suave e barato. Serve para mudanças lentas de clima, como uma paleta de dia esmaecendo em uma paleta de noite, e deixa os dois gradientes serem completamente diferentes em 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; }
}Escolhendo uma técnica
| Técnica | Trabalho do navegador por quadro | Melhor para |
|---|---|---|
Mover o background-position | Repintura | Elementos pequenos, botões, texto |
Cores e ângulos com @property | Repintura | Mudanças precisas de cor, bordas giratórias |
transform em uma camada | Em geral só composição | Fundos grandes, de tela cheia |
Fade cruzado com opacity | Em geral só composição | Mudanças lentas de clima ou de paleta |
Meça em vez de adivinhar. No Chrome DevTools, o destaque de pintura do painel Rendering marca as áreas repintadas a cada quadro, e uma gravação de Performance mostra quanto de cada quadro vai para a pintura. Desempenho de gradientes em CSS mostra o passo a passo.
Movimento reduzido e boas maneiras
Algumas pessoas ficam tontas ou distraídas com movimento no fundo, e os sistemas operacionais permitem que peçam menos. Respeite isso com uma consulta prefers-reduced-motion que pare a animação, deixando um quadro parado e finalizado. O guia de movimento reduzido explica o que conta como movimento que vale remover.
@media (prefers-reduced-motion: reduce) {
.hero,
.hero::before,
.sky::after {
animation: none;
}
}Evite
- Ciclos mais rápidos que cerca de 8 segundos em áreas grandes
- Rotação de matiz em arco-íris pela página inteira
- Movimento atrás de texto corrido que as pessoas precisam ler
- Animações que continuam rodando com a aba ociosa por minutos seguidos
Faça
- Movimento lento e ambiente dentro de uma família de cor
- Movimento no hero, quietude no conteúdo
- Um quadro parado e calmo para movimento reduzido
- Teste em um notebook e um celular modestos, não só em um desktop rápido
Perguntas frequentes
É possível animar um gradiente CSS?
Não diretamente: os navegadores pulam entre dois valores de gradiente nos keyframes. Anime o background-position, propriedades personalizadas registradas usadas dentro do gradiente ou o transform e a opacity de uma camada de gradiente.
Qual é o jeito mais suave de animar um fundo em gradiente?
Animar transform ou opacity em uma camada de gradiente separada, porque os navegadores costumam tratá-las sem repintar.
Como animo as cores de um gradiente em CSS?
Registre cada cor com @property usando syntax: "<color>", use as propriedades no gradiente e mude-as em @keyframes.
Gradientes animados deixam a página lenta?
Os pequenos raramente importam. Fundos animados grandes que repintam a cada quadro podem custar bateria e fluidez, então prefira transform ou opacity e meça com o DevTools.
Como respeito o movimento reduzido em animações de gradiente?
Envolva uma regra animation: none em @media (prefers-reduced-motion: reduce) para que quem pede menos movimento veja um quadro parado.
Escrito pelo Gradiently
A equipe por trás do Gradiently, uma ferramenta de design criada em torno dos Marks: gradientes vivos que fazem tudo o que você cria ter a sua cara.
Ver nosso perfil


