Animer du Texte avec des SVG
Vous avez sûrement déjà croisé, sur un site soigné, du texte qui s'écrit tout seul, trait après trait, comme tracé à la main sous vos yeux. C'est élégant, ça capte le regard, et le plus beau : ça se fait nativement, sans librairie, grâce à une simple astuce sur les chemins (paths) SVG. Ce post a pour but de vous expliquer, le plus simplement possible, comment créer cet effet, du concept de base jusqu'à une version propre avec React et GSAP.
Animation SVG Signature
L'idée est là : le texte se dessine sous vos yeux, avec un contrôle précis sur chaque trait et chaque lettre. Voyons d'abord pourquoi le SVG est indispensable pour cet effet, puis comment l'animer pas à pas.
Pourquoi utiliser des SVGs au lieu du CSS/HTML classique ?
Le CSS et les balises HTML classiques (<h1>, <p>, etc.) ne permettent pas de créer cet effet de dessin progressif pour plusieurs raisons :
Limitations du texte HTML
-
Le texte HTML est rendu comme des glyphes : Le navigateur affiche les lettres comme des formes pré-rendues (glyphes de police), pas comme des chemins animables. Une fois rendu, le texte devient une image statique.
-
Pas d'accès aux coordonnées de dessin : On ne peut pas connaître la longueur du "trait" d'une lettre pour l'animer. Le navigateur ne nous donne pas accès à ce genre d'outils.
-
Limitations CSS : Les propriétés
stroke-dasharrayetstroke-dashoffsetfonctionnent uniquement sur les éléments SVG<path>, pas sur le texte HTML. Ces propriétés sont essentielles pour créer l'effet de dessin progressif.
Avantages des chemins (paths) SVG
Les chemins SVG résolvent tous ces problèmes en représentant le texte comme des coordonnées mathématiques (attribut d), ce qui permet de :
- Calculer la longueur totale : Avec
getTotalLength(), on obtient la longueur exacte du chemin en pixels - Animer progressivement : On peut animer le trait le long du chemin de manière précise
- Contrôler chaque point : Chaque point du dessin est accessible et animable
- Créer des effets complexes : Possibilité d'animer plusieurs chemins simultanément ou séquentiellement
Les attributs clés pour l'animation :
-
stroke-dasharray: Définit le motif de tirets du trait. Par exemple,stroke-dasharray="10 5"crée des tirets de 10px suivis d'espaces de 5px. En utilisant la longueur totale du chemin comme valeur, on crée un seul long tiret qui couvre tout le chemin. -
stroke-dashoffset: Déplace le point de départ du motif de tirets le long du chemin. Une valeur positive décale le motif vers la fin du chemin, une valeur négative vers le début. En animant cette valeur de la longueur du chemin vers 0, on crée l'effet de dessin progressif.
Pour plus de détails, voir : stroke-dasharray et stroke-dashoffset sur MDN.
Mais comment convertir du texte en SVG ?
Le problème que l'on rencontre le plus rapidement en voulant faire ce genre d'animation est la conversion du texte en SVG. Pour cela il existe un merveilleux outil open source et gratuit créé par danmarshall permettant de convertir du texte en SVG : Google Font to SVG Path Converter :
Cet outil va nous permettre de :
- Sélectionner une police Google Font ou d'en importer une et entrer notre texte
- Voir le rendu de notre texte en SVG
- Voir et copier le code SVG généré
Dès que vous avez votre code SVG vous allez pouvoir passer à l'implémentation de l'animation.
Exemple Simple d'Implémentation
Voici un exemple minimaliste pour comprendre les concepts de base :
Animation SVG Simple
HTML :
<svg width="62" height="71.1" viewBox="0 0 62 71.1" xmlns="http://www.w3.org/2000/svg">
<path
class="path"
d="M 36.4 71.1 L 25.7 71.1 L 0 3.6 L 9.3 0 L 31.3 60.7 L 53.4 0.3 L 62 3.6 L 36.4 71.1 Z"
/>
</svg>
.path {
stroke: #000;
stroke-width: 0.25mm;
fill: none;
}
J'ai ici récupéré le code SVG généré par l'outil de conversion et ajouté une class à la balise <path> pour pouvoir y accéder plus facilement avec JavaScript et lui appliquer les styles CSS en lui donnant des valeurs par défaut.
JavaScript :
const path = document.querySelector('.path');
const length = path.getTotalLength();
path.style.strokeDasharray = length;
path.style.strokeDashoffset = length; // Commence caché
const duration = 2000; // 2 secondes
const startTime = Date.now();
function animate() {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
path.style.strokeDashoffset = length * (1 - progress); // De length vers 0
if (progress < 1) {
requestAnimationFrame(animate);
}
}
animate();
Points clés à comprendre
-
getTotalLength(): Obtient la longueur totale du chemin en pixels. -
strokeDasharray = length: Crée un tiret de la même longueur que le chemin entier. -
strokeDashoffset: On anime cette valeur delength(chemin caché) vers0(chemin visible). En diminuant progressivement, le tiret "glisse" le long du chemin, révélant le dessin progressivement. -
requestAnimationFrame: Synchronise l'animation avec le navigateur (~60fps) pour une animation fluide.
Maintenant que vous avez compris le principe de base, vous pouvez passer à l'implémentation complète avec React et GSAP.
Solution complète avec React et GSAP
Il est temps de passer à l'implémentation complète avec React et GSAP de notre animation :) !
Implémentation React
"use client";
import { useGSAP } from "@gsap/react";
import gsap from "gsap";
import { useRef } from "react";
export default function AnimatedText({ height = 120 }: { height?: number }) {
const pathRefs = useRef<(SVGPathElement | null)[]>([]);
useGSAP(() => {
pathRefs.current.forEach((path) => {
if (!path) return;
const length = path.getTotalLength();
path.style.strokeDasharray = length.toString();
path.style.strokeDashoffset = length.toString();
// Dessiner le trait
gsap.to(path, {
strokeDashoffset: 0,
duration: 4,
ease: "power2.in",
});
// Remplir après que le trait soit terminé
gsap.to(path, {
delay: 2,
fill: "#FFFCF2",
duration: 2,
ease: "power2.in",
});
});
}, []);
return (
<svg width="auto" height={height} viewBox="0 0 248.295 172.203">
<path
ref={(el) => {
pathRefs.current[0] = el;
}}
fill="none"
stroke="#FFFCF2"
d="M 151.601 0 L 151.801 0.2..."
/>
</svg>
);
}
Avantages de cette Approche
useGSAP: Hook React qui gère automatiquement le nettoyage des animations lors du démontage du composant- GSAP : Bibliothèque d'animation puissante avec des easing naturels (
power2.inpour une décélération fluide) - Animation en deux étapes : D'abord le trait, puis le remplissage pour un effet complet.
Animer Plusieurs Chemins
Pour plusieurs mots ou lettres, animez-les simultanément ou en cascade. La seule différence tient à un delay calculé à partir de l'index :
// Toutes en même temps
pathRefs.current.forEach((path) => {
gsap.to(path, {
strokeDashoffset: 0,
duration: 2,
ease: "power2.in",
});
});
// Les unes après les autres (effet cascade)
pathRefs.current.forEach((path, index) => {
gsap.to(path, {
strokeDashoffset: 0,
duration: 2,
delay: index * 0.4, // chaque chemin démarre 0,4 s après le précédent
ease: "power2.in",
});
});
C'est tout, et c'est volontairement court : l'essentiel est de retenir qu'on peut créer ce genre d'animation nativement, avec une seule astuce SVG et quelques lignes de JavaScript. Le reste n'est qu'affaire d'imagination, à vous de jouer :)