A versão curta
- O CSS @property regista uma propriedade personalizada com uma sintaxe, uma regra de herança e um valor inicial, o que diz ao browser que tipo de valor ela contém.
- Os browsers não conseguem fazer transition de um gradiente diretamente, porque o background-image não é interpolável, mas conseguem fazer transition de uma propriedade personalizada tipada usada dentro do gradiente.
- Propriedades tipadas como <color>, <angle>, <percentage> e <length> animam-se suavemente; uma propriedade com a sintaxe universal * só alterna entre valores.
- A regra @property é suportada no Chrome, Edge, Safari e Firefox atuais, e os browsers que a ignoram mostram simplesmente o gradiente sem movimento.
- Animar uma propriedade personalizada dentro de um fundo repinta o elemento a cada fotograma, por isso mantém a área animada modesta e respeita prefers-reduced-motion.
Nesta página
O CSS @property regista uma propriedade personalizada com um tipo, para o browser saber que --angle guarda um ângulo ou que --tint guarda uma cor. Quando sabe o tipo, o browser consegue interpolar entre dois valores, o que quer dizer que podes fazer transition e animar coisas que o CSS normalmente se recusa a mover: cores de gradientes, ângulos de gradientes e a posição de uma paragem de cor. Sem registo, uma propriedade personalizada é apenas uma cadeia de texto, e uma cadeia só consegue saltar de um valor para o seguinte.
Porque é que os gradientes não fazem transition sozinhos
Experimenta transition: background 0.4s num botão cujo estado hover troca um linear-gradient() por outro e nada se suaviza: o novo gradiente salta para o lugar. Os gradientes são imagens, e a especificação trata background-image como não interpolável, por isso o browser não tem forma de misturar uma imagem com outra diferente.
O truque habitual é sobredimensionar o fundo e deslizar o background-position, que é como se constroem a maioria dos gradientes CSS animados. Funciona, mas só move um gradiente fixo. Não podes mudar uma cor, rodar um ângulo nem empurrar uma paragem. As propriedades registadas mudam isso, porque o que se anima já não é a imagem, mas um número ou uma cor tipados lá dentro. O browser recalcula o gradiente a cada fotograma a partir do valor atual.
--tint não registada
- Guardada como uma cadeia de tokens
- As transições saltam a meio
- Herda por defeito
- Um valor inválido estraga a declaração no momento do cálculo
Registada com @property
- Lida como uma cor a sério
- As transições interpolam suavemente
- A herança é escolha tua
- Um valor inválido volta ao valor inicial
A sintaxe do @property
Uma regra @property tem três descritores. O syntax diz que tipo de valor é permitido, o inherits diz se os filhos recebem o valor e o initial-value é usado quando mais nada o define. Os três são obrigatórios, exceto que o initial-value pode ser omitido quando a sintaxe é *. Se faltar ou estiver errada alguma parte obrigatória, o browser 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 tem de ser computacionalmente independente, o que na prática quer dizer unidades absolutas: 0deg, 40%, 12px e cores hexadecimais servem, enquanto 2em ou var(--x) não. Definir inherits: false costuma ser o que queres para animação, e poupa ao browser o trabalho de empurrar o valor pela árvore.
<color>Anima-se suavemente
Bom para
<angle>Anima-se suavemente
Bom para
<percentage>Anima-se suavemente
Bom para
<length>Anima-se suavemente
Bom para
<number>Anima-se suavemente
Bom para
<integer>Anima-se suavemente
Bom para
*Não, alternaBom para
'<length> | <percentage>', ou uma lista com +.Animar a cor de um gradiente no hover
Este é o exemplo útil mais pequeno. O botão usa --tint como segunda cor, e o estado hover só muda --tint. Como a propriedade está registada como cor, a transição suaviza-se entre violeta e coral em vez de saltar.
@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, vê botões com gradiente em CSS e efeitos hover com gradiente CSS.
Rodar um contorno com gradiente cónico
Um uso favorito do @property é um contorno que parece viajar à volta de um cartão. Um gradiente cónico começa num ângulo, por isso registar esse ângulo e animá-lo de 0deg a 360deg faz rodar as cores. Dois fundos fazem o trabalho: a cor do cartão recortada à caixa de padding e o gradiente cónico recortado à caixa de contorno.
@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 paragem de cor
Uma percentagem registada deixa uma paragem deslizar. Usa-a para um preenchimento de progresso, um realce que varre um título ou um horizonte que sobe com o scroll. Aqui, --stop move o ponto onde o gradiente passa de tinta a 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%;
}Registar a partir de JavaScript
CSS.registerProperty() faz o mesmo trabalho a partir de um script. É útil quando um sistema de design regista as suas propriedades em runtime, ou quando um valor só se conhece depois do carregamento. Registar o mesmo nome duas vezes lança um erro, por isso protege essa chamada.
if ('registerProperty' in CSS) {
try {
CSS.registerProperty({
name: '--angle',
syntax: '<angle>',
inherits: false,
initialValue: '0deg',
})
} catch {
// Already registered, which is fine.
}
}Suporte dos browsers, alternativas e desempenho
O @property funciona no Chrome, Edge, Safari e Firefox atuais; o Firefox foi o último a acrescentá-lo, na versão 128. Consulta o caniuse se suportas dispositivos mais antigos. Um browser que não perceba a regra trata --angle como uma propriedade personalizada comum, por isso o teu gradiente continua a desenhar-se no valor inicial e simplesmente não se move. É uma boa alternativa, desde que o fotograma estático pareça acabado.
- 1
Regista antes de usar
Põe todas as regras
@propertyao nível de topo, fora de media queries, para se aplicarem em todo o lado. - 2
Usa sintaxes tipadas
Escolhe
<color>,<angle>ou<percentage>. Evita*para tudo o que planeias animar. - 3
Faz transition da propriedade
Escreve
transition: --tint 400ms, nomeando a propriedade personalizada e nãobackground. - 4
Respeita o movimento reduzido
Pára as animações em ciclo com
prefers-reduced-motion: reduce, como se descreve em prefers-reduced-motion. - 5
Verifica o fotograma parado
Desliga a animação e confirma que o gradiente em repouso continua a parecer intencional.
Se o movimento que queres vive em publicações sociais ou vídeo e não numa página web, um Mark do Gradiently já traz a sua própria luz e movimento lento, e o Pro exporta-o em MP4, WebM ou GIF onde o browser suporta gravação, sem escreveres keyframes. Para tudo o que é web, o @property é a ferramenta mais limpa que tens. A referência da MDN lista todos os descritores.
Perguntas frequentes
O que faz o CSS @property?
Regista uma propriedade personalizada com um tipo, uma regra de herança e um valor inicial. Conhecer o tipo permite ao browser validar o valor e interpolá-lo em transições e animações.
É possível animar um gradiente CSS?
Não diretamente, porque o background-image não é interpolável. Regista as cores, o ângulo ou as posições das paragens com @property, usa-os dentro do gradiente e anima essas propriedades.
Porque é que a minha animação @property não funciona?
Normalmente falta um descritor, o valor inicial usa uma unidade relativa, a sintaxe é *, ou o transition nomeia background em vez da propriedade personalizada. Qualquer descritor inválido faz o browser ignorar a regra inteira.
O Firefox suporta @property?
Sim. O Firefox acrescentou o @property na versão 128, por isso funciona agora em todos os principais browsers atuais.
O inherits deve ser true ou false?
Usa false na maioria dos valores animados. Mantém o valor no elemento onde o defines e poupa trabalho extra ao browser.
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