Boutons✨ Premium

Split Text

Le JS découpe le libellé en un span par lettre ; au survol, chaque lettre saute de 8 px — les impaires vers le haut, les paires vers le bas — avec 30 ms de décalage entre voisines et une courbe à rebond de 500 ms.

JSHoverText

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

Commencer — accueil d'une application d'apprentissage pour enfants — Split Text exemple 1

① Commencer — accueil d'une application d'apprentissage pour enfants

QuandHero coloré d'une application éducative : mascotte ou illustration, promesse, un bouton de démarrage.
PourquoiLes lettres qui sautent chacune à leur tour ont la légèreté d'un générique de dessin animé ; c'est l'un des rares contextes où un bouton peut se permettre de « danser ». Le mot court garde la vague lisible.
RéglagesTexte 18 px gras (le seuil de contraste passe à 3:1), amplitude ±10px, rotation ±8deg, décalage 0.04s.
Je viens ! — carte d'invitation à une fête — Split Text exemple 2

② Je viens ! — carte d'invitation à une fête

QuandCarte d'événement festif : date, lieu, nombre de participants, un bouton de réponse.
PourquoiLa vague de lettres joue le rôle de confettis sans image ni bibliothèque : un retour joyeux sur une action sociale légère. Sur trois mots, la vague dure 0,3 s de plus qu'au repos, ce qui reste court.
RéglagesPalette de la carte (dégradé #0f766e → #115e59 pour le contraste), padding: 13px 22px, amplitude ±6px pour une carte compacte.
C'est parti — dernière étape d'un onboarding — Split Text exemple 3

③ C'est parti — dernière étape d'un onboarding

QuandÉcran de fin de configuration : un message de réussite, un gros bouton pour entrer dans le produit.
PourquoiUn bouton isolé et généreux laisse la vague s'étirer : à 20 px de texte, le saut de 8 px et la rotation de 5° se voient sans être exagérés, et le mouvement clôt le parcours sur une note positive.
RéglagesTexte 20 px, padding: 18px 48px, durée .6s, décalage 0.035s, ombre au survol portée à 0 14px 36px.

Comment ça marche

Le script parcourt chaque [data-split-text], lit son textContent, vide l'élément et recrée un <span class="split-char"> par caractère. Les espaces deviennent des espaces insécables (\u00A0) pour ne pas s'effondrer dans un inline-block, et chaque span reçoit style="animation-delay: n × 0.03s" selon son rang : 0 s pour la première lettre, 0,27 s pour la dixième. « Split Text » donne 10 spans en 136 px.

Côté CSS, .split-char est en display: inline-block (condition pour qu'un transform agisse) et .btn-split-text force overflow: visible — contrairement aux autres boutons du catalogue — pour que les lettres puissent sortir de la boîte. Au :hover, chaque span reçoit une animation de .5s cubic-bezier(.68, -.55, .265, 1.55), une seule itération, forwards ; :nth-child(2n+1) prend splitTextUp (50 % : translateY(-8px) rotate(-5deg)) et :nth-child(2n) prend splitTextDown (50 % : translateY(8px) rotate(5deg)). Début et fin sont à zéro : chaque lettre part et revient à sa place.

La courbe à dépassement s'applique à chaque moitié du trajet : la lettre dépasse ses 8 px puis revient, ce qui fait le rebond. Le décalage de 30 ms fait courir une vague le long du mot : la dernière lettre finit 0,27 s après la première, l'ensemble dure 0,77 s puis se fige (l'animation ne rejoue qu'en quittant et reprenant le survol). Le bouton lui-même se soulève de 2 px avec une ombre 0 10px 30px rgba(20,184,166,.4) en .3s.

Le script attend un bouton en texte brut. Ne l'appliquez jamais à un bouton déjà découpé en spans sur plusieurs lignes (par exemple le HTML récupéré après exécution du script) : il redécouperait aussi les retours à la ligne et les espaces d'indentation. Mesuré dans Chromium sur un tel bouton : 63 spans au lieu de 10, une largeur de 323 px au lieu de 136 (chaque espace d'indentation devient un espace insécable visible), des délais de 0,15 à 1,77 s, et toutes les lettres tombent sur un rang pair, donc toutes descendent — plus aucune alternance. Une seule source : soit <button class="demo-btn btn-split-text" data-split-text>Split Text</button> avec le script, soit un bouton pré-découpé sans le script.

Accessibilité

  • Contraste insuffisant dans la version fournie : texte blanc sur le dégradé #14b8a6 → #0d9488 = 2,49:1 et 3,74:1, sous le seuil AA de 4,5:1 et, pour la première teinte, sous le seuil de 3:1 des grands textes. Passez à linear-gradient(135deg, #0f766e, #115e59) (5,5:1 et 7,6:1).
  • Lecteurs d'écran : un libellé découpé en dix <span> inline-block est parfois épelé ou coupé en mots aléatoires (« Spl it Te xt ») par VoiceOver et NVDA. Donnez au bouton un nom accessible entier : dans le script, avant de vider l'élément, t.setAttribute('aria-label', e.trim()) — les spans deviennent alors purement décoratifs.
  • prefers-reduced-motion absent du code : ajoutez @media (prefers-reduced-motion: reduce) { .btn-split-text:hover .split-char { animation: none } .btn-split-text { transition: none } }. Le bouton reste identique, sans vague ni soulèvement.
  • Clavier : pas de :hover à la navigation Tab. Dupliquez les trois règles de survol sous .btn-split-text:focus-visible (l'animation des spans et le soulèvement) pour que le focus déclenche la même vague. L'outline natif n'est pas retiré.
  • Tactile : effet exclusivement souris ; sur iOS l'état survolé (bouton soulevé) reste collé après un tap — enveloppez les règles dans @media (hover: hover). Cible ≈ 50 px de haut, au-dessus du minimum de 44 px. overflow: visible laisse les lettres déborder de 8 px + rotation : prévoyez 12 px libres au-dessus et au-dessous.

Compatibilité navigateur

Requiert ES2015 (fonctions fléchées), NodeList.forEach, les animations CSS de transform et :nth-child(an+b) — tous les navigateurs depuis 2016. Zéro dépendance.

Chrome 51+✓ Complet
Firefox 50+✓ Complet
Safari 10+✓ Complet
Edge 79+✓ Complet
Mobile iOS✓ Statique (pas de survol)
Android Chrome✓ Statique (pas de survol)

Sans JavaScript, un bouton en texte brut reste un bouton dégradé ordinaire qui se soulève au survol : aucune lettre ne bouge. Un bouton pré-découpé en spans (avec ses animation-delay en ligne) fonctionne en revanche sans aucun script. Sans animations CSS, les lettres restent immobiles.

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
Décalage entre lettres (JS — .03 * n) 0.03s Vitesse de la vague. 0.015s = les lettres sautent presque ensemble ; 0.08s = ola lente, qui dure 0,7 s sur dix lettres avant même le rebond.
animation-duration (CSS — :hover .split-char) .5s Durée du saut de chaque lettre. .35s = sec ; .8s = mou. La vague totale = durée + décalage × (nombre de lettres − 1).
translateY (CSS — @keyframes splitTextUp / splitTextDown, 50 %) −8px / +8px Amplitude du saut. ±4px = frémissement ; ±14px = les lettres quittent la boîte, prévoyez la place (overflow: visible).
rotate (CSS — @keyframes, 50 %) −5deg / +5deg Inclinaison au sommet du saut. 0deg = pur rebond vertical ; ±12deg = lettres qui basculent, moins lisibles pendant 0,25 s.
cubic-bezier(.68, -.55, .265, 1.55) (CSS — animation) courbe à dépassement Appliquée à chaque moitié du saut : la lettre dépasse ses 8 px puis revient. ease-in-out à la place donne un saut propre sans rebond.
Alternance (CSS — :nth-child(2n+1) / :nth-child(2n)) haut / bas Direction par rang. Mettez splitTextUp aux deux sélecteurs pour une vague entièrement vers le haut ; :nth-child(3n) pour une lettre sur trois.
background (CSS — .btn-split-text) linear-gradient(135deg, #14b8a6, #0d9488) Couleur du bouton. Pour un contraste AA avec le texte blanc : #0f766e → #115e59. L'ombre du survol (rgba(20,184,166,.4)) est à recolorer avec.

FAQ

Le script a été appliqué à un bouton déjà découpé en spans, écrits sur plusieurs lignes. Il relit le textContent, qui contient les sauts de ligne et les espaces d'indentation, et crée un span par caractère — y compris pour chaque espace, converti en espace insécable visible. Résultat mesuré : 63 spans, un bouton 2,4 fois plus large, et chaque lettre à un rang pair (donc splitTextDown pour toutes). Repartez d'un bouton en texte brut : <button class="demo-btn btn-split-text" data-split-text>Votre texte</button>, et laissez le script découper.
Oui : déplacez la déclaration animation et les deux animation-name de .btn-split-text:hover .split-char vers .btn-split-text .split-char. Pour une boucle, remplacez 1 par infinite et ajoutez une pause entre deux vagues en allongeant les keyframes (le saut entre 0 % et 30 %, immobilité jusqu'à 100 %). Pensez alors à prefers-reduced-motion : une vague permanente est bien plus intrusive qu'une vague au survol.
Le script vide tout l'élément [data-split-text] et ne recrée que du texte : une icône SVG ou un <span> enfant disparaîtrait. Posez data-split-text non pas sur le bouton mais sur un <span> qui n'enveloppe que le libellé, et placez l'icône à côté : <button class="btn-split-text"><span data-split-text>Jouer</span> ▶</button>. Adaptez alors les sélecteurs CSS (.btn-split-text:hover .split-char fonctionne tel quel, les spans restant des descendants).