Scroll✨ Premium

Horizontal Scroll

Six tuiles de 200 × 200 px — numéro à 32 px et libellé court — dans une piste flex à 12 px d'écart que scroll-snap-type: x mandatory arrête tuile centrée, un pas de 212 px, en CSS seul (zéro octet de JavaScript). Mesuré sur 524 px de large : un cran de molette horizontale ou un swipe de 150 px avance d'une tuile ; la première et la dernière ne se centrent jamais (±146 px) ; au-delà de 1 292 px de conteneur, plus rien ne défile alors que l'indice « Scrollez → » pulse toujours.

CSSHorizontalSticky

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

Familles de produits d'un catalogue mobile — 01 Outils, 02 Fixations, 03 Sécurité… — Horizontal Scroll exemple 1

① Familles de produits d'un catalogue mobile — 01 Outils, 02 Fixations, 03 Sécurité…

QuandPage catalogue mobile d'un distributeur : barre de recherche, bandeau des familles numérotées, grille de résultats en dessous qui suit la famille centrée.
PourquoiLes libellés courts numérotés donnent l'ordre de navigation d'un coup d'œil, avec trois ou quatre familles visibles en même temps. Horizontal Scroll (fx-0541), blocs colorés sans texte, ne peut pas nommer des familles ; Horizontal Snap (fx-0594), plein écran, n'en montre qu'une à la fois et fait perdre la vue d'ensemble.
RéglagesTuiles réduites à 128 × 92 px, numéro 22 px, gouttières de piste calc(50% - 64px) pour que la première et la dernière famille se centrent aussi ; un script de scène repère la tuile la plus proche du centre (classe is-active, aria-current) et affiche la grille correspondante ; fond clair, indice « Scrollez → » retiré.
Sélecteur de chapitres d'un cours en ligne — 01 Introduction, 02 Fondements, 03 Pratique, 04 Évaluation — Horizontal Scroll exemple 2

② Sélecteur de chapitres d'un cours en ligne — 01 Introduction, 02 Fondements, 03 Pratique, 04 Évaluation

QuandApplication de formation : titre du cours et progression, chapitres en défilement horizontal, contenu du chapitre sélectionné (leçons, durées, bouton) chargé sous le sélecteur.
PourquoiUn chapitre n'a pas d'illustration : un titre numéroté suffit, et la tuile centrée est le chapitre courant. Card Snap Carousel (fx-0595) — cartes de 200 × 240 px avec zone image, paragraphe et étiquette — serait surdimensionné pour un simple sélecteur.
RéglagesTuiles 150 × 104 px, numéro 26 px, anneau blanc de 2 px sur le chapitre centré, panneau du chapitre commuté par la même détection de tuile centrée ; avance automatique d'une tuile toutes les 560 ms pour la démonstration.
Indicateurs d'une campagne marketing, tableau de bord mobile — 01 ROAS, 02 CPC, 03 CTR, 04 CVR, 05 CAC — Horizontal Scroll exemple 3

③ Indicateurs d'une campagne marketing, tableau de bord mobile — 01 ROAS, 02 CPC, 03 CTR, 04 CVR, 05 CAC

QuandTableau de bord consulté sur téléphone : les cinq indicateurs principaux en ligne, chacun avec sa valeur et son écart, et le graphique des sept derniers jours de l'indicateur centré.
PourquoiLe défilement est libre et s'arrête sur chaque indicateur : on lit un chiffre précis sans hâte. Sticky Horizontal (fx-0578) fait défiler ses panneaux tout seul sur 12 s — impossible d'y lire une valeur à son rythme.
RéglagesCinq tuiles de 164 × 124 px alignées à gauche (align-items: flex-start), numéro réduit à 15 px, libellé en capitales espacées, valeur 28 px et écart ajoutés dans la tuile avec des éléments b et small (la règle .ss-horiz-item span ne vise que le numéro) ; graphique à barres commuté sous le bandeau.

Comment ça marche

Trois niveaux et pas une ligne de script. .ss-horiz-content est la fenêtre : height: 280px, overflow: auto hidden (défilement horizontal, vertical coupé), display: flex avec align-items: center, et surtout scroll-snap-type: x mandatory. Dedans, .ss-horiz-track aligne en flex six .ss-horiz-item avec gap: 12px et padding: 20px 16px. Chaque tuile : flex-shrink: 0, 200 × 200 px, border-radius: 14px, colonne centrée, libellé en .9rem (14,4 px) gras, un span pour le numéro en 2rem (32 px), graisse 800, opacity: .5, et scroll-snap-align: center. Six dégradés à 135° par :nth-child (indigo → violet → fuchsia → rose → ambre → vert → cyan). La piste mesure 6 × 200 + 5 × 12 + 32 = 1 292 px. Aucune variable CSS, js vide : le défilement est celui du navigateur, sur le compositeur, sans écouteur.

Mesuré dans Chromium sur une fenêtre de 524 px : scrollWidth 1 292, course maximale 768 px. Les positions d'arrêt sont les centres des tuiles moins la demi-fenêtre : 66, 278, 490, 702 — un pas de 212 px (200 + 12). La tuile 1 exigerait −146 px et la tuile 6 +914 : la butée les rabat à 0 et 768, donc ni la première ni la dernière ne se centrent, elles restent décalées de 146 px. mandatory interdit toute position intermédiaire : un scrollLeft forcé à 50 se pose à 66, à 320 → 278, à 900 → 768. Un cran de molette horizontale (deltaX 120) avance d'une tuile exactement (66 → 278 → 490 → 702 → 768) ; la molette verticale ne fait rien (0 px) ; sans JavaScript, tirer à la souris ne fait rien non plus — au trackpad, au tactile ou par la barre de défilement seulement. Sur iPhone 13 émulé (374 px), un swipe de 150 px donne 141, 353, 565, 777 (même pas de 212), un swipe de 40 px revient à 0. Pas de scroll-behavior: smooth : une écriture de scrollLeft saute ; scrollTo({ behavior: 'smooth' }) glisse (0 → 490 px en ~320 ms) et le snap termine.

Ce que le code ne règle pas. La fenêtre n'a aucune largeur propre : enfant flex du .demo-preview vendu (centré), elle rétrécit à la largeur du parent parce qu'un conteneur défilant a min-width: 0 ; dans un parent bloc elle prend 100 %. Dès que le parent dépasse 1 292 px, la piste tient entière, centrée, et rien ne défile plus (mesuré à 1 400 px : course 0) ; à 1 264 px il reste un moignon de 28 px entre deux positions de snap. Dans les deux cas .sdc-scroll-hint — « Scrollez → », préfixe sdc- partagé avec les autres démos de défilement du catalogue, pulsation d'opacité .3 ↔ .7 en 2 s — continue de clignoter. Rien ne marque la tuile centrée (pas d'état actif), et le HTML vendu mêle des libellés anglais (Design, Develop, Test…) à un indice en français. Le tag « Sticky » du catalogue ne correspond à rien dans le code : la variante collante et auto-animée est Sticky Horizontal (fx-0578).

Accessibilité

  • prefers-reduced-motion absent du code — et, pour une fois, presque sans conséquence : le défilement n'est déclenché que par l'utilisateur (aucune animation liée au scroll, aucun mouvement automatique). Seule la pulsation de l'indice l'ignore : mesuré sous reducedMotion: reduce, son opacité oscille toujours de 0,34 à 0,70 en une seconde. Ajoutez @media (prefers-reduced-motion: reduce) { .sdc-scroll-hint { animation: none; opacity: .5 } }, ou retirez l'indice à l'intégration.
  • Clavier : .ss-horiz-content n'a pas de tabindex. Chrome 130+ rend focalisable tout conteneur défilant sans enfant focalisable — mesuré : Tab s'arrête dessus et → avance d'une tuile (scrollLeft 0 → 66) —, Firefox et Safari non. Posez tabindex="0" et un aria-label sur la fenêtre. Si les tuiles servent de sélecteur (familles, chapitres), ce sont des div : remplacez-les par des button ou des liens et gérez aria-current sur celle qui commande le contenu.
  • Contraste insuffisant sur cinq tuiles sur six (libellé blanc 14,4 px gras, seuil 4,5:1) : tuile 1 indigo 4,4:1, tuiles 2 et 3 entre 3,5 et 3,9:1, tuiles 4 à 6 (rose → ambre → vert → cyan) entre 2,2 et 2,9:1. Le numéro à opacity: .5 tombe entre 1,5 et 2,2:1. Corrigez par des arrêts de dégradé plus sombres (#b45309, #15803d, #0e7490 à la place de l'ambre, du vert et du cyan), un text-shadow: 0 1px 2px rgba(0,0,0,.35), ou un libellé d'au moins 18,7 px gras (texte large, seuil 3:1).
  • Lecteurs d'écran et intégration : six div lus « 01 Design », « 02 Develop »… dans l'ordre, sans rôle ni annonce de la tuile centrée — la position de défilement n'a aucune sémantique. Le tactile fonctionne nativement (une tuile par swipe, un swipe court revient en place). Pour que la première et la dernière tuile se centrent comme les autres, donnez à la piste padding: 20px calc(50% - 100px) (c'est ce que font les trois scènes) ; pour ne pas tromper l'utilisateur sur grand écran, limitez la fenêtre (max-width) ou masquez l'indice quand scrollWidth ne dépasse pas clientWidth.

Compatibilité navigateur

Feuille de style seule, sans JavaScript : scroll-snap-type: x mandatory et scroll-snap-align: center (syntaxe de 2018), overflow à deux valeurs (auto hidden), gap en flexbox, dégradés linéaires. Le défilement est natif : l'effet fonctionne dans Firefox, contrairement aux animations pilotées au scroll en CSS (animation-timeline), que Firefox n'active dans aucune version.

Chrome 84+✓ Complet
Firefox 68+✓ Complet
Safari 14.1+✓ Complet
Edge 84+✓ Complet
Mobile iOS 14.5+✓ Complet (une tuile par swipe)
Android Chrome✓ Complet (une tuile par swipe)

Sans scroll-snap (navigateurs plus anciens), la piste défile librement et s'arrête n'importe où, mais tout reste visible et lisible. Sans gap en flexbox (Safari 13 et avant), les tuiles se touchent et le pas passe de 212 à 200 px. Rien ne dépend d'un script : il n'y en a pas.

Le code

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

index.html — structure
<div class="ss-horiz-content">
  <div class="ss-horiz-track">
    <div class="ss-horiz-item">
      <span>01</span> Design
    </div>
    <div class="ss-horiz-item">
      <span>02</span> Develop
    </div>
    <div class="ss-horiz-item">
      <span>03</span> Test
    </div>
    <div class="ss-horiz-item">
      <span>04</span> Deploy
    </div>
    <div class="ss-horiz-item">
      <span>05</span> Monitor
    </div>
    <div class="ss-horiz-item">
      <span>06</span> Iterate
    </div>
  </div>
</div>
<span class="sdc-scroll-hint">Scrollez →</span>
🔒 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
Taille des tuiles (CSS — .ss-horiz-item width / height) 200 × 200 px Le pas de snap vaut largeur + gap, soit 212 px : c'est la distance d'un cran de molette ou d'un swipe. Le nombre de tuiles visibles = largeur de la fenêtre ÷ 212 (deux et demie à 524 px). Les scènes descendent à 128 × 92 px sans rien changer d'autre.
Écart (CSS — .ss-horiz-track gap) 12px S'ajoute au pas de snap. À 0, les tuiles se touchent et le pas passe à 200 px ; à 24, les dégradés respirent mais une tuile de moins tient à l'écran.
Gouttières de la piste (CSS — .ss-horiz-track padding) 20px 16px Avec 16 px, la première et la dernière tuile s'arrêtent à 146 px du centre. padding: 20px calc(50% - 100px) (moitié de la fenêtre moins une demi-tuile) les centre comme les autres — c'est le réglage des trois scènes.
Rigueur de l'arrêt (CSS — .ss-horiz-content scroll-snap-type) x mandatory x proximity ne recale que près d'une tuile et laisse s'arrêter entre deux — préférable si les tuiles dépassent la fenêtre (mandatory rendrait l'excédent inatteignable). none : défilement libre, l'effet disparaît.
Point d'alignement (CSS — .ss-horiz-item scroll-snap-align) center start aligne la tuile sur le bord gauche : la première se pose alors naturellement à 0 et le padding gauche reste visible via scroll-padding-left: 16px sur la fenêtre.
Nombre de tuiles et couleurs (HTML + CSS — :nth-child(1) à (6)) 6 dégradés à 135° Une septième tuile n'a aucun fond : ajoutez une règle :nth-child(7) ou passez les dégradés en style inline comme le fait fx-0541. La piste s'allonge de 212 px par tuile.
Hauteur de la fenêtre (CSS — .ss-horiz-content height) 280px La piste (200 + 2 × 20 = 240 px) y est centrée. Réduisez-la avec les tuiles : 118 px pour des tuiles de 92 px dans la scène catalogue.
Défilement programmé (CSS — scroll-behavior, absent) auto (saut instantané) Pour qu'un bouton « suivant » ou un scrollLeft = … glisse, ajoutez scroll-behavior: smooth sur la fenêtre, ou appelez scrollTo({ left, behavior: 'smooth' }) — mesuré : 0 → 490 px en ~320 ms, le snap finit le geste.

FAQ

Parce que scroll-snap-align: center demande une position de défilement négative pour la première (centre à 116 px, demi-fenêtre 262 px : −146) et au-delà de la course pour la dernière (+914 px pour 768 de course). Le navigateur rabat ces positions aux butées 0 et 768 : les deux tuiles s'arrêtent à 146 px du centre, mesuré sur 524 px. Deux corrections : des gouttières de piste égales à la demi-fenêtre moins une demi-tuile (padding: 20px calc(50% - 100px)), ou l'alignement start avec scroll-padding-left. Sans cela, un script « tuile active = la plus proche du centre » ne sélectionnera jamais la première ni la dernière.
C'est le code tel quel. La fenêtre n'a pas de largeur maximale ; la piste fait 1 292 px. Dès que le conteneur atteint cette largeur, tout est visible, la course tombe à 0 (mesuré à 1 400 px de fenêtre) et l'indice continue de pulser puisqu'il n'est qu'une animation d'opacité. Entre 1 200 et 1 292 px, il reste quelques dizaines de pixels de course (28 px à 1 264) : la tuile ne fait que trembler entre deux arrêts. Posez un max-width sur .ss-horiz-content (720 px = trois tuiles centrées), ou masquez l'indice quand scrollWidthclientWidth — une ligne de JavaScript, la seule que l'effet demanderait.
La structure est identique (fenêtre, piste, six blocs, snap centré, même indice), mais fx-0541 montre des blocs de 180 × 140 px avec un seul chiffre et des dégradés en style inline : des vignettes, pas des libellés. fx-0586 ajoute un libellé court sous un numéro à moitié transparent dans une tuile carrée de 200 px : c'est la version « étapes ou familles nommées ». Les autres voisins du lot répondent à d'autres besoins — Horizontal Snap (fx-0594) : panneaux plein écran un par un ; Card Snap Carousel (fx-0595) : cartes 200 × 240 px avec zone image, texte et étiquette, plus scroll-behavior: smooth ; Sticky Horizontal (fx-0578) : défilement automatique en 12 s, sans contrôle de l'utilisateur.