Border Draw
Au survol, quatre traits de 2 px dessinent un cadre indigo autour du bouton : le haut et le bas en 300 ms, puis les deux côtés en 300 ms de plus. Deux pseudo-éléments, deux spans, aucune ligne de JavaScript.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Boutons comprend 27 effets, dont 2 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Le bouton .btn-border-draw est transparent (background: 0 0), en texte indigo #6366f1, avec un border: 2px solid transparent qui réserve 2 px tout autour. Les quatre côtés du cadre sont quatre boîtes distinctes : ::before (haut, top: 0; left: 0) et ::after (bas, bottom: 0; right: 0) font 2 px de haut pour 0 de large ; les deux <span> du HTML, .border-left (left: 0; bottom: 0) et .border-right (right: 0; top: 0), font 2 px de large pour 0 de haut. Un bouton n'a que deux pseudo-éléments : les spans fournissent les deux boîtes manquantes.
Au :hover, les pseudo-éléments passent à width: 100% et les spans à height: 100%. La séquence vient des transitions : transition: width .3s sur les traits horizontaux, transition: height .3s .3s sur les verticaux — même durée, mais un délai de 300 ms égal à la première phase. Le haut se trace de gauche à droite et le bas de droite à gauche (0 → 300 ms), puis la droite de haut en bas et la gauche de bas en haut (300 → 600 ms) : le cadre se dessine dans le sens des aiguilles d'une montre, deux côtés opposés à la fois. Courbe ease par défaut.
Mesuré dans Chromium sur le bouton livré (164 × 54 px) : les traits horizontaux atteignent 160 px et les verticaux 50 px, soit la boîte de padding — les quatre boîtes sont positionnées par rapport à elle, donc 2 px à l'intérieur du bord extérieur, dans l'espace de la bordure transparente. Et comme .demo-btn impose border-radius: 12px et overflow: hidden, la découpe arrondie (rayon intérieur 10 px) rogne les extrémités des traits droits : ils ne se rejoignent jamais, les quatre angles restent ouverts sur environ 6 px. C'est le rendu de la version livrée ; avec border-radius: 0 le cadre se ferme.
À la sortie du curseur, les mêmes transitions se rejouent à l'envers avec leurs délais : les traits horizontaux se rétractent aussitôt, les verticaux 300 ms plus tard — le cadre s'efface dans le même ordre qu'il s'est dessiné, pas en marche arrière. Rien d'autre ne change : ni fond, ni ombre, ni couleur de texte, ni :active. Le mouvement porte sur width et height, deux propriétés de mise en page recalculées à chaque image — sans conséquence pour quatre boîtes de 2 px, mais pas composées par le GPU comme le serait transform: scaleX().
Accessibilité
- Contraste au repos insuffisant : le texte
#6366f1sur le fond de démo#0a0a0fmesure 4,42:1, sous le seuil AA de 4,5:1 pour 16 px — et 4,47:1 sur blanc, tout aussi juste. Le fond du bouton est transparent : c'est votre page qui décide. Sur fond sombre, prenez#818cf8(6,6:1) ; sur fond clair,#4f46e5(6,3:1). Les traits reprennent la même couleur : au-dessus de 3:1 dans les deux cas, le cadre reste perceptible (WCAG 1.4.11). - prefers-reduced-motion absent du code : ajoutez
@media (prefers-reduced-motion: reduce) { .btn-border-draw::before, .btn-border-draw::after, .btn-border-draw .border-left, .btn-border-draw .border-right { transition: none } }— le cadre apparaît d'un bloc au survol, l'information est conservée. - Clavier : aucun
:hoverà la navigation Tab. Dupliquez les deux règles de survol vers:focus-visible(.btn-border-draw:focus-visible::before, .btn-border-draw:focus-visible::after { width: 100% }et l'équivalentheightpour les spans) : le cadre qui se dessine devient un indicateur de focus, en plus de l'outlinenatif que le code ne retire pas. - Lecteurs d'écran : les deux
<span>ne contiennent que des retours à la ligne, sans texte — le nom accessible reste le libellé. Par sécurité, posezaria-hidden="true"sur chacun, pour qu'aucune technologie d'assistance ne s'arrête sur des boîtes vides. - Tactile : pas de survol sur mobile, le cadre se trace au tap et reste affiché (iOS) —
@media (hover: hover)pour l'éviter. Un bouton transparent au repos se lit comme un lien : réservez-le aux actions secondaires. Cible 54 px de haut (padding 16 px, texte 18 px, bordure 2 × 2 px), au-dessus du minimum de 44 px, et aucun décalage de mise en page au survol grâce à la bordure transparente déjà réservée.
Compatibilité navigateur
Requiert les transitions CSS sur width/height, les pseudo-éléments ::before/::after et le positionnement absolu — tous les navigateurs depuis 2012. Aucun JavaScript, zéro dépendance.
Sans transitions, le cadre apparaît et disparaît d'un coup au survol ; sans pseudo-éléments (navigateurs préhistoriques), seuls les deux côtés portés par les spans se dessinent.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :
<button class="demo-btn btn-border-draw">
Border Draw
<span class="border-left"></span>
<span class="border-right"></span>
</button>
Le code complet HTML + CSS + JS de Border Draw, prêt à coller — et les 840 effets. Ou 299 € TTC une fois, accès à vie.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
| Couleur #6366f1 (CSS — color + background des 4 traits) | #6366f1 | Cinq occurrences à changer ensemble. Mettez background: currentColor sur les quatre traits : la couleur du texte gouverne tout, et une seule déclaration suffit pour la marque ou pour le contraste (#818cf8 sur sombre, #4f46e5 sur clair). |
| transition: width .3s (CSS — ::before, ::after) | .3s | Durée de la première phase (haut et bas). Si vous la changez, alignez le délai des côtés dessus, sinon les phases se chevauchent ou laissent un trou. |
| transition: height .3s .3s (CSS — .border-left, .border-right) | .3s de durée, .3s de délai | Le délai est le séquenceur. 0s : les quatre côtés se tracent en même temps (300 ms au total). .15s : les côtés partent à mi-course des traits horizontaux, plus fluide. |
| Épaisseur height: 2px / width: 2px (CSS — les 4 traits) | 2 px | 1 px : filet fin ; 3 à 4 px : cadre affirmé. Ajustez la bordure transparente du bouton à la même valeur pour que le trait reste à la même distance du bord. |
| border-radius (CSS — .demo-btn) | 12px | Décide des angles. 0 : les traits se rejoignent, cadre fermé. Au-delà de 12 px, les coins ouverts s'élargissent — un style en soi (cadre « à coins coupés »). |
| Ancres left/right et top/bottom (CSS — position de chaque trait) | haut : left 0 · bas : right 0 · gauche : bottom 0 · droite : top 0 | Le point d'ancrage fixe le sens du tracé. Mettez right: 0 sur ::before et left: 0 sur ::after, top: 0 sur .border-left et bottom: 0 sur .border-right : le cadre se dessine dans le sens inverse. |
| border: 2px solid transparent (CSS — .btn-border-draw) | transparent | Remplacez transparent par rgba(99, 102, 241, .25) : un cadre fantôme est visible au repos, que les traits viennent souligner au survol — plus lisible comme bouton pour un élément transparent. |
FAQ
overflow: hidden les découpe selon le border-radius: 12px du bouton (10 px à l'intérieur de la bordure). Aux angles, l'arc s'éloigne des bords de plus de 2 px : le trait y est rogné en biseau sur environ 6 px et ne rencontre pas son voisin. Trois issues : border-radius: 0 pour un cadre fermé, assumer les coins ouverts comme signature, ou passer par un <svg> avec un <rect rx="12"> animé en stroke-dashoffset si vous voulez un tracé qui suive vraiment la courbe.::before porte border-top et border-right, ::after porte border-bottom et border-left, chacun passant de width: 0; height: 0 à 100%. Deux boîtes suffisent alors, au prix d'un tracé en deux L symétriques plutôt qu'en quatre côtés séquencés. Le code livré garde les spans pour contrôler chaque côté séparément.::before en transition: width .15s, .border-right en height .15s .15s, ::after en width .15s .3s, .border-left en height .15s .45s. Le tracé enchaîne haut → droite → bas → gauche en 600 ms, comme un stylo qui ne se lève pas — les ancres livrées s'y prêtent déjà : le bas part de la droite (right: 0) et la gauche part du bas (bottom: 0).