Boutons✨ Premium

Glitch Effect

Deux copies du libellé, découpées en bandes par clip-path, sautent de ±3 px avec des ombres magenta et cyan — un glitch permanent, en CSS seul.

CSSAnimationGlitch

Vous aurez accès à la démo interactive avec un compte gratuit.

Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Boutons comprend 27 effets, dont 2 gratuits. Découvrir la catégorie →

3 exemples d'usage

Bouton « Jouer » — landing de tournoi esport ou de jeu — Glitch Effect exemple 1

① Bouton « Jouer » — landing de tournoi esport ou de jeu

QuandHero sombre d'un site de jeu ou de tournoi : titre en capitales, date, un bouton d'entrée.
PourquoiLe vocabulaire visuel (aberration chromatique, lignes de balayage) est celui du média ; le glitch permanent tient le rôle du « insert coin » qui clignote.
RéglagestranslateX porté à ±5 px, ombres à 3 px, cycles 1.1 s / 1.3 s pour un rendu plus nerveux.
Page 404 — retour à l'accueil — Glitch Effect exemple 2

② Page 404 — retour à l'accueil

QuandPage d'erreur : grand « 404 », une phrase, un bouton de retour.
PourquoiLe glitch raconte l'erreur (signal corrompu) et occupe une page vide par nature. Un seul élément animé : le message reste lisible.
RéglagesCycles ralentis à 2.2 s / 2.6 s (glitch paresseux), fond #0f0f14, ombres magenta et cyan conservées.
Inscription à un hackathon — carte d'événement tech — Glitch Effect exemple 3

③ Inscription à un hackathon — carte d'événement tech

QuandCarte listant un événement (nom, date, places restantes) avec un bouton d'inscription.
PourquoiSur une carte, l'effet joue le rôle d'un accent de marque « tech » sans bibliothèque ni image ; le libellé court reste net.
RéglagesFond #0ea5e9, ombres #f0f → #fff et #0ff → #000 pour un glitch monochrome, translateX ±2 px.

Comment ça marche

.btn-glitch::before et ::after recréent le libellé avec content: attr(data-text) — l'attribut data-text du bouton doit porter le même texte que son contenu. Les deux pseudo-éléments sont en position: absolute; top: 0; width: 100%; height: 100%, centrés en display: flex, avec le même fond #6366f1 que le bouton : là où une bande est visible, elle recouvre entièrement le texte d'origine.

Chaque copie ne montre qu'une bande horizontale. ::before est décalé de left: 2px avec un fantôme magenta (text-shadow: -2px 0 #f0f) et animé par glitchTop (1,4 s) ; ::after est décalé de left: -2px avec un fantôme cyan (text-shadow: 2px 0 #0ff) et animé par glitchBottom (1,7 s). Le clip-path: inset(haut 0 bas) de chaque keyframe découpe une bande située entre 22 % et 66 % de la hauteur — là où se trouve le texte.

steps(1, end) fait tout le caractère de l'effet : aucune interpolation entre les keyframes. Tous les 20 % du cycle (280 ms pour la bande haute, 340 ms pour la basse), la bande saute à une nouvelle position et à un nouveau translateX entre −3 et +3 px. Les deux durées n'ont pas de diviseur commun : le motif ne se répète qu'au bout de 23,8 s et paraît aléatoire.

overflow: hidden sur .demo-btn coupe les débordements de ±3 px aux bords, et position: relative sur .btn-glitch ancre les pseudo-éléments. L'animation tourne dès le chargement, sans survol : le bouton n'est jamais immobile.

Accessibilité

  • prefers-reduced-motion absent du code : un mouvement permanent dans le champ de vision. Ajoutez @media (prefers-reduced-motion: reduce) { .btn-glitch::before, .btn-glitch::after { display: none } } — il reste un bouton indigo ordinaire, au libellé parfaitement lisible.
  • Lecteurs d'écran : content: attr(data-text) est du contenu généré, que Chrome, Firefox et Safari intègrent au nom accessible d'un bouton — le libellé peut être annoncé trois fois (« Jouer Jouer Jouer »). Posez aria-label sur le bouton avec le texte visible : il devient le nom accessible et les pseudo-éléments sont ignorés.
  • Lisibilité : à tout instant, une bande décale une partie des glyphes de 3 px au plus et ajoute des fantômes colorés. Acceptable pour un libellé court (un ou deux mots, 16 px, graisse 600) ; à éviter sur un texte long ou sous 14 px.
  • Contraste : texte blanc sur #6366f1 = 4,47:1, juste sous le seuil AA de 4,5:1 ; les fantômes magenta et cyan dégradent encore la lisibilité locale. #4f46e5 donne 6,3:1 — à changer aux trois occurrences (bouton et deux pseudo-éléments).
  • Scintillement : les bandes changent 3,6 et 2,9 fois par seconde, mais la zone qui bouge fait quelques pixels de haut sur un petit élément — loin des éclairs plein écran visés par WCAG 2.3.1. La règle reduced-motion ci-dessus reste la bonne protection pour les personnes sensibles au mouvement. Anneau de focus natif conservé (pas d'outline: none).

Compatibilité navigateur

Requiert clip-path: inset() sans préfixe, content: attr(), la fonction de temps steps() et text-shadow. Aucun JavaScript, zéro dépendance.

Chrome 55+✓ Complet
Firefox 54+✓ Complet
Safari 13.1+✓ Complet (9.1–13 avec -webkit-)
Edge 79+✓ Complet
Mobile iOS 13.4+✓ Complet
Android Chrome✓ Complet

Sans clip-path, les deux copies s'affichent entières l'une sur l'autre : le texte reste lisible mais bouge en bloc de ±3 px avec ses ombres colorées. Doublez les déclarations en -webkit-clip-path pour Safari 9.1 à 13.

Le code

Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :

index.html — structure
🔒 Débloquer le code complet — à partir de 2,99 € le 1er mois

HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
data-text (HTML — attribut du bouton) identique au libellé Texte des deux copies. Doit rester égal au libellé visible ; dans un framework, liez les deux à la même variable.
animation-duration (CSS — ::before 1.4s / ::after 1.7s) 1.4s / 1.7s Vitesse des sauts (cinq par cycle). Gardez deux durées sans diviseur commun pour éviter un motif visible ; 0.8s / 1.1s = frénétique.
translateX (CSS — @keyframes glitchTop / glitchBottom) −3 à +3 px Amplitude du tremblement horizontal. ±6 px déchire franchement le texte ; ±1 px donne un frisson.
clip-path: inset(…) (CSS — chaque keyframe) bandes entre 22 % et 66 % de la hauteur Position et épaisseur des tranches. Elles visent la zone du texte (≈ 30–70 % de la hauteur avec le padding par défaut) — à recaler si vous changez le padding.
text-shadow (CSS — ::before #f0f / ::after #0ff) −2px 0 #f0f / 2px 0 #0ff Aberration chromatique. Un seul canal (#f0f seul) est plus sobre ; 0 0 6px à la place du décalage donne un halo au lieu d'un dédoublement.
left: 2px / -2px (CSS — ::before / ::after) ±2px Décalage de base des copies par rapport au texte d'origine. À 0, les copies ne se distinguent que par leurs ombres.
steps(1, end) (CSS — animation-timing-function) steps(1, end) Saccade sans interpolation. steps(2, end) ajoute une position intermédiaire ; linear transforme le glitch en glissement continu — ce n'est plus un glitch.

FAQ

Oui. Au repos, masquez les copies : .btn-glitch::before, .btn-glitch::after { display: none }. Réaffichez-les avec leurs animations sous .btn-glitch:hover::before et .btn-glitch:hover::after (display: flex plus la déclaration animation de chacune). L'animation repart de son 0 % à chaque survol.
Les bandes affichent data-text, pas le contenu du bouton. Si vous changez le libellé (traduction, état « Chargement… »), mettez l'attribut à jour au même moment : btn.dataset.text = btn.textContent. Un attribut absent donne des bandes vides : le texte semble alors troué.
position: relative fait des ::before/::after en position: absolute des calques exactement superposés au bouton (top: 0; width/height: 100%). overflow: hidden coupe ce qui dépasse quand les copies glissent de ±3 px et à cause des left: ±2px — sans lui, des bords de couleur apparaissent à l'extérieur du bouton.