Text Reveal
Quatre blocs titre + sous-titre dans une boîte de 280 px : chaque mot (1,5 rem, graisse 800) part à translateY(100 %) sous une ligne en overflow: clip et remonte sur les 40 % de son entrée dans la boîte — 11 px de défilement —, puis son sous-titre passe de 0 à 1 sur les 10 → 50 % de sa propre entrée, 37 px plus bas. Deux animations CSS sur animation-timeline: view(), zéro JavaScript.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Scroll comprend 70 effets, dont 12 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Le HTML vendu : un cadre .demo-preview (flex centré, min-height: 300px, position: relative, fond #0a0a0f, texte blanc, font-family: sans-serif), la boîte .sdc-scroll-container (100% × 280px, overflow-y: auto, scroll-behavior: smooth, barre de 4 px stylée par ::-webkit-scrollbar, pouce violet à 40 %), le plateau .sdc-textreveal-content (900 px de haut, padding: 80px 24px, colonne flex, gap: 40px) et quatre div contenant chacun une ligne .sdc-textreveal-line (overflow: clip) qui masque un span.sdc-textreveal-word (inline-block, 1,5 rem = 24 px, graisse 800, blanc, 28 px de haut) et un p.sdc-textreveal-sub (0,82 rem = 13 px, blanc à 40 %, margin-top: 8px). Sous la boîte, span.sdc-scroll-hint « Scrollez ↓ » (absolu, 8 px du bas du cadre, 10,4 px, blanc à 30 %) pulse de .3 à .7 toutes les 2 s. Mesuré en page vierge : course 900 − 280 = 620 px, mots à 80, 184, 288 et 392 px du haut du plateau — un pas de 104 px, car la marge basse par défaut du p (13 px) s'ajoute aux 28 + 8 + 15 px du bloc et aux 40 px de gap. Aucun JavaScript, aucun id, aucune variable CSS, aucune erreur console.
Les deux textes partagent le même réglage : animation-timeline: view(), animation-duration: auto, animation-fill-mode: both, courbe linéaire. view() crée pour chaque élément une chronologie anonyme lue sur le conteneur de défilement le plus proche — ici la boîte — et graduée sur la traversée de son cadre par l'élément ; animation-range choisit le segment qui pilote les images-clés. Le mot part à translateY(100%) (100 % de sa hauteur, 28 px, sous sa ligne qui le rogne) et opacity: 0, et rejoint translateY(0) / 1 sur entry entry 40% : de l'instant où son bord haut touche le bas de la boîte jusqu'à 40 % de son entrée, soit 11,2 px de défilement. Mesuré par crans de 8 px dans Chromium 151 : le troisième mot est à 0 / 28 px à scrollTop 8, à .69 / 8,6 px à 16, à 1 / 0 à 24 ; le quatrième fait le même trajet entre 112 et 128. Le sous-titre n'a pas de transform de départ (le translateY(0) de sdcFadeIn ne change rien) : il passe de 0 à 1 sur entry 10% entry 50%, 40 % de ses 15 px, soit 6 px (mesuré .38 à 48, 1 à 56 pour le troisième ; .35 à 152, 1 à 160 pour le quatrième). Le décalage titre → détail vient de la géométrie plus que des pourcentages : le sous-titre entre dans la boîte 36 px après le mot (28 px de mot + 8 px de marge), et ses 10 % n'ajoutent que 1,5 px. Passé scrollTop 160, tout est visible ; il reste 460 px de course vide.
Jusqu'au 30 septembre 2026, la ligne était en overflow: hidden, et le masque ne s'est jamais ouvert : un élément en overflow: hidden est un conteneur de défilement, donc view() s'accrochait à la ligne elle-même, dont le mot remplit le cadre dès le départ. Mesuré sur ce code : getAnimations()[0].timeline.source = .sdc-textreveal-line, animation finished figée à 20 %, les quatre mots à opacité 1 et sans transform au repos — même celui posé à 392 px, hors de la boîte. Seuls les sous-titres, enfants directs des blocs, se rattachaient à la boîte et apparaissaient. overflow: clip rogne à l'identique sans créer de conteneur de défilement : la source devient .sdc-scroll-container et le mot sort de sa ligne. Autres traits du code : rien n'est indexé par id, chaque mot porte sa propre chronologie, donc plusieurs copies cohabitent dans une page et un cinquième bloc s'ajoute sans CSS ; scroll-behavior: smooth ne lisse que les défilements programmés ; la police est le sans-serif du système (rien n'est chargé) ; et le champ JavaScript du code vendu est vide.
Accessibilité
- prefers-reduced-motion absent du code : mesuré sous la préférence dans Chromium, le troisième mot passe toujours de 0 à 1 entre scrollTop 8 et 24, l'indice pulse (
animation-play-state: running) etscroll-behaviorrestesmooth. Le mouvement suit le geste et ne cache rien de durable — un bloc entré dans la boîte reste affiché —, ce qui le range dans les animations déclenchées par l'interaction (WCAG 2.3.3). Pour un repli sans mouvement :@media (prefers-reduced-motion: reduce) { .sdc-textreveal-word, .sdc-textreveal-sub { animation: none; opacity: 1; transform: none } .sdc-scroll-hint { animation: none } .sdc-scroll-container { scroll-behavior: auto } }. - Clavier : mesuré, Tab donne le focus à la boîte sans
tabindexdans Chromium et Firefox (flèche bas : 40 et 51 px, PageDown : 285 et 303 px — la révélation suit), pas dans WebKit (focus resté surbody, flèches sans effet). Ajouteztabindex="0", unaria-label(« Quatre mots, défilement vertical ») et un style:focus-visiblesur.sdc-scroll-container. Au doigt, le geste doit commencer dans la boîte ;overscroll-behavior: containévite d'entraîner la page en bout de course. - Contraste : le mot blanc sur
#0a0a0fmesure 19,8:1. Le sous-titre à 40 % de blanc vaut 3,8:1 à 13 px — sous les 4,5:1 exigés pour un texte de cette taille ; 60 % (rgba(255,255,255,.6)) donne 7,3:1. L'indice mesure 2,6:1 au repos, de 1,2:1 à 1,8:1 sous la pulsation (l'opacité de .3 à .7 se multiplie au blanc à 30 % de la couleur) : décoratif, posez-luiaria-hidden="true". Le fond#0a0a0fdu cadre fait partie du code : sur une page blanche, retirez-le et le texte blanc disparaît (1:1) — changez alors les trois couleurs, comme la troisième scène sur papier clair. - Lecteurs d'écran et structure :
opacity: 0ne retire rien de l'arbre d'accessibilité, les huit textes sont lus dans l'ordre, avant comme après le défilement, et rien n'est annoncé au passage — il n'y a rien à annoncer. Le mot est unspandans undiv, le sous-titre unp: aucun titre dans le plan de la page. Pour des noms de salle ou d'épreuve, mettez le mot dans unh2ouh3(la classe suffit, la balise est libre) et gardez lep. Le libellé « Scrollez ↓ » est écrit en français dans le HTML, quelle que soit la langue de la page.
Compatibilité navigateur
CSS seul : animation-timeline: view(), animation-duration: auto, animation-range avec les repères entry — les animations pilotées par le défilement, arrivées dans Chrome et Edge 115 (juillet 2023) et Safari 26 (septembre 2025). Firefox ne les rend dans aucune version : mesuré dans Firefox 153, CSS.supports('animation-timeline: view()') répond faux, animation-duration: auto est rejeté (durée calculée 0 s) et l'animation, finished sur une chronologie de document, applique sa dernière image-clé — les huit textes sont affichés à opacité 1, sans transform, dès le repos, et la boîte défile normalement (course 620 px). Un visiteur Firefox voit donc une liste statique et complète, sans le glissement. ::-webkit-scrollbar est ignoré par Firefox (barre native). Zéro dépendance, zéro script.
Là où animation-timeline et animation-duration: auto sont inconnus (Firefox, Safari avant 26, Chrome avant 115), les deux déclarations tombent, l'animation dure 0 s et animation-fill-mode: both la fige sur sa dernière image-clé : opacité 1, translateY(0). Le code n'a pas de bloc @supports et n'en a pas besoin, parce que l'état final est l'état lisible ; il en faudrait un — @supports not (animation-timeline: view()) { … } — si vous inversiez les images-clés (texte qui s'efface) ou si la fin de sdcTextReveal cessait d'être l'état de lecture. Sans overflow: clip (Chrome avant 90, Firefox avant 81, Safari avant 16), la ligne ne rogne plus rien, mais aucun mot n'y est translaté : rien ne change à l'écran.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :
<div class="demo-preview">
<div class="sdc-scroll-container">
<div class="sdc-textreveal-content">
<div>
<div class="sdc-textreveal-line">
<span class="sdc-textreveal-word">…</span>
</div>
<p class="sdc-textreveal-sub">…</p>
</div>
<div>
<div class="sdc-textreveal-line">
<span class="sdc-textreveal-word">…</span>
</div>
<p class="sdc-textreveal-sub">…</p>
</div>
<div>
<div class="sdc-textreveal-line">
<span class="sdc-textreveal-word">…</span>
</div>
<p class="sdc-textreveal-sub">…</p>
</div>
<div>
<div class="sdc-textreveal-line">
<span class="sdc-textreveal-word">…</span>
</div>
<p class="sdc-textreveal-sub">…</p>
</div>
</div>
</div>
<span class="sdc-scroll-hint">…</span>
</div>
Le code complet HTML + CSS + JS de Text Reveal, prêt à coller — et les 811 effets. Ou 299 € une fois, accès à vie.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Plage du mot (CSS — .sdc-textreveal-word { animation-range: entry entry 40% }) |
entry 0 % → entry 40 % (11,2 px pour un mot de 28 px) | Les pourcentages sont ceux de l'entrée du mot dans la boîte, donc proportionnels à sa hauteur, pas à celle de la boîte. entry 0% entry 100% étire la sortie sur toute l'entrée (28 px, le réglage des trois scènes) ; entry 0% cover 30% la prolonge jusqu'à ce que le mot ait gravi 30 % de la boîte (environ 92 px). |
Plage du sous-titre (CSS — .sdc-textreveal-sub { animation-range: entry 10% entry 50% }) |
entry 10 % → entry 50 % (6 px pour 15 px de haut) | Le retard sur le mot vient surtout des 36 px qui séparent leurs entrées ; les 10 % n'ajoutent que 1,5 px. Pour un vrai temps mort, retardez le début (entry 100% cover 30%) ou augmentez margin-top. |
Départ du mot (CSS — transform: translateY(100%) et opacity: 0) |
100 % de sa hauteur (28 px), invisible | Le mot part entièrement sous sa ligne. translateY(60%) le laisse dépasser d'un tiers avant le défilement ; opacity: 1 dans la règle de base donne une sortie de masque pure, sans fondu — l'image-clé finale reste valable. |
Boîte et plateau (CSS — .sdc-scroll-container { height: 280px }, .sdc-textreveal-content { height: 900px }) |
280 px / 900 px (course 620 px, tout révélé à 160 px) | Le plateau est fixé à 900 px quel que soit le contenu : 460 px de course vide après le dernier bloc. height: auto avec un padding-bottom d'au moins la moitié de la boîte laisse le dernier bloc entrer complètement (les scènes : 110 à 150 px). |
Taille et couleurs (CSS — font-size: 1.5rem, color: #fff ; .sdc-textreveal-sub : .82rem, rgba(255,255,255,.4)) |
24 px / 800 / blanc ; 13 px / blanc à 40 % | La plage suit la hauteur du mot : à 44 px (scène 2), les 40 % font 18 px de course. Le sous-titre à 40 % vaut 3,8:1 sur #0a0a0f ; 60 % passe à 7,3:1. Sur fond clair, changez les trois couleurs et retirez le fond du cadre. |
Masque de ligne (CSS — .sdc-textreveal-line { overflow: clip }) |
clip | À garder tel quel : hidden ferait de la ligne un conteneur de défilement et view() s'y rattacherait — les mots ne bougeraient plus (c'était le défaut du code avant le 30/09/2026). La ligne accepte un filet (border-top, scène 3) ou un padding-top sans rien casser. |
Indice et barre (CSS — .sdc-scroll-hint, ::-webkit-scrollbar) |
« Scrollez ↓ » à 8 px du bas, barre de 4 px | L'indice s'accroche au cadre .demo-preview (position: relative) : sans ce cadre, il tombe au bas de la page — supprimez le span et la @keyframes sdcHintPulse. La barre ne concerne que Chrome et Safari ; scrollbar-width: thin couvre Firefox. |
FAQ
overflow: hidden — le code vendu jusqu'au 30 septembre 2026, et encore la copie affichée dans la page catégorie. Un élément en overflow: hidden est un conteneur de défilement ; view() prend le plus proche, donc la ligne, où le mot occupe tout le cadre : l'animation est terminée avant le premier geste (mesuré : source de la chronologie = .sdc-textreveal-line, état finished figé à 20 %, quatre mots à opacité 1 au repos). La règle vaut pour tout ancêtre entre le mot et la boîte : une carte en overflow: hidden, un accordéon, un carrousel captent la chronologie de la même façon. Remplacez par overflow: clip (ou clip-path: inset(0)), qui rogne sans créer de conteneur, et vérifiez avec el.getAnimations()[0].timeline.source que la source est bien la boîte.animation-range: entry entry 40% est mesuré sur l'entrée du mot, c'est-à-dire sur sa propre hauteur : 40 % de 28 px font 11,2 px de défilement, et 6 px pour le sous-titre. Un cran de molette de 100 px les traverse en une ou deux images ; au pavé tactile ou au doigt, le glissement se voit. Mesuré par pas de 8 px : 0 → .69 → 1 sur trois relevés. Pour l'étirer, élargissez la plage (entry 0% entry 100% : 28 px, le choix des trois scènes ; entry 0% cover 30% : environ 92 px, le mot finit de sortir alors qu'il est déjà bien dans la boîte) ou augmentez la taille du mot — la plage grandit avec lui. Ne touchez pas à animation-duration: auto : avec une chronologie de défilement, c'est la plage qui tient lieu de durée.animation-timeline: view(), animation-duration: auto, animation-range, zéro JavaScript, Firefox à plat dans les deux cas — mais pas le geste. fx-0569 aligne 43 mots inline-block dans un paragraphe de 300 px et n'anime que leur color : de blanc à 15 % à #e0e7ff (les six accents de violet à 20 % à #a78bfa) sur entry cover 40%, une seule plage pour tous. Les mots sont en place dès le départ et s'allument en glissant vers le haut de la boîte — une lecture qui s'éclaire. fx-0560 travaille par paire : un mot qui se déplace (translateY(100%) → 0) derrière un masque de ligne, puis un sous-titre qui apparaît sur une seconde plage, 36 px plus bas. Il fait quatre titres avec leur détail, là où fx-0569 fait un texte courant. Prenez fx-0569 pour un paragraphe à lire, fx-0560 pour une liste de titres courts que chaque détail suit.