Várias maneiras de animar uma borda no CSS
Como definir bordas
Há alguns métodos disponíveis para definir uma borda em um elemento: border
, outline
e box-shadow
. Como detalhado em Os 3 métodos de CSS para adicionar bordas de elementos (link em inglês) de Stephanie Eckles, cada abordagem tem suas próprias vantagens e desvantagens, especialmente quando se trata de animar as bordas. A principal razão para não usar um border
do CSS adequado é para fins de animação.
Um artigo que chamou minha atenção recentemente é Fantastic CSS border animation (em inglês), em que a autora Coco explorou mais opções. Ao injetar conteúdo gerado usando ::before
e ::after
, eles criam uma borda falsa que é animada.
O que mais me chama a atenção são as visualizações animadas usadas no artigo. Elas ajudam a explicar exatamente o que está sendo feito para alcançar o efeito desejado.
A camada branca e as linhas coloridas são conteúdo gerado. Ao esmaecer a camada branca, fica claro como eles empilham e como a animação funciona.
Como manter o modelo de caixa
Uma desvantagem de usar conteúdo gerado para imitar uma borda é que você acaba com um modelo de caixa quebrado: o conteúdo agora pode obscurecer a borda falsa porque ela é pintada por baixo. Para reduzir, aplique o border-width
desejado como padding
.
Para ter uma borda verdadeira e, assim, manter o funcionamento do modelo de box, é possível usar vários planos de fundo, que você estica até a área de borda.
Noções básicas
Vamos começar criando uma borda pontilhada e adicionando vários planos de fundo.
/* Size of the border */
--border-size: 0.5rem;
/* Create a dotted border */
border: var(--border-size) dotted lime;
/* Create two background layers:
1. A white semi-transparent
2. A layer with the colored boxes
*/
background-image:
linear-gradient(to right, rgb(255 255 255 / 0.5), rgb(255 255 255 / 0.5)),
conic-gradient(
from 45deg,
#d53e33 0deg 90deg,
#fbb300 90deg 180deg,
#377af5 180deg 270deg,
#399953 270deg 360deg
)
;
Como dimensionar os planos de fundo com background-origin
Como você pode ver, há algo estranho acontecendo com os planos de fundo: eles são pintados na borda, mas o conic-gradient
parece estar errado. Esse é o comportamento esperado: por padrão, as imagens de plano de fundo não são exibidas na borda, porque a origem delas é o padding-box
do elemento. Para criar uma borda, as imagens de plano de fundo definidas são repetidas na própria borda, resultando no efeito visual estranho.
Para resolver esse problema, estique o plano de fundo para que ele também ocupe o tamanho da borda. Você pode fazer isso manualmente, esticando e reposicionando o plano de fundo, mas o ideal é usar a propriedade background-origin
para dimensionar o plano de fundo em relação ao border-box
.
/* Manually add or offset the size of the border where needed */ background-position: calc(var(--border-size) * -1) calc(var(--border-size) * -1); background-size: calc(var(--border-size) * 2 + 100%) calc(var(--border-size) * 2 + 100%);
background-origin: border-box;
Esta adição torna tudo muito melhor:
Reduzir a camada de plano de fundo branca com background-clip
Como os planos de fundo ocupam todo o espaço agora, a camada semitransparente precisa ser reduzida novamente. Em vez de mexer no background-size
de novo, há uma maneira mais fácil de fazer isso: use background-clip
e defina-o como padding-box
. Dessa forma, o plano de fundo não é mais exibido abaixo da área da borda.
background-clip:
padding-box, /* Clip white semi-transparent to the padding-box */
border-box /* Clip colored boxes to the border-box (default) */
;
Por fim, defina a borda transparent
para ter o efeito completo.
border: 0.3rem dotted transparent;
Animação
Para restaurar a animação da borda, manipule o ângulo de início do conic-gradient
.
--angle: 0deg;
conic-gradient(
from var(--angle),
#d53e33 0deg 90deg,
#fbb300 90deg 180deg,
#377af5 180deg 270deg,
#399953 270deg 360deg
);
Graças a @property, isso se torna muito fácil nos navegadores compatíveis:
@property --angle {
syntax: "<angle>";
initial-value: 0deg;
inherits: false;
}
@keyframes rotate {
to {
--angle: 360deg;
}
}
Combinado, o código se torna:
Conteúdo bônus: border-image
Uma abordagem coberta anteriormente para desenhar uma borda de gradiente é usar o CSS border-image
.
Isso permite um código mais simplificado, já que você não precisa lidar com planos de fundo sobrepostos. A animação pode ser aplicada da mesma maneira que antes.
/* Create a border */
border: 0.5rem solid transparent;
/* Paint an image in the border */
border-image:
conic-gradient(
from var(--angle),
#d53e33 0deg 90deg,
#fbb300 90deg 180deg,
#377af5 180deg 270deg,
#399953 270deg 360deg
) 1
;
No entanto, algumas coisas não funcionam mais com essa abordagem:
- O
border-image
não segue oborder-radius
. Ele sempre vai permanecer retangular. - Ao definir
border-image-slice
para preencher, oborder-image
não é pintado abaixo dobackground
definido, mas na parte de cima. Isso pode ser um problema se você quiser que o plano de fundo seja semitransparente.
Para encerrar
Há muitas possibilidades de animar bordas no CSS. Dependendo do caso de uso, você pode usar um ou outro.