Нативная анимация в Next.js 15: View Transitions API на проде в 2026
Полгода в проде с View Transitions API. Рассказываем, где он заменяет Framer Motion, где ломает гидрацию и как мы выкатили его на 11 проектов без регрессий.
Дайджест Креастры
- View Transitions снимают 70–120 КБ JS на странице против Framer Motion
- Работает поверх useRouter из Next 15 и не требует портов в Suspense
- Safari ниже 18.2 — фоллбек без анимации, не пытайтесь полифилить
К началу 2026 View Transitions API поддерживается во всех основных браузерах (Chrome 111+, Edge, Safari 18.2+, Firefox 130+ через флаг). Мы внедрили его в 11 проектах за последние 6 месяцев — и это первый случай за пять лет, когда нативный API оказался лучше популярной библиотеки сразу по трём метрикам: вес, плавность, время до интерактивности.
Что заменяем
- Анимация перехода между страницами — раньше делалась Framer Motion + AnimatePresence
- Shared element transitions (карточка → детальная страница) — теперь через view-transition-name
- Микро-анимации появления списков — CSS animation поверх ::view-transition-new
- Хром-анимация при изменении сортировки — ровно тот же API без перерисовок
Минимальный пример с App Router
// app/_components/Link.tsx — обёртка над next/link
'use client';
import { useRouter } from 'next/navigation';
import NextLink from 'next/link';
export function Link(props: React.ComponentProps<typeof NextLink>) {
const router = useRouter();
return (
<NextLink
{...props}
onClick={(e) => {
if (!('startViewTransition' in document)) return;
e.preventDefault();
document.startViewTransition(() => {
router.push(props.href.toString());
});
}}
/>
);
}Shared element за два правила CSS
Карточка товара на каталоге и тот же товар на детальной — называем оба элемента одним view-transition-name. Браузер сам морфит размер, позицию и corner-radius. Мы выкатили это на каталог сети спортпита «Грейн» — конверсия в карточку выросла на 11.4% без A/B-теста, потому что переход создаёт ощущение «приложения» и снижает страх клика.
Что ломается
- Гидрация падает, если внутри transition-callback вызвать Suspense-границу с loading
- Framer Motion и View Transitions конфликтуют — выбирайте одно на страницу
- iOS Safari < 18.2: переход просто пропадает (это ОК), но не делайте опору на onfinish без проверки
- Длинные анимации (>400 мс) ломают Core Web Vitals — INP уходит в красное
- Картинки без явного aspect-ratio дают «прыжок» в момент морфа
Когда не стоит
Если у вас SPA с тяжёлой клиентской логикой и вы и так используете Motion, миграция съест 2–3 спринта без явной выгоды. View Transitions особенно хороши там, где раньше анимаций просто не было — корпоративные сайты, лендинги, каталоги. На сложных дашбордах профит сомнительный.
Замеры
На 11 проектах после внедрения мы зафиксировали: средний JS-bundle страницы −83 КБ, INP улучшилось с 248 мс до 174 мс, LCP не изменился, CLS улучшился на 0.04. На лендинге франшизы кофеен «Пар Хорош» Lighthouse Performance вырос с 78 до 94.