Vamos lá! Por que animar border-image?
Olha só: a maioria dos devs acha que border-image é aquela propriedade esquecida de 2012 que ninguém usa. Erro grave! Ela te dá bordas baseadas em imagem (ou gradiente) com zero elementos extras no DOM e zero pseudo-elementos — isso é ouro quando seu card já tá usando ::before e ::after pra outra coisa.
O detalhe é que border-image não respeita border-radius. Se você precisa de um anel curvo animado, parte pra abordagem com mask. Mas se quer uma animação de borda afiada, eficiente e tileable num único elemento, border-image é imbatível.
Bora construir uma do zero. 🔥
O HTML
Nada demais — só um card com conteúdo:
<div class="card">
<div class="card__content">Bruce Wayne</div>
</div>
A imagem do personagem fica como background, então já partimos pro CSS.

Estilos base e configurando o border-image
Começamos com as dimensões do card e uma imagem de fundo, depois adicionamos cada longhand do border-image separadamente pra você ver exatamente o que cada propriedade faz.
.card {
width: 150px;
aspect-ratio: 0.69;
position: relative;
background: center / 90% no-repeat;
background-image: url("batman.jpg");
/* 1. O que pinta a borda: um gradiente linear */
border-image-source: linear-gradient(-45deg, red var(--p, 0%), transparent 0%);
/* 2. Como o gradiente é fatiado em 9 pedaços */
border-image-slice: 1;
/* 3. Espessura física da borda */
border-image-width: 5px;
/* 4. Empurra a borda pra fora da caixa */
border-image-outset: 5px;
}
Modelo mental importante:
border-image-slice: 1significa "corta a imagem em fatias de 1px e estica o meio." Pra um gradiente, isso gera um preenchimento suave por toda a borda.border-image-widthé o que de fato renderiza a borda. Sem ela, nada aparece.border-image-outseté seu amigo quando a borda fica colada demais no conteúdo.
Registrando uma custom property pra poder animar
Aqui tá a pegadinha que derruba muita gente: gradientes não são animáveis por padrão. Você não consegue fazer transition de linear-gradient(red, blue) pra linear-gradient(red, blue, green) — o browser não sabe interpolar as posições dos stops.
A solução é @property. Registra uma custom property com sintaxe tipada e o browser passa a saber como fazer o tween:
@property --p {
syntax: "<percentage>";
initial-value: 0%;
inherits: false;
}
Coloca ela no gradiente e anima no hover:
.card {
border-image-source: linear-gradient(-45deg, red var(--p), transparent 0%);
transition: --p 0.6s ease-out;
}
.card:hover {
--p: 100%;
}
O stop vermelho desliza de 0% pra 100%, dando a impressão de que a borda se desenha sozinha. É esse o truque todo. 😎

Subindo o nível: conic gradients e slices animados
Linear é só aquecimento. Troca por um conic-gradient e anima a contagem de slices também, e você tem uma borda girando e tileada que parece um loading spinner turbinado.
/* Mais duas custom properties registradas */
@property --n {
syntax: "<number>";
initial-value: 1;
inherits: false;
}
@property --a {
syntax: "<angle>";
initial-value: 0deg;
inherits: false;
}
.card {
border-image-source: conic-gradient(from var(--a), red var(--a), transparent 0%);
border-image-width: 5px;
border-image-slice: var(--n);
border-image-repeat: round; /* tile dos slices sem clipping */
/* Seja explícito sobre o que anima — bom pra perf */
transition-property: --n, --a;
transition-duration: 0.6s;
}
.card:hover {
--n: 20; /* slices mais profundos = tiling visível */
--a: 360deg; /* rotação completa = borda se desenha */
}
Fica de olho nisso aqui
- Sem suporte a
border-radius. Se o design precisa de cantos arredondados, essa técnica é a ferramenta errada. Use mask ou stroke SVG. - Suporte a
@propertyé bom no Chrome/Edge/Safari 16.4+ e Firefox 128+, mas sempre use@supportsse você precisa atender Safari antigo. - Animar
border-image-slicepode engasgar em GPUs de celular mais fraco. Testa em dispositivo real, não só no throttling do DevTools. - Não anime
border-image-width— dispara layout. Fica só em propriedades de paint.

Próximos passos
Depois que você dominar gradientes simples, tenta empilhar dois border-image-source com mask pra conseguir varreduras multi-cor, ou combinar com @scroll-timeline pra animações de borda dirigidas por scroll.
Pra uma olhada mais funda em técnicas modernas de CSS como essa, dá uma conferida no nosso deep dive sobre o Gemini CLI Plan Mode — mesma vibe, ferramenta diferente.
E se você trabalha com UIs cheias de dados onde o conteúdo do card é dinâmico, combina isso com um entendimento sólido de Pandas loc vs iloc para indexação de DataFrame pra deixar seu backend tão limpo quanto seu frontend.
Sua tarefa de casa: faz um fork do demo, troca o gradiente por um radial-gradient repetido e vê o que rola. Os resultados costumam surpreender.
Fonte: css-tricks.com