7.8 KiB
Rapport : corrections scroll colonnes gauche/droite et scale-down du titre
Contexte
Sur les pages full des projets et evenements, deux animations GSAP coexistent :
- Scale-down du titre : le header (titre) retrecit de
scale 1.0 -> 0.4pendant le scroll, avec une translationyqui compense pour garder le bord visuel fixe. - Gel de la colonne gauche : la colonne gauche defile naturellement puis se fige (contre-translation 1:1 du scroll) pendant que la colonne droite (images en
position: sticky) continue.
Les images de la colonne droite sont en position: sticky; top: 0 et s'empilent les unes sur les autres.
Problemes identifies
1. node/573 — image remonte en fin de scroll (FIXE)
Cause : le :after de .field_images avait height: 100vh statique. Quand la colonne gauche est tres haute (texte long), le contexte sticky s'epuisait avant la fin du scroll, et l'image remontait.
Fix :
- CSS :
height: var(--sticky-extent, 100vh)sur le:after(fallback 100vh si pas de JS). - JS :
adjustStickyContext()calculescrollRange - imgHeight + clientHeightet pose la valeur en CSS custom property--sticky-extentsur.field_images. Recalcule au load de chaque image.
Status : fonctionne.
2. node/576 — ecart entre le titre et le contenu (FIXE puis REGRESSIF)
Cause : initHeaderH etait mesure une fois, de maniere synchrone, avant les requestAnimationFrame. Si la police Epilogue ou Splitting changeait la hauteur du header apres cette mesure, end et y etaient faux, creant un ecart visuel entre le bas du header et le contenu.
Fix applique :
yetendtransformes en fonctions qui mesurentpageHeader.offsetHeightau moment ou GSAP en a besoin.initHeaderHsupprime, remplace parpageHeader.offsetHeightpartout (y compris dansleftFreezeStart).
Status : l'ecart est corrige, mais le fix a introduit un nouveau probleme (voir point 4).
3. node/549 et 570 — colonne gauche redescend en fin de scroll (REGRESSIF puis REFIXE)
Cause : leftFreezeStart utilisait Math.max(overflow, titleEnd). Sur 549/570, titleEnd (proportionnel a la hauteur du titre a 12em) peut depasser overflow (hauteur naturelle de la colonne - viewport), ce qui decale le freeze trop loin et la colonne redescend.
Fix applique : retour a la logique d'origine pour leftFreezeStart :
const overflow = leftColumn.offsetHeight - scroller.clientHeight;
if (overflow > 0) return overflow;
return pageHeader ? pageHeader.offsetHeight * (1 - headerScaleTarget) : 0;
Status : fonctionne pour 549/570, mais casse 576 (voir point 4).
4. node/576 — colonne se fige trop tot, titre diminue en descendant (REGRESSIF)
Cause : ensureScrollForTitle agrandit le spacer de la colonne gauche pour garantir assez de scroll pour le scale-down du titre. Le spacer rend overflow > 0, donc leftFreezeStart retourne overflow. Mais overflow peut etre inferieur a titleEnd (le spacer donne juste assez de scroll pour end, pas assez pour que overflow = end). La colonne se fige avant la fin du scale-down, le y pousse le titre vers le bas.
Tentative de fix avec Math.max(overflow, titleEnd) : corrige 576 mais casse 549/570 (voir point 3).
Fix actuel : ensureScrollForTitle est appele avant la creation des ScrollTriggers. La formule du spacer est spacerAdd = end + viewport - colHeight, ce qui garantit que overflow = end = titleEnd apres l'agrandissement. La logique d'origine de leftFreezeStart (if overflow > 0 return overflow) retourne alors une valeur >= titleEnd.
Status : a tester. Le succes depend du timing : si le spacer est bien en place avant le calcul de leftFreezeStart, tout est coherent.
5. node/586 — pas d'image, scroll insuffisant pour le scale-down (NON FIXE)
Cause : sans image, la colonne droite est vide. Le contenu de la colonne gauche est court. Le scroll naturel est insuffisant pour que le titre termine son scale-down.
Fix tente : ensureScrollForTitle agrandit le spacer avec la formule spacerAdd = end + viewport - colHeight. Le scroll resultant devrait etre exactement end.
Probleme : le spacer etait calcule avec l'ancienne formule end - scrollRange qui ne tenait pas compte du viewport. La nouvelle formule corrige le calcul, mais le lenis.resize() au window.load est necessaire pour que Lenis recalcule sa plage de scroll apres le chargement de la police.
Status : partiellement corrige. Le scroll est cree mais peut etre insuffisant si Lenis ne refresh pas correctement. Le lenis.resize() au load a ete ajoute dans initSmoothScroll.
6. node/545 et 583 — pas d'image, texte court, pas de scroll (OK)
Ces pages n'ont pas d'image et le contenu est court. Il n'y a pas de scroll, le titre ne diminue pas. C'est le comportement attendu et accepte.
Fichiers modifies
assets/js/main.js
-
initSmoothScroll():- Ajout de
lenis.resize()+ScrollTrigger.refresh()auwindow.load return lenispour permettre un acces futur
- Ajout de
-
initPageFull():cols,leftColumn,rightColumn,spacer,spacerBaseHeightdeclares en haut de la fonctionadjustStickyContext()defini avantensureScrollForTitle, calcule--sticky-extentbase surscrollRange - imgHeight + clientHeightensureScrollForTitle(): agrandit le spacer siscrollRange < end. Formule :spacerAdd = end + viewport - colHeight. Appele avant legsap.to()et auwindow.load.yetenddu ScrollTrigger du titre : transformes en fonctions() => pageHeader.offsetHeight * (1 - headerScaleTarget)initHeaderHsupprimeleftFreezeStart: logique d'origine (overflowsi > 0, sinontitleEnd), mais avecpageHeader.offsetHeightau lieu deinitHeaderH
assets/scss/main.scss
:afterde.field_images:height: 100vhremplace parheight: var(--sticky-extent, 100vh)
assets/js/titles.js
- Ajout de
measureOverflow(): mesure le debordement du titre sous l'image et posedata-overflow-linessur le h2. Utilise au scroll pour les pages liste (home, archives, projets lies). - Appele dans
initTitles()apres le traitement Splitting de chaque titre.
Points non resolus
- 586 : le scroll cree par le spacer peut etre insuffisant si Lenis ne refresh pas correctement. Le
lenis.resize()auloaddevrait aider mais n'a pas ete confirme. - 576 : depend du timing de
ensureScrollForTitlepar rapport aux ScrollTriggers. Si le spacer n'est pas en place avant le calcul deleftFreezeStart, la colonne se fige trop tot. - Interaction
ensureScrollForTitle/adjustStickyContext: les deux se recalculent mutuellement mais peuvent entrer en conflit si les hauteurs changent apres le chargement. - 549/570 : la logique d'origine de
leftFreezeStartfonctionne, mais toute modification qui changeoverflow(comme le spacer) peut casser le comportement.
Approches envisagees mais abandonnees
Math.max(overflow, titleEnd)dansleftFreezeStart: corrige 576/586 mais casse 549/570.format: 'iife'dans Vite : incompatible avec multiple entry points.format: 'es'dans Vite : ne change pas le output (deja en format classique).type: moduledansleshed.libraries.yml: pour resoudre la redeclarationconst ctentretitles.jsetmain.js.applique mais non teste en prod.
Tests a faire
- 549 : colonne gauche ne redescend pas en fin de scroll
- 570 : colonne gauche ne redescend pas en fin de scroll
- 576 : titre diminue sans descendre, contenu colle au header
- 573 : image ne remonte pas en fin de scroll
- 586 : titre peut terminer son scale-down
- 545 : pas de scroll, titre ne diminue pas (OK)
- 583 : pas de scroll, titre ne diminue pas (OK)
- Pages liste (home, archives) :
data-overflow-linesfonctionne