Orchestrez des défilements magnétiques, des transitions d'état animées par le navigateur et un respect rigoureux de prefers-reduced-motion.
Ouvrir cette leçon dans KodokonLe scroll snap repose sur deux acteurs : le conteneur définit un snapport (sa zone visible, réduite par scroll-padding) et une stratégie via scroll-snap-type - proximity n'aimante que près d'un point d'accroche, mandatory garantit de toujours finir sur un point, même après un défilement programmatique. Les enfants déclarent leur zone d'alignement avec scroll-snap-align (ajustable par scroll-margin). Subtilité méconnue : lors d'un swipe rapide, le navigateur peut légitimement sauter plusieurs points ; scroll-snap-stop: always l'oblige à s'arrêter sur chacun, indispensable pour un carrousel de type story.
.carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding-inline: 1rem;
}
.carousel > article {
flex: 0 0 80%;
scroll-snap-align: center;
scroll-snap-stop: always;
}L'API View Transitions anime un changement d'état DOM sans bibliothèque. document.startViewTransition(callback) capture un instantané visuel de l'état courant, exécute votre callback (qui mute le DOM), puis anime entre ancien et nouvel état. Sous le capot, le navigateur construit un arbre de pseudo-éléments au-dessus de la page : ::view-transition contient des ::view-transition-group, chacun abritant ::view-transition-old (l'instantané, un contenu remplacé comparable à une image) et ::view-transition-new (la représentation vivante). Par défaut : fondu croisé. La page est non interactive pendant la transition.
function applyUpdate(updateDom) {
if (!document.startViewTransition) {
updateDom();
return;
}
document.startViewTransition(() => updateDom());
}Le vrai pouvoir vient de view-transition-name : un élément nommé est extrait dans son propre groupe de transition. Si un élément portant le même nom existe avant et après, le navigateur interpole automatiquement position et taille entre les deux - l'effet de morphing d'une vignette vers son plein écran, sans une ligne de JavaScript d'animation. Chaque nom doit être unique dans la page à un instant donné, sous peine d'abandon de la transition. Les pseudo-éléments se stylent avec des animations CSS ordinaires.
.hero-thumb { view-transition-name: hero; }
::view-transition-old(hero),
::view-transition-new(hero) {
animation-duration: 0.4s;
animation-timing-function: ease-in-out;
}Reste l'obligation d'accessibilité : prefers-reduced-motion: reduce signale un utilisateur sensible au mouvement (troubles vestibulaires, migraines). Réduire ne veut pas dire supprimer : un fondu d'opacité reste acceptable, ce sont les grands déplacements, zooms et parallaxes qu'il faut neutraliser. Vous connaissez déjà la surcharge globale défensive en CSS (durées quasi nulles, vue au module précédent) ; les view transitions ajoutent un second front : côté JavaScript, interrogez window.matchMedia("(prefers-reduced-motion: reduce)") avant de lancer une transition ou un scroll animé.
const reduceMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
if (reduceMotion || !document.startViewTransition) {
updateDom();
} else {
document.startViewTransition(() => updateDom());
}