Sticky Image Change
Un bloc « 01 » de 120 px épinglé à 10 px du haut d'une boîte de 280 px, dont le dégradé et l'ombre changent par paliers — indigo, violet, magenta, rose-ambre — sur 920 px de course, pendant que quatre panneaux se révèlent dessous : deux timelines CSS, scroll() et view(), zéro JavaScript.
Mis à jour le
Premiere Section
L'image reste fixe pendant que le contenu defile. Technique ideale pour presenter des fonctionnalites.
Deuxieme Section
Chaque section de texte declenche un changement visuel dans l'image sticky.
Troisieme Section
Les transitions douces guident l'utilisateur a travers le contenu de maniere fluide.
Quatrieme Section
Pattern utilise dans le journalisme interactif et les sites de produits.
Cet effet est gratuit — la catégorie Scroll en contient 70 au total, dont 12 gratuits. Effect.Labs regroupe 811 effets vanilla. Découvrir la catégorie →
Exemples d'usage
Rameur léger
Échauffement · 5 min
Mobilité hanches
Échauffement · 2 × 10
Squat poids du corps
Échauffement · 2 × 15
Fentes marchées
Endurance · 3 × 12
Pompes
Endurance · 3 × 12
Gainage
Endurance · 3 × 45 s
Squat barre
Effort · 4 × 8
Soulevé de terre
Effort · 4 × 6
Développé couché
Effort · 4 × 8
Sprints
Intensité max · 6 × 20 s
Burpees
Intensité max · 3 × 15
Kettlebell swing
Intensité max · 4 × 15
En-tête Server exposé
2.3Commentaires HTML de debug en production
2.6Version de jQuery obsolète
3.7Cookie de session sans SameSite
5.3Énumération d'utilisateurs au login
5.9Content-Security-Policy absente
6.5IDOR sur /api/factures/{id}
7.5XSS stockée dans la page profil
8.2Jeton de réinitialisation prévisible
8.8Injection SQL sur la recherche
9.4Contournement d'authentification JWT alg=none
9.8Exécution de code via téléversement de fichier
10.0Comment ça marche
Le HTML vendu : le cadre .demo-preview (flex, 280px, overflow: hidden, fond #0a0a0f, sans-serif), la boîte .sdc-scroll-container (100% × 280px, overflow-y: auto, scroll-behavior: smooth, barre de 4 px via ::-webkit-scrollbar), le contenu .ss-imgchange-content (1200px en border-box, padding: 20px 12px), le bloc .ss-imgchange-display et la colonne .ss-imgchange-panels (gap: 16px). Course : 1200 − 280 = 920 px (mesuré). Le bloc de 120px (rayon 14 px, « 01 » en 2rem graisse 800) tient par position: sticky; top: 10px; z-index: 2 : à 20 px du haut au repos, fixé à 10 px dès 10 px de défilement. Sa règle animation: ssImgChange linear; animation-timeline: scroll(nearest) remplace le temps par la position du défileur le plus proche, la boîte. La @keyframes ssImgChange n'a que des plateaux — 0%, 20% indigo → violet (#6366f1 → #8b5cf6), 25%, 45% violet → magenta (→ #d946ef), 50%, 70% magenta → rose (→ #f43f5e), 75%, 100% rose → ambre (→ #f59e0b), chacun avec une ombre 0 8px 30px teintée à 30 %. En pixels : 0-184, 230-414, 460-644, 690-920, séparés par trois transitions de 46 px.
Mesuré dans Chromium, page vierge, les transitions sont asymétriques : l'ombre s'interpole en continu (à 200 px, rgba(113, 99, 243, .3)), mais un linear-gradient ne s'interpole pas entre deux images clés — le moteur saute à la valeur suivante à mi-chemin du segment : 207 → 208 px (22,5 %), 437 → 438 (47,5 %), 666 → 667 (72,5 %). WebKit 26 saute aussi, dès le début de la transition (mesuré 185 px). Une couleur qui change net sous une ombre qui glisse : c'est le caractère de l'effet, une section, une couleur. Le « 01 » ne change jamais — texte statique, aucun compteur ne le pilote.
Les panneaux ont leur propre timeline. Chaque .ss-imgchange-panel (fond blanc à 4 %, bordure à 8 %, h4 de 13,6 px, p de 11,5 px en blanc à 50 %) part de opacity: 0; transform: translateY(20px) et joue sbFadeUp sur animation-timeline: view(), animation-range: entry 0% entry 50% : le fondu commence quand son haut franchit le bord bas de la boîte et s'achève à moitié entré — 36 px de course pour un panneau de 72 px (mesuré à 1 280 px de large) ; both garde l'état final. Au repos : panneau 1 plein, 2 à 0,88, 3 et 4 à 0 ; le 4 atteint 1 à 184 px. Le bloc couvre les 130 px du haut, les panneaux passent dessous : 150 px de lecture. Ils occupent les pixels 160 à 517 du contenu : dès 387 px de défilement, plus aucun n'apparaît, et les 533 derniers pixels de course — troisième et quatrième paliers — défilent sur du vide (à 390 px de large, les textes passent à la ligne et en comblent une partie). scroll-behavior: smooth ne lisse que les défilements programmés (scrollTop = 460 : 332 ms dans Chromium, 528 ms dans Firefox). Le champ JavaScript est vide ; .sdc-scroll-container, l'indice .sdc-scroll-hint (« Scrollez ↓ », absolu dans le cadre, pulsant de 0,3 à 0,7 en 2 s) et sbFadeUp sont le socle commun de la catégorie, identique dans Split Screen Sticky (fx-0589) : coller les deux sur une page ne crée aucun conflit.
Accessibilité
- prefers-reduced-motion absent du code : mesuré sous émulation, rien ne change — paliers, glissement de 20 px des panneaux, pulsation de l'indice (
running),smooth. Les timelines sont pilotées par le lecteur (animation déclenchée par l'interaction, WCAG 2.3.3), la pulsation non. Ajoutez@media (prefers-reduced-motion: reduce) { .ss-imgchange-panel { animation: none; opacity: 1; transform: none } .sdc-scroll-hint { animation: none } .sdc-scroll-container { scroll-behavior: auto } }; les paliers de couleur ne déplacent rien et peuvent rester. - Clavier : mesuré, Tab focalise la boîte sans
tabindexdans Chromium et Firefox ; flèche bas avance de 40 px (Chromium) ou 51 px (Firefox), Page suivante de 285 / 303 px, Fin va à 920 — paliers et panneaux suivent, les timelines lisent la position, pas le geste. WebKit ne focalise pas une boîte défilante sanstabindex="0": ajoutez-le avec unaria-labelet un style:focus-visible. - Contraste : le « 01 » blanc, 32 px graisse 800 (texte large, seuil 3:1), vaut 4,5:1 sur
#6366f1, 4,2:1 sur#8b5cf6, 3,5:1 sur#d946ef, 3,7:1 sur#f43f5emais 2,2:1 sur l'ambre#f59e0b: le coin bas-droit du dernier palier échoue — passez à#b45309(5,0:1). Titres des panneaux 18:1 ; paragraphe en blanc à 50 % sur le fond effectif#141419: 5,3:1 à 11,5 px, juste au-dessus du seuil. L'indice « Scrollez ↓ », blanc à 30 % sur#0a0a0f, vaut 2,6:1 au repos, de 1,2:1 à 1,8:1 sous la pulsation — les deux opacités se multiplient, 0,09 à 0,21 : décoratif,aria-hidden="true". - Lecteurs d'écran : le bloc est un
divlu « 01 » ; sa couleur n'est pas annoncée — si elle porte un sens (famille, zone, criticité), écrivez-le en toutes lettres, comme le font les trois scènes. Quatreh4sans h2/h3 au-dessus cassent le plan de la page. Les panneaux àopacity: 0restent dans l'arbre d'accessibilité et sont tous lus dès le départ, ce qui est voulu. Sansanimation-timeline(Firefox), tout est visible à plat.overscroll-behavior: containévite d'entraîner la page en bout de boîte.
Compatibilité navigateur
CSS seul : animation-timeline: scroll(nearest) et view(), animation-range, position: sticky, dégradés, @keyframes. Champ JavaScript vide, zéro dépendance. Chrome et Edge 115+, Safari et iOS 26+ ; Firefox : aucune version (mesuré : CSS.supports('animation-timeline: scroll()') = false, durée calculée 0s). Ce qu'un visiteur Firefox voit, mesuré page vierge : la boîte défile, le bloc reste épinglé à 10 px, indigo → violet du début à la fin, sans ombre (elle n'existe que dans les images clés), et les quatre panneaux sont visibles, en place, à opacité 1 — l'animation de 0 s en both se fige sur son état final. Rien de caché : le code n'a pas de @supports et n'en a pas besoin. Pour une ombre sous Firefox, posez un box-shadow dans la règle de base du bloc.
Même chose dans Safari avant 26 et Chrome avant 115 : deux animations de 0 s, panneaux à l'état final, bloc sur sa règle de base, page lisible en entier — seule la couleur ne raconte plus rien. Sans position: sticky, le bloc remonterait avec le contenu ; là où overflow n'est pas honoré (clients mail), le contenu s'étire sur 1 200 px, panneaux visibles.
Le code
Copiez les trois blocs dans votre page. Aucune dépendance.
<div class="sdc-scroll-container">
<div class="ss-imgchange-content">
<div class="ss-imgchange-display">01</div>
<div class="ss-imgchange-panels">
<div class="ss-imgchange-panel"><h4>Premiere Section</h4><p>L'image reste fixe pendant que le contenu defile. Technique ideale pour presenter des fonctionnalites.</p></div>
<div class="ss-imgchange-panel"><h4>Deuxieme Section</h4><p>Chaque section de texte declenche un changement visuel dans l'image sticky.</p></div>
<div class="ss-imgchange-panel"><h4>Troisieme Section</h4><p>Les transitions douces guident l'utilisateur a travers le contenu de maniere fluide.</p></div>
<div class="ss-imgchange-panel"><h4>Quatrieme Section</h4><p>Pattern utilise dans le journalisme interactif et les sites de produits.</p></div>
</div>
</div>
</div>
<span class="sdc-scroll-hint">Scrollez ↓</span>
.ss-imgchange-content {
height: 1200px;
padding: 20px 12px;
}
.ss-imgchange-display {
width: 100%;
height: 120px;
border-radius: 14px;
background: linear-gradient(135deg, #6366f1, #8b5cf6);
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
font-weight: 800;
color: white;
position: sticky;
top: 10px;
z-index: 2;
animation: ssImgChange linear;
animation-timeline: scroll(nearest);
}
.ss-imgchange-panels {
padding-top: 20px;
display: flex;
flex-direction: column;
gap: 16px;
}
.ss-imgchange-panel {
padding: 16px;
border-radius: 12px;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
opacity: 0;
transform: translateY(20px);
animation: sbFadeUp linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
.ss-imgchange-panel h4 {
font-size: 0.85rem;
font-weight: 700;
color: #fff;
margin: 0 0 6px;
}
.ss-imgchange-panel p {
font-size: 0.72rem;
color: rgba(255, 255, 255, 0.5);
margin: 0;
line-height: 1.5;
}
.sdc-scroll-container {
width: 100%;
height: 280px;
overflow-y: auto;
position: relative;
scroll-behavior: smooth;
}
.sdc-scroll-container::-webkit-scrollbar {
width: 4px;
}
.sdc-scroll-container::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.05);
}
.sdc-scroll-container::-webkit-scrollbar-thumb {
background: rgba(139, 92, 246, 0.4);
border-radius: 2px;
}
.sdc-scroll-hint {
position: absolute;
bottom: 8px;
left: 50%;
transform: translateX(-50%);
font-size: 0.65rem;
color: rgba(255, 255, 255, 0.3);
z-index: 5;
pointer-events: none;
animation: sdcHintPulse 2s ease-in-out infinite;
}
@keyframes sbFadeUp {
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes ssImgChange {
0%,
20% {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
box-shadow: 0 8px 30px rgba(99, 102, 241, 0.3);
}
25%,
45% {
background: linear-gradient(135deg, #8b5cf6, #d946ef);
box-shadow: 0 8px 30px rgba(139, 92, 246, 0.3);
}
50%,
70% {
background: linear-gradient(135deg, #d946ef, #f43f5e);
box-shadow: 0 8px 30px rgba(217, 70, 239, 0.3);
}
75%,
100% {
background: linear-gradient(135deg, #f43f5e, #f59e0b);
box-shadow: 0 8px 30px rgba(244, 63, 94, 0.3);
}
}
@keyframes sdcHintPulse {
0%,
100% {
opacity: 0.3;
}
50% {
opacity: 0.7;
}
}
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Paliers de couleur (CSS — @keyframes ssImgChange) |
4 plateaux : 0-20 %, 25-45 %, 50-70 %, 75-100 %, dégradés à 135° | Chaque paire de pourcentages est un plateau, l'écart de 5 % (46 px) une transition : l'ombre s'y fond, le dégradé bascule à mi-chemin (mesuré 207, 437, 667 px). Cinquième palier : redistribuez les pourcentages (0-16, 20-36…) ; vrai fondu : animez background-color sur une couleur unie. |
Course (CSS — .ss-imgchange-content { height: 1200px }, .sdc-scroll-container { height: 280px }) |
920 px (230 px par palier) | Les pourcentages sont ceux de la course entière, 1 200 − 280. Les panneaux s'arrêtent à 517 px : ramenez le contenu à 800px (course 520) pour que les quatre paliers se jouent pendant qu'il reste à lire, ou ajoutez des panneaux. |
Calage des paliers (CSS — animation-range à ajouter sur .ss-imgchange-display) |
absent (normal : 0 % en haut, 100 % en fin de course) |
Deux longueurs en pixels redéfinissent où tombent 0 % et 100 % de la timeline : animation-range: -38px 590px place les bascules (22,5 / 47,5 / 72,5 %) aux offsets où chaque groupe prend le relais. Réglage clé des trois scènes ; à recalculer si les hauteurs changent. |
Révélation des panneaux (CSS — .ss-imgchange-panel, animation-range: entry 0% entry 50%) |
fondu sur la première moitié de l'entrée, 20 px de glissement | entry 0% entry 100% étale le fondu sur toute l'entrée ; entry 48px entry 96px le retarde de 48 px (sous un bandeau bas). Gardez both : sans lui, un panneau sorti de sa plage retombe à opacity: 0. |
Point d'épinglage et hauteur du bloc (CSS — top: 10px, height: 120px) |
10 px / 120 px (130 px couverts, 150 px de lecture) | Un bloc de 60 px laisse 210 px aux panneaux. top: auto; bottom: 8px l'épingle en bas — il doit alors être le dernier enfant du contenu. Le z-index: 2 le garde au-dessus des panneaux. |
Contenu du bloc (HTML — « 01 », CSS — font-size: 2rem; font-weight: 800) |
« 01 », statique | Le texte n'est pas piloté par le défilement : image, SVG ou libellé au choix. Pour un libellé par palier, superposez des span à opacity: 0 sur la même timeline scroll(nearest), chacun avec sa tranche en animation-range — c'est ce que font les scènes. |
Défilement doux, indice et barre (CSS — scroll-behavior: smooth, .sdc-scroll-hint, ::-webkit-scrollbar) |
smooth / « Scrollez ↓ » pulsant 2 s / barre de 4 px | smooth n'agit que sur les positions posées par script ou ancre (mesuré : 460 px en 332 ms). L'indice est du français en dur, absolu dans .demo-preview : traduisez-le ou retirez le span avec sa @keyframes sdcHintPulse. La barre stylée n'existe que dans Chromium et Safari ; pour Firefox, scrollbar-width: thin. |
FAQ
Pourquoi la couleur saute-t-elle d'un coup alors que l'ombre se fond ?
Parce que les images clés animent un linear-gradient, qu'aucun moteur mesuré n'interpole : Chromium passe à la valeur suivante à mi-chemin du segment (22,5 %, 47,5 %, 72,5 % : 207 → 208, 437 → 438, 666 → 667 px), WebKit 26 dès son début (185 px). L'ombre — une couleur, des longueurs — s'interpole normalement sur les 46 px de chaque transition (à 200 px, rgba(113, 99, 243, .3)). Cette bascule nette est le caractère de l'effet : une section, une couleur. Pour un fondu continu, animez background-color sur une couleur unie, ou une variable enregistrée par @property que le dégradé lit.
Qu'est-ce qui le distingue de Split Screen Sticky (fx-0589) ?
Le socle est identique — même boîte .sdc-scroll-container de 280 px, même bloc collé à top: 10px, mêmes panneaux révélés par sbFadeUp sur view() entre entry et entry 50% — mais ce qui est animé au défilement diffère. Dans fx-0589 (premium), le bloc de 100 px garde un fond fixe (#1a1a3e → #2d1b69) et c'est l'icône SVG qu'il contient qui tourne de 360° sur animation-timeline: scroll(), en continu, sur 720 px de course, devant trois cartes à liste. Dans fx-0585, c'est le bloc lui-même qui change : dégradé et ombre par paliers, quatre couleurs pour quatre panneaux, 920 px de course, rien d'animé à l'intérieur. Prenez fx-0585 quand la couleur doit dire où l'on est (famille, zone, criticité) ; fx-0589 quand un visuel fixe doit vivre pendant que le texte défile.
Comment faire coïncider un palier avec chaque panneau, ou chaque groupe de panneaux ?
Par animation-range en pixels sur le bloc, sans toucher aux pourcentages. Relevez l'offset auquel chaque groupe doit prendre le relais (son haut dans le contenu, moins la hauteur où vous voulez qu'il passe : bord bas du bloc, milieu de la boîte) ; ces offsets doivent tomber sur les bascules, à 22,5 %, 47,5 % et 72,5 % de la plage. Pour des relais réguliers, à partir des deux premiers offsets o₁ et o₂ : longueur = (o₂ − o₁) ÷ 0,25, début = o₁ − 0,225 × longueur — un début négatif est permis, le premier palier est simplement déjà entamé au repos. Les trois scènes tiennent ainsi en une ligne (-67px 533px pour douze constats en quatre groupes, course 452 px). Si les groupes ont des hauteurs très différentes, changez plutôt les pourcentages de la @keyframes. Dans le code vendu, rien n'est calé : les paliers se répartissent sur la course entière et les panneaux s'arrêtent à 517 px sur 920.