Scroll✨ Premium

Sticky Horizontal

Cinq panneaux de la largeur du cadre sur une piste flex, poussée par un seul @keyframes de 12 s en boucle infinie : 2,16 s d'arrêt par panneau, 240 ms de glissement linéaire, puis 600 ms de rembobinage qui retraversent les quatre panneaux. Ni scroll, ni JavaScript, ni écouteur : mesuré, molette, survol et clic n'y changent rien — le bandeau tourne même sur un écran que personne ne touche.

CSSAnimationAuto-play

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. Scroll comprend 70 effets, dont 12 gratuits. Découvrir la catégorie →

3 exemples d'usage

Accueil d'un sous-traitant automobile — le bandeau de certifications tourne seul — Sticky Horizontal exemple 1

① Accueil d'un sous-traitant automobile — le bandeau de certifications tourne seul

QuandPage d'accueil ou écran du hall d'un atelier de mécanique : en-tête, accroche, deux boutons, et en bas les certifications (ISO 9001, IATF 16949, ISO 14001, marquage CE, ISO 45001) qui passent une à une.
PourquoiLe visiteur lit l'accroche, le bandeau tourne sans lui ; sur l'écran du hall ou sur une borne, personne ne fera jamais le geste qu'exige Horizontal Scroll (fx-0541, défilement natif à la main). L'horloge CSS suffit, et cinq certifications lues 4 s chacune valent mieux que cinq logos serrés sur une ligne.
RéglagesCycle porté à 24s (4,3 s par certification, glissement de 480 ms), height: 112px sur le cadre, .panel-number à 1.75rem en dégradé #7dd3fc → #c7d2fe, fonds acier (#0f1a2b → #16324d…), padding: 16px 24px et gap: 6px. Sur la version web, ajouter la pause au survol.
Borne de commande rapide — les offres du jour tournent pendant le choix — Sticky Horizontal exemple 2

② Borne de commande rapide — les offres du jour tournent pendant le choix

QuandÉcran de borne : à gauche l'étape « Choisissez votre plat » (grille de plats, panier), à droite une colonne de 220 px où les formules du jour se succèdent — menu midi 11,90 €, dessert offert, −20 % en happy hour, menu enfant, cookies 1 + 1.
PourquoiLe client est en train de composer sa commande : un carrousel à balayer (Card Snap Carousel, fx-0595) exigerait qu'il interrompe son geste ; ici la colonne change d'elle-même toutes les 4 s et c'est le prix, en 40 px, qui attire l'œil sans rien demander. Rien ne se passe au toucher — sur une borne, c'est voulu.
RéglagesCycle 20s (3,6 s par offre, glissement de 400 ms), cadre à la hauteur vendue de 280 px dans une colonne de 220 px — les panneaux suivent, min-width: 100% —, chiffre en #fde68a → #fb923c, libellé à .9rem et 78 % de blanc, fonds chauds par nth-child.
Écran d'atelier — le flux de production défile sans opérateur — Sticky Horizontal exemple 3

③ Écran d'atelier — le flux de production défile sans opérateur

QuandÉcran fixe en salle de production : bandeau « Ligne 3 · Atelier B », heure et cadence, puis les postes (A découpe, B pliage, C soudure, D contrôle, expédition) qui passent avec leur compteur de pièces et un état « en cadence » ou « retard ».
PourquoiPersonne ne touche cet écran pendant le travail : les autres défilements horizontaux de la catégorie demandent un scroll ou un balayage (fx-0567 en animation-timeline, fx-0541 et fx-0586 en scroll-snap) — un @keyframes en boucle est le seul qui tourne à vide. Vu de loin, un poste toutes les 5 s se lit ; un retard passe en ambre sans que le reste change.
RéglagesCycle 30s (5,4 s par poste, glissement de 600 ms), cadre de 280 px pleine largeur, .panel-number vendu (2,5 rem) en #67e8f9 → #a5b4fc, et en #fde68a → #fb923c pour le poste en retard (:nth-child(3) .panel-number), libellé à 1rem et 80 % de blanc, une pastille d'état ajoutée sous le libellé.

Comment ça marche

Anatomie : .sticky-h-viewport (width: 100%, height: 280px, overflow: hidden) contient .sticky-h-track, une boîte flex de la hauteur du cadre, qui aligne cinq .sticky-h-panel en min-width: 100% : chaque panneau mesure la largeur de la piste — donc celle du cadre — et les cinq débordent quatre fois à droite (mesuré sur une page vierge de 800 px : cadre 784 px, piste 784 px, scrollWidth 3 920 px). Chaque panneau est une colonne flex centrée (gap: 12px, padding: 24px) qui porte un chiffre .panel-number2.5rem soit 40 px, font-weight: 800, dégradé #a855f7 → #ec4899 découpé dans les glyphes par background: … text et -webkit-text-fill-color: transparent — et un libellé .panel-label (.85rem, 13,6 px, blanc à 50 %). Cinq fonds par nth-child, un dégradé à 135° chacun : #0f0f23 → #1a1a3e, #1a0f23 → #2d1a3e, #0f1a23 → #1a2d3e, #1a230f → #2d3e1a, #230f1a → #3e1a2d.

L'horloge : animation: 12s linear 0s infinite normal none running slideHorizontal sur la piste. Les images-clés posent translateX(0) de 0 à 18 %, -100% de 20 à 38 %, -200% de 40 à 58 %, -300% de 60 à 78 %, -400% de 80 à 95 %, puis 0 à 100 %. Les pourcentages de translateX se rapportent à la largeur de la piste elle-même, c'est-à-dire à un panneau : chaque palier décale d'un panneau exactement. Chronologie mesurée, identique dans Chromium, Firefox et WebKit : panneau 1 de 0 à 2,16 s, glissement de 2,16 à 2,40 s (784 px en 240 ms, 3,3 px/ms, linear donc sans amorti), panneau 2 de 2,40 à 4,56 s, panneau 3 de 4,80 à 6,96 s, panneau 4 de 7,20 à 9,36 s, panneau 5 de 9,60 à 11,40 s — 1,8 s seulement, son palier ne fait que 15 %. De 95 à 100 %, la piste revient de -400% à 0 en 600 ms : un rembobinage qui traverse les panneaux 4, 3 et 2 à l'envers à 5,2 px/ms (mesuré : -300% à 11,55 s, -200% à 11,7 s, -100% à 11,85 s). Le cycle repart sur le panneau 1 à 12,0 s.

Ce que le code n'est pas : il n'y a ni position: sticky, ni conteneur défilable, ni JavaScript (la clé js est vide), ni id, ni variable CSS, ni écouteur. Mesuré : 1 000 ms d'horloge murale font 1 000 ms d'animation ; cinq crans de molette de 120 px à la verticale puis à l'horizontale sur le cadre laissent scrollLeft et scrollTop à 0 et l'animation running ; le survol la laisse running ; le clic aussi. Seule transform change : le mouvement reste sur le compositeur, aucune mise en page par image. La conséquence est double : la chronologie ne dépend de rien (écran d'accueil, borne, mur d'atelier), et elle n'obéit à rien — rien ne la met en pause, rien ne ramène un lecteur au panneau précédent. Trois restes du catalogue : le prélude .demo-preview (min-height: 300px, centrage flex) laisse deux bandes de 10 px de #0a0a0f au-dessus et au-dessous du cadre de 280 px ; les libellés « Decouverte », « Creation », « Iteration » sont écrits sans accent ; le nom slideHorizontal est générique — un autre @keyframes du même nom déclaré plus bas dans la page remplacerait celui-ci.

Accessibilité

  • prefers-reduced-motion absent du code : mesuré avec la préférence activée, l'animation est running et la chronologie identique (2,16 s, 240 ms, rembobinage de 600 ms). Ajoutez @media (prefers-reduced-motion: reduce) { .sticky-h-track { animation: none } } — mais seul, ce repli ne laisse que le premier panneau visible : complétez par .sticky-h-viewport { overflow-x: auto; scroll-snap-type: x mandatory } et .sticky-h-panel { scroll-snap-align: start }, l'horloge s'arrête et les cinq panneaux restent atteignables au doigt ou à la molette.
  • Ni pause ni arrêt (WCAG 2.2.2 : un contenu qui bouge seul plus de 5 s doit pouvoir être mis en pause) : aucun bouton, aucun survol — mesuré, animation-play-state reste running sous le pointeur. Le minimum tient en une règle : .sticky-h-viewport:hover .sticky-h-track, .sticky-h-viewport:focus-within .sticky-h-track { animation-play-state: paused } ; mieux, un bouton qui pose une classe .is-paused. Sur un écran sans utilisateur — kiosque, mur d'atelier — la règle n'a pas d'objet, et c'est précisément là que cet effet est à sa place.
  • Contraste : le libellé blanc à 50 % mesure de 4,17:1 (panneau 4, extrémité #2d3e1a) à 5,31:1 sur les cinq fonds — conforme partout sauf sur le bord clair du panneau 4 (seuil 4,5:1). Le chiffre, 40 px en gras, est un grand texte (seuil 3:1) : 3,56 à 5,35:1 sur les panneaux 1, 2, 3 et 5, mais 2,92:1 pour l'extrémité rose #ec4899 sur le panneau 4. Sur une page claire, si les panneaux perdent leurs fonds sombres, le libellé disparaît (blanc sur blanc) : remplacez rgba(255, 255, 255, .5) par une couleur pleine.
  • Lecteurs d'écran et clavier : les cinq panneaux restent dans le DOM et dans l'arbre d'accessibilité quelle que soit leur position — un lecteur lit les cinq libellés dans l'ordre, rien n'est annoncé au changement de panneau puisque rien ne change dans le DOM. Pour un bandeau décoratif, posez aria-hidden="true" sur .sticky-h-viewport. Si vous mettez des liens dans les panneaux, le focus clavier peut atterrir sur un panneau translaté hors du cadre, invisible sous overflow: hidden : mettez l'animation en pause sur :focus-within et laissez le navigateur défiler (overflow-x: auto), ou gardez les panneaux inertes.

Compatibilité navigateur

CSS seul : @keyframes et transform: translateX(), flexbox, background-clip: text via le raccourci background: … text et -webkit-text-fill-color. Aucune ligne de JavaScript, aucune variable CSS, aucune ressource. C'est une animation temporelle classique : elle tourne dans Firefox, contrairement aux défilements horizontaux pilotés par animation-timeline de la même catégorie (Horizontal Scroll Section fx-0567, Horizontal Scroll fx-0564), que Firefox n'exécute dans aucune version.

Chrome 120+✓ Complet (de 43 à 119 : glissement OK, chiffres invisibles)
Firefox 49+✓ Complet
Safari 15.5+✓ Complet (avant : chiffres invisibles)
Edge 120+✓ Complet (79 à 119 : chiffres invisibles)
Mobile iOS 15.5+✓ Complet (tourne seul, rien à toucher)
Android Chrome 120+✓ Complet

Là où background-clip: text n'existe que sous préfixe (Chrome et Edge avant 120, Safari avant 15.5, Firefox avant 49), la déclaration background: … text est rejetée en bloc et -webkit-text-fill-color: transparent reste : les chiffres sont invisibles, les libellés et le glissement fonctionnent. Repli : .panel-number { color: #c084fc } en base, et le dégradé, -webkit-background-clip: text, background-clip: text et le -webkit-text-fill-color ensemble dans @supports ((background-clip: text) or (-webkit-background-clip: text)) { … }. Sans @keyframes — aucun navigateur courant — les cinq panneaux restent figés sur le premier.

Le code

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

index.html — structure
<div class="sticky-h-viewport">
  <div class="sticky-h-track">
    <div class="sticky-h-panel">
      <span class="panel-number">01</span>
      <span class="panel-label">Decouverte</span>
    </div>
    <div class="sticky-h-panel">
      <span class="panel-number">02</span>
      <span class="panel-label">Exploration</span>
    </div>
    <div class="sticky-h-panel">
      <span class="panel-number">03</span>
      <span class="panel-label">Creation</span>
    </div>
    <div class="sticky-h-panel">
      <span class="panel-number">04</span>
      <span class="panel-label">Iteration</span>
    </div>
    <div class="sticky-h-panel">
      <span class="panel-number">05</span>
      <span class="panel-label">Livraison</span>
    </div>
  </div>
</div>
🔒 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
Durée du cycle (CSS — .sticky-h-track { animation: 12s … }) 12 s : 2,16 s par panneau, 240 ms de glissement, 600 ms de rembobinage Tout est proportionnel : à 20s, 3,6 s d'arrêt, 400 ms de glissement, 1 s de rembobinage. Sous 8 s le glissement (160 ms) devient une coupure ; au-delà de 30 s, le rembobinage dépasse 1,5 s et se voit vraiment.
Arrêt et glissement (CSS — @keyframes slideHorizontal : 0%, 18%20%, 38%) 18 % d'arrêt et 2 % de glissement par panneau, 15 % sur le dernier, 5 % de retour Écartez les deux bornes (17% / 21%) pour un glissement deux fois plus long. Pour un départ et une arrivée en douceur, ajoutez animation-timing-function: ease-in-out dans le bloc de chaque palier : la fonction posée sur une image-clé s'applique jusqu'à la suivante, sans toucher au linear global.
Nombre de panneaux (HTML — 5 × .sticky-h-panel ; keyframes jusqu'à translateX(-400%)) 5, couplés aux 5 paliers Les paliers sont écrits en dur : un 6ᵉ panneau n'est jamais montré, avec 4 panneaux le palier -400% affiche 1,8 s de vide. Pour 6 panneaux : 0%, 14% → 0, 16%, 30%-100%, 32%, 46%-200%, 48%, 62%-300%, 64%, 78%-400%, 80%, 95%-500%, to → 0.
Hauteur (CSS — .sticky-h-viewport { height: 280px }) 280 px Les panneaux suivent (height: 100%) ; la largeur est toujours celle du conteneur. 112 px suffisent à un bandeau de logos. Le prélude .demo-preview ajoute 10 px de fond au-dessus et au-dessous (min-height: 300px) : retirez-le à l'intégration.
Fonds des panneaux (CSS — .sticky-h-panel:nth-child(1…5) { background: linear-gradient(135deg, …) }) 5 dégradés sombres à 135°, du bleu nuit au bordeaux Un dégradé par position, pas par contenu : réordonnez les panneaux, les fonds ne suivent pas. Une teinte différente par panneau rend le glissement lisible même quand les textes se ressemblent.
Chiffre (CSS — .panel-number { font-size: 2.5rem; font-weight: 800; background: linear-gradient(135deg, #a855f7, #ec4899) text }) 40 px, graisse 800, violet → rose Le dégradé est découpé dans les glyphes ; il change avec les deux couleurs. Un texte court — certification, prix, nom de poste — tient sur une ligne jusqu'à 10 caractères à 40 px dans un cadre de 540 px. Voir la compatibilité pour le repli sans background-clip: text.
Libellé (CSS — .panel-label { font-size: .85rem; color: rgba(255, 255, 255, .5) }) 13,6 px, blanc à 50 % Contraste de 4,17 à 5,31:1 sur les fonds vendus ; passez à .75 et 1rem pour un écran lu à distance. Le texte n'est pas centré quand il passe sur deux lignes : ajoutez text-align: center.
Pause et arrêt (CSS — à ajouter) aucun : survol, clic et molette mesurés sans effet .sticky-h-viewport:hover .sticky-h-track { animation-play-state: paused } suffit pour une page web ; sous prefers-reduced-motion: reduce, animation: none sur la piste et overflow-x: auto; scroll-snap-type: x mandatory sur le cadre pour que les cinq panneaux restent atteignables.

FAQ

C'est le dernier segment des images-clés : de 95% (translateX(-400%)) à 100% (translateX(0)), la piste revient au départ en 5 % du cycle, soit 600 ms pour quatre largeurs — mesuré 5,2 px/ms sur un cadre de 784 px, les panneaux 4, 3 et 2 passant à l'envers (-300% à 11,55 s, -200% à 11,7 s, -100% à 11,85 s). Le code ne bégaie pas, il rembobine. Pour une boucle sans retour visible : ajoutez un 6ᵉ panneau, copie du premier, et remplacez la fin des images-clés par 80%, 98% { transform: translateX(-400%) } puis to { transform: translateX(-500%) }. À 100 % la copie occupe le cadre, à 0 % l'original la remplace au pixel près : le saut est invisible. Le sixième fond nth-child(6) doit reprendre le premier.
La même topologie — un cadre en overflow: hidden, une piste flex, des panneaux, un @keyframes en translateX — mais deux horloges. fx-0567 branche l'animation sur le défilement (animation-timeline: --hscrollTimeline, conteneur haut de 400 %) : l'utilisateur fait avancer la piste en scrollant, rien ne bouge s'il ne scrolle pas, et Firefox n'exécute animation-timeline dans aucune version. fx-0578 branche la même piste sur le temps (12s linear infinite) : elle avance sans personne, ne s'arrête pour personne et tourne dans Firefox comme partout — mesuré ici, molette, survol et clic laissent la chronologie intacte. Choisissez fx-0567, ou Horizontal Scroll fx-0541 en scroll-snap natif, quand un lecteur tient la page ; fx-0578 quand l'écran n'a pas de lecteur — hall d'accueil, borne, atelier — ou pour un bandeau secondaire qu'on regarde sans le piloter.
Le nom décrit ce que l'effet imite, pas ce qu'il fait. La section « collée » qui fait passer ses panneaux à l'horizontale pendant qu'on scrolle à la verticale est un motif connu — fx-0567 l'implémente avec un vrai position: sticky ; ce code en reproduit l'image, un cadre fixe et des panneaux qui défilent, avec une simple animation temporelle : aucun position: sticky, aucun conteneur défilable, aucun JavaScript. La description du catalogue le dit à sa manière (« défilement horizontal automatique simulant une navigation par panneaux »). Conséquence pratique : posez-le dans n'importe quel bloc de la page, il n'a besoin ni d'une hauteur de scroll ni d'un parent particulier — mais ne comptez pas sur lui pour réagir au scroll.