Scroll✨ Premium

Zoom In Sticky

Un carré de 120 px dans une boîte de 280 px qui défile : animation-timeline: scroll() le fait passer de scale(1) à scale(2.2) et son rayon de 20 à 4 px sur 520 px de course. Dans le flux, pas épinglé malgré son nom ; CSS seul.

CSSZoomScroll

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

Le ballon-sonde gonfle en montant — page pédagogique d'un service météorologique — Zoom In Sticky exemple 1

① Le ballon-sonde gonfle en montant — page pédagogique d'un service météorologique

QuandPage « Comprendre l'atmosphère » d'un service météo : un titre, trois lignes sur la pression qui tombe au dixième vers 16 km, puis un repère d'altitude fixé sur la boîte (0, 4, 8, 12, 16 km avec leur pression) ; le lecteur défile, le ballon décolle du sol, monte à travers le ciel et grossit de 96 à 211 px, jusqu'à dépasser le repère des 16 km par le haut ; les valeurs sol, tropopause et éclatement passent dessous.
PourquoiDans le flux, comme dans le code vendu, l'objet monte avec la page et grossit jusqu'au bout : c'est la trajectoire d'un ballon-sonde, et le facteur 2,2 est exact — la pression divisée par dix multiplie le volume par dix, le diamètre par ∛10 ≈ 2,2. fx-0580 Zoom on Scroll l'épinglerait à 110 px du haut : un ballon qui ne monte pas ; fx-0563 Zoom & Blur le ramènerait à ×1 et le flouterait en fin de course. Ici l'état le plus grand est le dernier et il sort par le haut de la boîte : le ballon continue vers 30 km.
RéglagesCode vendu intact, aucun position: sticky : boîte de 316 px, plateau remplacé par une colonne « intro de 178 px · 76 px de ciel · ballon de 96 × 124 px · 76 px de ciel · valeurs de 78 px », course 216 px ; ballon en SVG (enveloppe, ficelle, radiosonde) dans une boîte transparente ; ciel en dégradé et repère d'altitude posés sur la boîte, fixes, pendant que la colonne défile. Mesuré : enveloppe centrée sur le repère 0 km au repos, entière de 95 à 189 px de défilement (×1,5 à ×2,05), centrée sur 16 km en bout de course à ×2,2 (211 × 273 px), le haut sorti de 36 px. Les 76 px de ciel sous le ballon absorbent les 74 px que scale(2.2) ajoute sans changer la mise en page : la dalle finale ne couvre pas les valeurs.
Zoom sur la matière d'un tissu de haute couture — fiche produit d'une boutique en ligne — Zoom In Sticky exemple 2

② Zoom sur la matière d'un tissu de haute couture — fiche produit d'une boutique en ligne

QuandFiche d'un tweed bouclé : nom du tissu, deux lignes sur l'armure, puis un échantillon carré de 132 px ; le client défile, le carré vient au centre et grossit jusqu'à 290 px — trame, flammés crème et marine, ourlet surjeté et étiquette tissée apparaissent ; composition, laize, poids et prix passent dessous.
PourquoiSur une fiche de tissu, la couleur est ce qu'on vend : fx-0590 grossit sans toucher à l'opacité ni au flou, le bordeaux reste le même du premier au dernier pixel de course — fx-0580 Zoom on Scroll descend à opacity: .8 et grise la matière, fx-0563 Zoom & Blur la floute aux deux bouts. Et son facteur 2,2 tient dans la fiche : 132 px deviennent 290, là où le 5× de fx-0580 ferait 660 px. L'échantillon n'est pas une image : cinq calques de dégradés répétés (sergé à 45°, fils, deux semis de points) que le transform agrandit sans flou.
RéglagesBoîte de 312 px, colonne « intro de 160 px · échantillon · caractéristiques de 290 px », course 270 px ; .ss-zoom-box à 132 px, position: sticky; top: 90px (épinglé après 70 px), fond remplacé par les cinq dégradés, ourlet en outline: 1px dashed, étiquette tissée de 4 px (8,8 px à 2,2×) ; échelle 2,2 conservée, 290 px dans 312. Fond crème, sans-serif.
La tache urbaine s'étend sur soixante ans — atlas en ligne d'une agence d'urbanisme — Zoom In Sticky exemple 3

③ La tache urbaine s'étend sur soixante ans — atlas en ligne d'une agence d'urbanisme

QuandPage « Étalement urbain » de l'atlas d'une agence d'urbanisme, sur un quadrillage à échelle constante (un carreau = 2 km) posé en fond de la boîte : un titre, trois lignes sur l'emprise bâtie passée de 18 à 87 km² pendant que la population ne faisait que ×1,6 ; le lecteur défile, soixante ans passent, la tache urbaine — emprise, centre ancien, cinq axes — s'étend de 110 à 242 px sur un quadrillage qui ne bouge pas, puis les relevés 1960, 1990 et 2020 passent dessous.
PourquoiRien ne monte ici : le défilement est le temps, et l'objet ne se déplace que parce que la page avance — ce qui compte est qu'il s'étend sur un quadrillage fixe, à échelle constante. Le facteur du code vendu est le bon : une surface multipliée par 4,8, c'est ×2,2 dans chaque direction, et la mi-course (×1,6, 46 km²) tombe sur 1990. La timeline étant le défilement de la boîte et non l'horloge, le lecteur revient à 1960 en remontant la page et s'arrête sur l'année qu'il veut. fx-0570 Zoom Into Content ferait surgir la tache à sa taille finale dès son entrée ; fx-0580 Zoom on Scroll la griserait à .8 — sur une carte, la teinte de l'emprise bâtie est une légende et ne doit pas changer.
RéglagesCode vendu intact, aucun position: sticky : boîte de 312 px, colonne « intro de 190 px · 56 px de carte · tache de 110 × 110 px · 68 px de carte · relevés de 66 px », course 178 px ; tache en SVG (emprise en polygone, cinq axes, centre ancien) dans une boîte transparente — le border-radius animé 20 → 4 px agit sur une boîte invisible ; quadrillage de 40 px en fond de la boîte, fixe pendant que la colonne défile. Mesuré : tache visible sur 66 px sous le pli au repos, entière de 70 px de défilement (×1,47) jusqu'au bout, 242 px de 2 à 244 en fin de course à ×2,2, les relevés à 246 ; les 68 px de carte sous la tache absorbent les 66 px que scale(2.2) ajoute vers le bas. Fond papier, sans-serif.

Comment ça marche

Quatre éléments et deux textes : le cadre .demo-preview (flex centré, min-height: 300px, fond #0a0a0f, texte blanc), la boîte .sdc-scroll-container (280px, overflow-y: auto, scroll-behavior: smooth), le plateau .ss-zoom-content (800 px, flex centré) et le carré .ss-zoom-box : 120 × 120 px, border-radius: 20px, dégradé 135° #6366f1 → #ec4899, le mot ZOOM en 19,2 px graisse 800. Deux textes codés en dur, blancs à 30 % : l'étiquette .ss-zoom-label « Zoom progressif lie au scroll » (11,2 px, à 20 px du bas du plateau, sans accent) et l'indice .sdc-scroll-hint « Scrollez ↓ » (10,4 px, pulsation .3 → .7 toutes les 2 s). Course : 800 − 280 = 520 px. 2 Ko de CSS, aucun JavaScript, aucun id, aucune variable var(--…) ; collé dans une page vierge, fond blanc ou sombre, 1 280 et 390 px : aucune requête, aucune erreur console.

Une règle fait l'effet : animation-name: ssZoomIn avec animation-timeline: scroll() — l'animation avance avec la position du premier ancêtre défilant, la boîte, et non avec le temps ; animation-duration: auto et animation-range: normal étalent les images-clés sur toute la course, linear les relie en droite, animation-fill-mode: none rend l'état de base hors animation. Deux images-clés : scale(1); border-radius: 20px et scale(2.2); border-radius: 4px. Mesuré : ×1,23 / 16,9 px à 100 px de défilement, ×1,6 / 12 px à 260, ×2,2 / 4 px à 520 — +0,23 d'échelle par 100 px, sans palier. Le rayon rendu n'est pas celui du code : transform agrandit aussi les coins, 4 px à 2,2× font 8,8 px à l'écran — l'arrondi passe de 17 % à 3,3 % du côté, d'une vignette à une dalle. Le plus grand état est le dernier : rien ne redescend.

Le carré est centré à 400 px du haut d'un plateau dont la boîte ne montre que 280 : au repos il est à 340–460 px, sous le pli — le visiteur voit un fond sombre et l'indice. Mesuré : il entre par le bas à 60 px de défilement (88 px visibles à 130, ×1,3), est entier de 260 (44–236 px, ×1,6) à 300, puis, dans le flux et non épinglé, sort par le haut en grossissant : 124 px visibles à 390, 64 à 460, et à 520 ses 264 px vont de −252 à 12 px — 12 px de dalle en haut de la boîte, plus l'étiquette. Le nom dit sticky, le code ne contient aucun position: sticky (FAQ). À 390 px de large, 264 px tiennent sous les 374 px de la boîte sans piste horizontale. Sans id, plusieurs copies dans une page pilotent chacune leur boîte.

Accessibilité

  • prefers-reduced-motion absent du code : mesuré sous émulation, mêmes valeurs (×1 → ×2,2), l'indice pulse toujours. Rien n'est caché et le grossissement ne se produit que sous le geste du lecteur (WCAG 2.3.3). Pour l'honorer : @media (prefers-reduced-motion: reduce) { .ss-zoom-box, .sdc-scroll-hint { animation: none } } — le carré reste à 120 px, rayon 20, l'état que voit Firefox.
  • Clavier : mesuré, Tab donne le focus à la boîte sans tabindex dans Chromium et Firefox ; flèche bas avance de 40 px dans Chromium (+0,09 d'échelle) et de 51 dans Firefox, PageDown de 285 et 303, Fin va à 520. WebKit 26.5 ne focalise pas la boîte (flèches sans effet) sans tabindex="0" : ajoutez-le, avec un :focus-visible visible et un aria-label.
  • Contraste : ZOOM (blanc, 19,2 px, graisse 800 — texte « grand », seuil 3:1) vaut 4,5:1 sur le bleu #6366f1, 4,3:1 au milieu du dégradé, 3,5:1 sur le rose #ec4899 : conforme ; un texte de moins de 18,7 px en gras échouerait au seuil 4,5:1 sur les deux tiers du carré. Indice et étiquette (blanc à 30 % sur #0a0a0f) valent 2,6:1 au repos — l'étiquette en permanence, l'indice seulement si sa pulsation est coupée : son opacity .3 → .7 se multiplie aux 30 % de la couleur, de 1,2:1 à 1,8:1 sous la pulsation. Décoratifs, posez aria-hidden="true" ; pour les rendre lisibles, montez à 70 % (9,7:1) et retirez la pulsation, qui les ramènerait entre 1,8:1 et 5,2:1.
  • Lecteurs d'écran : le carré est un div dont le texte ZOOM est lu tel quel ; le changement d'échelle n'est pas annoncé, et n'a pas à l'être. S'il devient une image porteuse de sens (carte, échantillon, schéma), donnez-lui role="img" et un aria-label, et écrivez l'information aussi hors du carré : un lecteur d'écran ne zoome pas en défilant. Les deux textes sont lus en français, quelle que soit la langue de la page.

Compatibilité navigateur

CSS seul : animation-timeline: scroll(), animation-duration: auto, animation-range (Scroll-driven Animations), transform, border-radius animé, overflow-y: auto. Zéro JavaScript, zéro dépendance. Chrome et Edge 115+, Safari et iOS 26+ : mesuré dans WebKit 26.5, mêmes valeurs que Chromium 151 à chaque position. Firefox : aucune version. Mesuré dans Firefox 153 : CSS.supports() répond faux pour les trois déclarations, ignorées ; l'animation dure 0 s sans remplissage et le carré garde son état de base, transform: none, border-radius: 20px. Le visiteur Firefox voit un carré de 120 px, rayon 20, qui traverse la boîte comme n'importe quel contenu — entré par le bas à 60 px de défilement, entier de 200 à 340, sorti à 460 — puis l'étiquette. Rien n'est caché, rien ne se superpose : il n'y a pas d'effet. Le code vendu ne contient aucun @supports : ce repli est celui de la cascade, et @supports not (animation-timeline: scroll()) { .ss-zoom-box { animation: none } } donnerait le même rendu.

Chrome 115+✓ Complet
Firefox (toutes versions)✓ Sans effet : carré de 120 px, rayon 20, tout visible
Safari 26+✓ Complet
Edge 115+✓ Complet
Mobile iOS 26+✓ Complet (défilement tactile de la boîte)
Android Chrome 115+✓ Complet

Sans animation-timeline (Firefox, Chrome et Edge avant 115, Safari et iOS avant 26) : carré de 120 px, rayon 20, qui défile avec le plateau, tout visible. Là où overflow n'est pas honoré (certains clients mail), le plateau de 800 px s'affiche entier. Sans dégradé, pas de couleur de secours : ZOOM blanc sur le fond du cadre.

Le code

Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :

index.html — structure
<div class="demo-preview">
  <div class="sdc-scroll-container">
    <div class="ss-zoom-content">
      <div class="ss-zoom-box">…</div>
      <span class="ss-zoom-label">…</span>
    </div>
  </div>
  <span class="sdc-scroll-hint">…</span>
</div>
Débloquer le code complet — 9,90 € HT/mois

Le code complet HTML + CSS + JS de Zoom In Sticky, 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éfautEffet
Facteur d'échelle (CSS — to { transform: scale(2.2) }) 1 → 2,2× (120 → 264 px) Taille finale = côté × facteur. Mesuré avec scale(3) : 360 px, dont 60 visibles en bout de course ; à 390 px de large, 360 px tiennent encore sous les 374 px de la boîte. Au-delà de sa largeur, overflow-y: auto ouvre une piste horizontale : posez overflow-x: hidden.
Rayon (CSS — border-radius: 20px → 4px) 20 → 4 px (8,8 px rendus à 2,2×) Rayon rendu = rayon × échelle. 0 pour de vrais angles droits ; 20px → 9px pour un arrondi constant à l'écran (mesuré : 14,5 px à mi-course, 9 px en bout, soit 20 px rendus).
Épingler l'objet (CSS — position: sticky; top: 80px à ajouter sur .ss-zoom-box) absent : l'objet est dans le flux Mesuré : le carré s'accroche à 260 px de défilement et finit entier dans la boîte, de 8 à 272 px, au lieu de 12 px visibles (détail en FAQ). La ligne qu'ajoute la scène du tissu ; le ballon et la tache urbaine restent dans le flux.
Course (CSS — .ss-zoom-content { height: 800px }, .sdc-scroll-container { height: 280px }) 520 px (+0,23 d'échelle par 100 px) Course = plateau − boîte : 1 200 px de plateau = 920 px de course, zoom deux fois plus lent. Mesuré avec une boîte de 480 px : carré visible dès le repos (340–460), course 320, 212 de ses 264 px visibles en bout.
Timeline et plage (CSS — animation-timeline: scroll(), animation-range: normal) défileur le plus proche, 0 → 100 % de la course scroll(root) pilote le carré par la page entière, view() par sa traversée de la fenêtre. animation-range: 20% 80% concentre le zoom sur les 312 px du milieu — mesuré : ×1 à 104, ×2,18 à 410, puis retour à 120 px dès 416 (animation-fill-mode: none) ; both fige 2,2× de 416 à 520.
Rythme (CSS — animation-timing-function: linear) linear Mesuré en ease-in-out : ×1,16 à 130 px (contre ×1,3), ×1,6 à 260, ×2,05 à 390 (contre ×1,9) — départ lent, précipitation au milieu, arrivée douce. ease-out met l'essentiel du zoom dans le premier tiers.
Contenu et textes (CSS — width/height: 120px ; HTML — ZOOM, .ss-zoom-label, .sdc-scroll-hint) 120 × 120 px, ZOOM ; « Scrollez ↓ », « Zoom progressif lie au scroll » Tout le contenu du carré est agrandi avec lui : ZOOM fait 42 px à 2,2×, une <img> de 120 px est étirée à 264 (floue) — fournissez 264 px de source, ou du SVG et des dégradés comme les scènes ; 200 × 130 px donnent 440 × 286. Les deux textes sont codés en dur : traduisez-les ou supprimez les deux span (sdcHintPulse part avec ; l'indice est accroché au cadre .demo-preview).

FAQ

Parce que le carré est centré dans un plateau de 800 px dont la boîte de 280 ne montre que le haut : au repos il est à 340–460 px, sous le pli, et rien ne l'épingle — il monte avec le plateau en grossissant et sort par le haut (mesures ci-dessus : entier de 260 à 300, 12 px visibles à 520). Trois remèdes : une boîte plus haute (mesuré à 480 px : visible dès le repos, 212 px visibles en bout), du contenu au-dessus du carré pour faire de son entrée une annonce, ou la ligne position: sticky (question suivante). Le piège : remonter le carré dans le plateau sans rien d'autre — il sort encore plus tôt.
Le code vendu ne contient aucun position: sticky ; le nom vient de la carte du catalogue. Une ligne suffit : .ss-zoom-box { position: sticky; top: 80px }. Mesuré dans la boîte vendue : le carré monte de 340 à 80 px, s'y accroche à 260 px de défilement (×1,6), puis reste centré à 140 px pendant que le plateau défile dessous ; à 520, ses 264 px vont de 8 à 272 — entier dans la boîte. Le top se calcule : centre voulu − 60 px (la moitié du côté), et le carré final doit tenir dans la boîte (264 px dans 280). Le bloc conteneur du sticky est le plateau .ss-zoom-content : le carré y reste collé jusqu'au bout, comme dans la scène du tissu de cette page.
Même image de départ — carré en dégradé, mot ZOOM, coins qui se resserrent, boîte de 280 px — mais deux codes. fx-0580 calcule en JavaScript : un écouteur scroll lit t = scrollTop ÷ 620 et écrit scale(1 + 4t), border-radius: 12 − 10t et opacity: 1 − .2t sur une cible de 60 px, position: sticky; top: 80px dans son CSS : le carré s'accroche à 110 px du haut et grossit sur place jusqu'à 5×, 300 px, en grisant à .8 ; deux ids (#zoom-scroll, #zoom-target) — une instance par page ; il tourne sur Firefox. fx-0590 n'écrit rien : animation-timeline: scroll() anime scale(1) → scale(2.2) et border-radius: 20px → 4px sur un carré de 120 px dans le flux, sans sticky malgré son nom, sans opacité, sans id — autant de copies que de boîtes — et rien sur Firefox. La règle de choix : fx-0580 quand l'objet doit rester à l'écran pour devenir lisible (QR, graphique, formule : ses trois scènes), quand Firefox compte, ou quand la page doit lire t — afficher un pourcentage, débloquer un bouton ; fx-0590 quand l'objet doit traverser la boîte en grossissant (ballon, tache urbaine), garder son opacité et ses couleurs, tenir dans la boîte à 2,2× (264 px dans 280, contre 300 pour le 5× de fx-0580), ou exister en plusieurs exemplaires — et une ligne position: sticky lui rend l'épinglage (question précédente).