lenec ru

← все посты

View Transitions API в Astro: реальные кейсы

19K

View Transitions появились в Astro ещё в третьей версии и за это время превратились из красивой демки в рабочий инструмент. Я их использую в трёх проектах: сайте конференции, корпоративном блоге и интернет-магазине одежды. Везде по-разному — где-то это просто плавный fade между страницами, где-то — анимация перетекающего изображения с карточки в детальную.

В этой заметке покажу четыре реальных кейса с кодом и оговорками. Ничего фантастического, всё работает в стабильных Chrome и Firefox 2026.

Что такое View Transitions в Astro

Это надстройка над браузерным API document.startViewTransition. Astro между навигациями делает MPA похожим на SPA: подменяет HTML без перезагрузки и анимирует переходы. Для подключения хватает одной строчки в общем layout:

---
import { ViewTransitions } from 'astro:transitions';
---
<html lang="ru">
  <head>
    <ViewTransitions />
  </head>
  <body><slot /></body>
</html>

Этого достаточно для базового fade. Дальше — кастомизация по элементам.

Кейс 1. Карточка → детальная страница (shared element)

На сайте, где у каждой статьи есть обложка, хочется, чтобы при клике картинка не «прыгала» с маленькой превьюшки до большой, а плавно перетекала. Для этого обоим элементам ставим одно и то же transition:name:

<!-- список -->
<a href={`/p/${post.slug}`}>
  <img
    src={post.cover}
    alt={post.title}
    transition:name={`cover-${post.slug}`}
  />
  <h2 transition:name={`title-${post.slug}`}>{post.title}</h2>
</a>

<!-- детальная -->
<img src={post.cover} alt={post.title} transition:name={`cover-${post.slug}`} />
<h1 transition:name={`title-${post.slug}`}>{post.title}</h1>

На клик карточка плавно увеличивается, заголовок переезжает, всё выглядит как родное SPA. Браузеру для этого ничего больше не нужно, никакой настройки CSS. Хитрость: transition:name должен быть уникальным для пары «исходный — целевой», иначе анимация не сцепится.

Кейс 2. Кастомная анимация перехода

По умолчанию Astro делает fade. Хочется, например, slide-up для главной и обычный fade для остальных. Это решается через transition:animate:

<main transition:animate="slide">
  <slot />
</main>

Доступные варианты: fade (по умолчанию), slide, none и initial. Если хочется свою — описываешь через CSS-переменную:

::view-transition-old(root) {
  animation: 220ms cubic-bezier(0.4, 0, 0.2, 1) both fade-out;
}
::view-transition-new(root) {
  animation: 220ms cubic-bezier(0.4, 0, 0.2, 1) both slide-in-up;
}

@keyframes fade-out { to { opacity: 0; } }
@keyframes slide-in-up { from { transform: translateY(8px); opacity: 0; } }

Кейс 3. Сохранение состояния (persist)

На магазине есть плеер с обзором коллекции, который не хочется перезагружать при переходе между страницами. Для этого Astro даёт директиву transition:persist:

<audio controls transition:persist="main-player">
  <source src="/audio/playlist.mp3" type="audio/mpeg" />
</audio>

Ключевое — одинаковое имя в transition:persist на обеих страницах. Astro переиспользует тот же DOM-узел, и плеер продолжает играть после смены маршрута. Я так же использую этот приём для верхней навигации с открытым выпадающим меню — выглядит как SPA, хотя страницы перезагружаются.

Кейс 4. Условное отключение для пользователей

Анимации не для всех. У части пользователей выставлен prefers-reduced-motion: reduce, и им нужны мгновенные переходы. Astro уважает это значение автоматически — если браузер сообщает «без движения», переходов не будет. Но если хочешь дать пользователю явный выключатель — добавь свой переключатель и хранение в cookie.

document.addEventListener('astro:before-preparation', (e) => {
  if (localStorage.getItem('animations') === 'off') {
    e.preventDefault();
  }
});

Тут e.preventDefault() отменяет View Transition, и страница откроется обычной перезагрузкой. На больших сайтах с тяжёлыми анимациями такой выключатель — заметная плюсуха к UX.

События жизненного цикла

Astro даёт несколько кастомных событий, которые удобно слушать:

  • astro:before-preparation — перед началом перехода;
  • astro:after-preparation — когда новый HTML уже разобран, но ещё не вставлен;
  • astro:before-swap — перед заменой DOM (можно подменить заголовок страницы и т. п.);
  • astro:after-swap — DOM подменён, можно повторно проинициализировать сторонние библиотеки;
  • astro:page-load — финальный, аналог DOMContentLoaded для SPA-режима.

На after-swap я обычно перезапускаю прогресс-бар чтения, переинициализирую подсветку кода (Prism, Shiki) и подключаю клиентский поиск.

Тонкости

Транзишены не работают между совсем разными типами страниц. Если у тебя главная — статика, а блог — SSR с динамическим списком, переход будет, но shared elements не сработают, потому что DOM соответствующего узла в исходной странице нет.

Sticky-элементы (липкая шапка) часто моргают, потому что во время анимации они не «знают», на какой стороне находятся. Лечение — задать им transition:name с уникальным именем и явный layout: тогда браузер сам сделает корректный shared transition.

Очень тяжёлые анимации (большие изображения, много DOM-узлов) ловят кадровый jank. Если стресс-тест ругается — упрости целевой DOM или ограничь анимацию через contain: paint на родителе.

Совместимость

На январь 2026 поддержка View Transitions: Chromium-браузеры — стабильно с версии 111, Firefox — с 124, Safari — с 17.4. Везде, где не поддерживается, переход просто превращается в обычный фейд через Astro-fallback. Юзер ничего «сломанного» не увидит.

Когда не использовать

  • Если сайт состоит из одной страницы — нечего переходить.
  • Если у тебя SSR с длинным временем ответа: переход начнётся, а потом будет ждать сервер и выглядеть зависшим. Я в таких местах либо отключаю транзишен, либо показываю промежуточный лоадер через loading.astro.
  • Если используешь сторонний роутер (например, htmx) — в нём своя логика навигации.

Что дальше

View Transitions — недешёвая в плане сил кастомизация на старте, но возвращает массу очков восприятия проекта. Раньше за плавную смену страниц приходилось платить целым SPA-фреймворком и SSR-стеком; теперь — одной строчкой и осмысленной разметкой. Для контентных сайтов это, на мой взгляд, must-have.

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.