Организуй магнитную прокрутку, переходы между состояниями, которые анимирует сам браузер, и строгое уважение к prefers-reduced-motion.
Открыть этот урок в KodokonВ scroll snap участвуют два актёра: контейнер задаёт snapport (свою видимую область, ужатую на scroll-padding) и стратегию через scroll-snap-type - proximity притягивает только вблизи точки привязки, а mandatory гарантирует, что ты всегда окажешься на одной из них, даже после программной прокрутки. Дети объявляют свою область выравнивания через scroll-snap-align (её можно подстроить через scroll-margin). Малоизвестная тонкость: при быстром свайпе браузер имеет полное право перескочить через несколько точек привязки; scroll-snap-stop: always заставляет его останавливаться на каждой - незаменимо для карусели в духе сторис.
.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;
}API View Transitions анимирует смену состояния DOM без единой библиотеки. document.startViewTransition(callback) делает визуальный снимок текущего состояния, выполняет твой колбэк (который меняет DOM), затем анимирует переход между старым и новым состоянием. Под капотом браузер строит поверх страницы дерево псевдоэлементов: ::view-transition содержит элементы ::view-transition-group, каждый из которых держит ::view-transition-old (снимок, замещаемое содержимое, сравнимое с картинкой) и ::view-transition-new (живое представление). По умолчанию - перекрёстное затухание. Во время перехода страница не интерактивна.
function applyUpdate(updateDom) {
if (!document.startViewTransition) {
updateDom();
return;
}
document.startViewTransition(() => updateDom());
}Настоящая сила приходит с view-transition-name: именованный элемент выносится в собственную группу перехода. Если элемент с тем же именем существует до и после, браузер сам интерполирует положение и размер между ними - эффект морфинга из миниатюры в полноэкранный вид, без единой строки анимации на JavaScript. Каждое имя должно быть уникальным на странице в любой момент времени, иначе переход отменяется. Псевдоэлементы стилизуются обычными CSS-анимациями.
.hero-thumb { view-transition-name: hero; }
::view-transition-old(hero),
::view-transition-new(hero) {
animation-duration: 0.4s;
animation-timing-function: ease-in-out;
}Остаётся обязанность по доступности: prefers-reduced-motion: reduce сигнализирует о пользователе, чувствительном к движению (вестибулярные нарушения, мигрени). Уменьшить не значит убрать: затухание по opacity остаётся приемлемым; нейтрализовать нужно крупные перемещения, зумы и параллакс. Защитное глобальное переопределение в CSS ты уже знаешь (околонулевые длительности, разбирали в предыдущем модуле); view transitions добавляют второй фронт: со стороны JavaScript спрашивай window.matchMedia("(prefers-reduced-motion: reduce)") перед запуском перехода или анимированной прокрутки.
const reduceMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
if (reduceMotion || !document.startViewTransition) {
updateDom();
} else {
document.startViewTransition(() => updateDom());
}