Resumindo
- O CSS @property registra uma propriedade personalizada com uma sintaxe, uma regra de herança e um valor inicial, o que diz ao navegador que tipo de valor ela guarda.
- Os navegadores não conseguem fazer transição de um gradiente diretamente, porque background-image não é interpolável, mas conseguem fazer transição de uma propriedade personalizada tipada usada dentro do gradiente.
- Propriedades tipadas como <color>, <angle>, <percentage> e <length> animam suavemente; uma propriedade com a sintaxe universal * só salta entre valores.
- A regra @property é suportada nas versões atuais do Chrome, Edge, Safari e Firefox, e os navegadores que a ignoram simplesmente mostram o gradiente sem movimento.
- Animar uma propriedade personalizada dentro de um fundo repinta o elemento a cada quadro, então mantenha a área animada modesta e respeite prefers-reduced-motion.
Nesta página
O CSS @property registra uma propriedade personalizada com um tipo, para que o navegador saiba que --angle guarda um ângulo ou que --tint guarda uma cor. Sabendo o tipo, ele consegue interpolar entre dois valores, o que significa que você pode fazer transição e animar coisas que o CSS normalmente se recusa a mover: cores de gradiente, ângulos de gradiente e a posição de uma parada de cor. Sem registro, uma propriedade personalizada é só uma string, e uma string só consegue pular de um valor para o próximo.
Por que gradientes não fazem transição sozinhos
Experimente transition: background 0.4s num botão cujo estado de hover troca um linear-gradient() por outro e nada suaviza: o novo gradiente entra de uma vez. Gradientes são imagens, e a especificação trata background-image como não interpolável, então o navegador não tem como misturar uma imagem numa outra diferente.
O contorno habitual é aumentar o fundo e deslizar background-position, que é como a maioria dos gradientes animados em CSS é feita. Funciona, mas só move um gradiente fixo de lugar. Você não consegue mudar uma cor, girar um ângulo ou empurrar uma parada. Propriedades registradas mudam isso, porque o que está sendo animado deixa de ser a imagem e passa a ser um número ou uma cor tipados dentro dela. O navegador recalcula o gradiente a cada quadro a partir do valor atual.
--tint não registrada
- Guardada como uma string de tokens
- Transições pulam na metade
- Herda por padrão
- Um valor inválido quebra a declaração no momento do cálculo
Registrada com @property
- Interpretada como uma cor de verdade
- Transições interpolam suavemente
- A herança é escolha sua
- Um valor inválido volta para o valor inicial
A sintaxe do @property
Uma regra @property tem três descritores. syntax diz que tipo de valor é permitido, inherits diz se os filhos recebem o valor e initial-value é usado quando nada mais o define. Os três são obrigatórios, exceto que initial-value pode ficar de fora quando a sintaxe é *. Se alguma parte obrigatória faltar ou estiver errada, o navegador ignora a regra inteira, em silêncio.
@property --tint {
syntax: '<color>';
inherits: false;
initial-value: #7c3aed;
}
@property --angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@property --stop {
syntax: '<percentage>';
inherits: false;
initial-value: 40%;
}O valor inicial precisa ser computacionalmente independente, o que na prática significa unidades absolutas: 0deg, 40%, 12px e cores hex funcionam, enquanto 2em ou var(--x) não. Definir inherits: false costuma ser o que você quer para animação, e poupa o navegador de propagar o valor pela árvore.
<color>Anima suavemente
Bom para
<angle>Anima suavemente
Bom para
<percentage>Anima suavemente
Bom para
<length>Anima suavemente
Bom para
<number>Anima suavemente
Bom para
<integer>Anima suavemente
Bom para
*Não, ele saltaBom para
'<length> | <percentage>', ou uma lista com +.Animar a cor de um gradiente no hover
Este é o menor exemplo útil. O botão usa --tint como segunda cor, e o estado de hover só muda --tint. Como a propriedade está registrada como cor, a transição suaviza entre violeta e coral em vez de trocar de uma vez.
@property --tint {
syntax: '<color>';
inherits: false;
initial-value: #7c3aed;
}
.button {
background: linear-gradient(120deg, #1e1b4b 0%, var(--tint) 100%);
transition: --tint 400ms ease;
}
.button:hover {
--tint: #fb7185;
}Para mais formas de tratar botões, veja botões com gradiente em CSS e efeitos hover com gradiente em CSS.
Girar uma borda com gradiente cônico
Um uso favorito do @property é uma borda que parece percorrer o contorno de um card. Um gradiente cônico começa a partir de um ângulo, então registrar esse ângulo e animá-lo de 0deg a 360deg faz as cores girarem. Dois fundos fazem o trabalho: a cor do card recortada na padding box e o gradiente cônico recortado na border box.
@property --angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
.card {
border: 2px solid transparent;
border-radius: 16px;
background:
linear-gradient(#0f0b1e, #0f0b1e) padding-box,
conic-gradient(from var(--angle), #22d3ee, #7c3aed, #f472b6, #22d3ee) border-box;
animation: spin 6s linear infinite;
}
@keyframes spin {
to { --angle: 360deg; }
}
@media (prefers-reduced-motion: reduce) {
.card { animation: none; }
}conic-gradient(from 0deg, #22d3ee, #7c3aed, #f472b6, #22d3ee)Mover uma parada de cor
Uma porcentagem registrada deixa uma parada deslizar. Use para o preenchimento de uma barra de progresso, um destaque que varre um título ou um horizonte que sobe com a rolagem. Aqui --stop move o ponto em que o gradiente passa do tinta para o verde-azulado.
@property --stop {
syntax: '<percentage>';
inherits: false;
initial-value: 20%;
}
.meter {
background: linear-gradient(90deg, #0d9488 0%, #0d9488 var(--stop), #0f172a var(--stop));
transition: --stop 600ms ease-out;
}
.meter[data-done] {
--stop: 100%;
}Registrar pelo JavaScript
CSS.registerProperty() faz o mesmo trabalho a partir de um script. É útil quando um design system registra suas propriedades em tempo de execução, ou quando um valor só é conhecido depois do carregamento. Registrar o mesmo nome duas vezes gera um erro, então proteja a chamada.
if ('registerProperty' in CSS) {
try {
CSS.registerProperty({
name: '--angle',
syntax: '<angle>',
inherits: false,
initialValue: '0deg',
})
} catch {
// Already registered, which is fine.
}
}Suporte dos navegadores, alternativas e desempenho
@property funciona nas versões atuais do Chrome, Edge, Safari e Firefox; o Firefox foi o último a adotá-lo, na versão 128. Consulte o caniuse se você atende dispositivos mais antigos. Um navegador que não entende a regra trata --angle como uma propriedade personalizada comum, então seu gradiente continua sendo desenhado no valor inicial e simplesmente não se move. É uma boa alternativa, desde que o quadro parado pareça acabado.
- 1
Registre antes de usar
Coloque cada regra
@propertyno nível superior, fora de media queries, para que valha em todo lugar. - 2
Use sintaxes tipadas
Escolha
<color>,<angle>ou<percentage>. Evite*para qualquer coisa que pretenda animar. - 3
Faça a transição da propriedade
Escreva
transition: --tint 400ms, nomeando a propriedade personalizada em vez debackground. - 4
Respeite o movimento reduzido
Pare animações em loop sob
prefers-reduced-motion: reduce, como descrito em prefers reduced motion. - 5
Confira o quadro parado
Desligue a animação e garanta que o gradiente em repouso ainda pareça intencional.
Se o movimento que você quer vive em posts ou vídeos, e não numa página web, um Mark do Gradiently já carrega sua própria luz e movimento lento, e o Pro o exporta como MP4, WebM ou GIF onde o navegador permite gravar, sem escrever keyframes. Para tudo na web, @property é a ferramenta mais limpa que você tem. A referência da MDN lista todos os descritores.
Perguntas frequentes
O que o CSS @property faz?
Registra uma propriedade personalizada com um tipo, uma regra de herança e um valor inicial. Saber o tipo permite ao navegador validar o valor e interpolá-lo em transições e animações.
Dá para animar um gradiente CSS?
Não diretamente, porque background-image não é interpolável. Registre as cores, o ângulo ou as posições das paradas com @property, use-os dentro do gradiente e anime essas propriedades.
Por que minha animação com @property não funciona?
Geralmente falta um descritor, o valor inicial usa uma unidade relativa, a sintaxe é * ou a transição nomeia background em vez da propriedade personalizada. Qualquer descritor inválido faz o navegador ignorar a regra inteira.
O Firefox suporta @property?
Sim. O Firefox adotou o @property na versão 128, então agora ele funciona em todos os principais navegadores atuais.
inherits deve ser true ou false?
Use false para a maioria dos valores animados. Isso mantém o valor no elemento onde você o definiu e evita trabalho extra para o navegador.
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