Animations de bordure CSS

Découvrez plusieurs façons d'animer une bordure en CSS.

Définir des bordures

Il existe plusieurs méthodes pour définir une bordure sur un élément : border, outline et box-shadow. Comme l'explique Stephanie Eckles dans The 3 CSS Methods for Adding Element Borders, chaque approche présente ses propres avantages et inconvénients, en particulier lorsqu'il s'agit d'animer les bordures. La principale raison de ne pas utiliser un border CSS approprié est l'animation.

Animations de bordure à l'aide de outline-offset par Kevin J. Powell

Un article qui a récemment attiré mon attention est Fantastic CSS border animation, dans lequel l'auteur Coco explore d'autres options. En injectant du contenu généré à l'aide de ::before et ::after, ils créent une fausse bordure qui est ensuite animée.

Ce qui me frappe le plus, ce sont les visualisations animées utilisées dans l'article. Ils permettent d'expliquer exactement ce qui est fait pour obtenir l'effet souhaité.

Animations de bordure à l'aide de contenu généré par Coco

La couche blanche et les lignes colorées sont des contenus générés. En faisant apparaître et disparaître le calque blanc, on comprend clairement comment ils s'empilent et comment l'animation fonctionne.

Conserver le modèle de boîte

L'inconvénient d'utiliser du contenu généré pour imiter une bordure est que vous vous retrouvez avec un modèle de boîte défectueux : le contenu peut désormais masquer la fausse bordure, car ladite "bordure" est peinte en dessous. Pour résoudre ce problème, vous devez appliquer le border-width souhaité en tant que padding.

Pour obtenir une vraie bordure et ainsi conserver le fonctionnement du modèle de boîte, vous pouvez utiliser plusieurs arrière-plans que vous étirez ensuite dans la zone de bordure.

Principes de base

Commençons par créer une bordure en pointillés et ajouter les différents arrière-plans.

/* 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
  )
;

Dimensionner les arrière-plans avec background-origin

Comme vous pouvez le voir, il y a un problème avec les arrière-plans : ils sont peints dans la bordure, mais la propriété conic-gradient semble incorrecte. Il s'agit en fait du comportement prévu : par défaut, les images de fond ne sont pas dessinées dans la bordure, car leur origine est le padding-box de l'élément. Pour créer une bordure, les images d'arrière-plan définies sont répétées dans la bordure elle-même, ce qui produit un effet visuel étrange.

Pour résoudre ce problème, vous devez étirer l'arrière-plan afin qu'il occupe également la taille de la bordure. Vous pouvez le faire manuellement en étirant et en repositionnant l'arrière-plan, mais il est préférable d'utiliser la propriété background-origin pour dimensionner l'arrière-plan par rapport à border-box.

Browser Support

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

Source

À éviter
/* 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%);
À faire
background-origin: border-box;

Ce simple ajout améliore considérablement l'apparence de l'ensemble :

Réduire le calque d'arrière-plan blanc avec background-clip

Comme les arrière-plans occupent désormais tout l'espace, la couche semi-transparente doit être réduite à nouveau. Au lieu de modifier à nouveau background-size, il existe un moyen plus simple : utilisez background-clip et définissez-le sur padding-box. De cette façon, l'arrière-plan n'est plus dessiné sous la zone de la bordure.

Browser Support

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

Source

background-clip:
  padding-box, /* Clip white semi-transparent to the padding-box */
  border-box /* Clip colored boxes to the border-box (default) */
;

Enfin, définissez la bordure sur transparent pour obtenir l'effet complet.

border: 0.3rem dotted transparent;

Animation

Pour restaurer l'animation de la bordure, vous pouvez manipuler l'angle de départ de conic-gradient.

--angle: 0deg;
conic-gradient(
  from var(--angle),
  #d53e33 0deg 90deg,
  #fbb300 90deg 180deg,
  #377af5 180deg 270deg,
  #399953 270deg 360deg
);

Grâce à @property, cela devient un jeu d'enfant dans les navigateurs compatibles :

Browser Support

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

Source

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

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

Une fois combiné, le code devient :

Contenu de type "Bonus" : border-image

Une approche déjà abordée pour dessiner une bordure en dégradé consiste à utiliser la propriété CSS border-image.

Browser Support

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

Source

Il permet de simplifier le code, car vous n'avez pas à gérer les arrière-plans qui se chevauchent. L'animation peut être appliquée de la même manière qu'auparavant.

/* 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
;

Toutefois, vous remarquerez que certaines choses ne fonctionnent plus avec cette approche :

  • Le border-image ne suit pas le border-radius. Il reste toujours rectangulaire.
  • Lorsque vous définissez border-image-slice sur "fill", le border-image n'est pas peint sous le background défini, mais au-dessus. Cela peut poser problème si vous souhaitez que l'arrière-plan soit semi-transparent.

En conclusion

Il existe de nombreuses possibilités pour animer des bordures en CSS. Selon le cas d'utilisation, vous pouvez privilégier l'un ou l'autre.