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.
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
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
tabindexdans 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) sanstabindex="0": ajoutez-le, avec un:focus-visiblevisible et unaria-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 : sonopacity.3 → .7 se multiplie aux 30 % de la couleur, de 1,2:1 à 1,8:1 sous la pulsation. Décoratifs, posezaria-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
divdont 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-luirole="img"et unaria-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.
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) :
<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>
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éfaut | Effet |
|---|---|---|
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
position: sticky (question suivante). Le piège : remonter le carré dans le plateau sans rien d'autre — il sort encore plus tôt.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.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).