Animações de borda CSS

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.

Border Animations using outline-offset by Kevin J. Powell

Um artigo que chamou minha atenção recentemente é Fantastic CSS border animation (em inglês), em que o autor 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.

Animações de borda usando conteúdo gerado por Coco

A camada branca e as linhas coloridas são conteúdo gerado. Ao mostrar e ocultar a camada branca, fica claro como elas se sobrepõem 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 real e manter o funcionamento do modelo de caixa, use vários planos de fundo que serão esticados para a área da 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.

Compatibilidade com navegadores

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 3.

Origem

O que não fazer
/* 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%);
O que fazer
background-origin: border-box;

Essa adição faz com que tudo pareça muito melhor:

Reduzir a camada de plano de fundo branca com background-clip

Com os planos de fundo ocupando todo o espaço, a camada semitransparente precisa ser reduzida novamente. Em vez de mexer em background-size de novo, há uma maneira mais fácil de fazer isso: use background-clip e defina como padding-box. Dessa forma, o plano de fundo não é mais exibido abaixo da área da borda.

Compatibilidade com navegadores

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 5.

Origem

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:

Compatibilidade com navegadores

  • Chrome: 85.
  • Edge: 85.
  • Firefox: 128.
  • Safari: 16.4.

Origem

@property --angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

@keyframes rotate {
  to {
    --angle: 360deg;
  }
}

Quando tudo é combinado, o código fica assim:

Conteúdo bônus: border-image

Uma abordagem anteriormente abordada para desenhar uma borda gradiente é usar o CSS border-image.

Compatibilidade com navegadores

  • Chrome: 16.
  • Edge: 12.
  • Firefox: 15.
  • Safari: 6.

Origem

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 o border-radius. Ele sempre vai permanecer retangular.
  • Ao definir border-image-slice para preencher, o border-image não é pintado abaixo do background 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.