Реализация CSS View Transitions API для переходов между страницами

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация CSS View Transitions API для переходов между страницами
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Реализация CSS View Transitions API для переходов между страницами

View Transitions API позволяет создавать плавные анимированные переходы между состояниями DOM — или между страницами в MPA/SPA — с помощью нативного браузерного механизма. Браузер делает скриншот текущего состояния, применяет новое, затем анимирует переход. По умолчанию используется crossfade, но через CSS-псевдоэлементы можно реализовать любую анимацию.

Поддержка браузеров

Chrome 111+, Edge 111+, Safari 18+. Firefox — с флагом, без стабильной поддержки на 2025 год. Обязательна проверка через document.startViewTransition перед использованием.

Базовое использование (SPA)

// utils/view-transition.ts

export async function navigateWithTransition(
  updateDOM: () => void | Promise<void>
): Promise<void> {
  // Fallback для браузеров без поддержки
  if (!document.startViewTransition) {
    await updateDOM()
    return
  }

  const transition = document.startViewTransition(async () => {
    await updateDOM()
  })

  try {
    await transition.finished
  } catch (e) {
    // Переход был прерван (новый переход начался)
    if (!(e instanceof DOMException && e.name === 'AbortError')) {
      throw e
    }
  }
}

Интеграция с React Router / Next.js

React Router v6

// router/transition-router.tsx
import { useNavigate } from 'react-router-dom'
import { navigateWithTransition } from '../utils/view-transition'

export function useTransitionNavigate() {
  const navigate = useNavigate()

  return (to: string, options?: { replace?: boolean }) => {
    navigateWithTransition(() => {
      navigate(to, options)
    })
  }
}

Next.js App Router

Next.js 14+ поддерживает View Transitions через unstable_viewTransition в next/link:

// app/components/TransitionLink.tsx
'use client'
import Link from 'next/link'
import { useRouter } from 'next/navigation'

export function TransitionLink({
  href,
  children,
  className,
}: {
  href: string
  children: React.ReactNode
  className?: string
}) {
  const router = useRouter()

  const handleClick = (e: React.MouseEvent) => {
    e.preventDefault()
    if (!document.startViewTransition) {
      router.push(href)
      return
    }
    document.startViewTransition(() => {
      router.push(href)
    })
  }

  return (
    <a href={href} onClick={handleClick} className={className}>
      {children}
    </a>
  )
}

CSS: кастомные анимации переходов

/* styles/view-transitions.css */

/* Псевдоэлементы по умолчанию */
::view-transition-old(root) {
  animation: fade-out 0.2s ease-out;
}

::view-transition-new(root) {
  animation: fade-in 0.3s ease-out;
}

@keyframes fade-out {
  to { opacity: 0; }
}

@keyframes fade-in {
  from { opacity: 0; }
}

/* Слайд для навигации */
@keyframes slide-from-right {
  from { transform: translateX(40px); opacity: 0; }
}

@keyframes slide-to-left {
  to { transform: translateX(-40px); opacity: 0; }
}

/* Применяем к конкретному направлению (атрибут на html) */
html[data-transition="forward"] {
  &::view-transition-old(root) {
    animation: slide-to-left 0.25s ease-in both;
  }
  &::view-transition-new(root) {
    animation: slide-from-right 0.25s ease-out both;
  }
}

html[data-transition="backward"] {
  &::view-transition-old(root) {
    animation: 0.25s ease-in both reverse slide-from-right;
  }
  &::view-transition-new(root) {
    animation: 0.25s ease-out both reverse slide-to-left;
  }
}

Установка атрибута при навигации:

// Определяем направление перед стартом перехода
function navigate(to: string, history: string[]) {
  const isBack = history[history.length - 2] === to
  document.documentElement.dataset.transition = isBack ? 'backward' : 'forward'

  document.startViewTransition(() => {
    // Обновление DOM/маршрута
    router.push(to)
  })
}

Именованные view-transition-name: общие элементы

Именованные переходы позволяют плавно "переносить" элемент между страницами (shared element transition):

/* Страница списка */
.product-card-image {
  view-transition-name: product-image; /* уникальное имя */
}

/* Страница детального просмотра */
.product-detail-image {
  view-transition-name: product-image; /* то же имя */
}

/* Браузер сам анимирует переход от одного к другому */
::view-transition-group(product-image) {
  animation-duration: 0.4s;
  animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

Для динамических имён (список товаров):

// components/ProductCard.tsx
export function ProductCard({ product }: { product: Product }) {
  return (
    <div>
      <img
        src={product.image}
        alt={product.name}
        style={{
          // view-transition-name должно быть уникальным в DOM
          viewTransitionName: `product-image-${product.id}`,
        }}
      />
    </div>
  )
}
// pages/product/[id]/page.tsx
export default function ProductDetail({ params }: { params: { id: string } }) {
  return (
    <img
      src={product.image}
      style={{ viewTransitionName: `product-image-${params.id}` }}
    />
  )
}

Управление паузой и готовностью

async function transitionWithControl(update: () => void) {
  const transition = document.startViewTransition(update)

  // Ждём пока старый контент скопирован
  await transition.ready

  // Здесь можно запустить дополнительные Web Animations
  document.documentElement.animate(
    { opacity: [1, 0.8, 1] },
    { duration: 300, pseudoElement: '::view-transition-new(root)' }
  )

  await transition.finished
}

Отключение для prefers-reduced-motion

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
  }
}

Типичные сроки

Базовый crossfade между страницами Next.js/React Router — 4–6 часов. Направленные слайд-переходы + shared element transitions для списка/детали — 2–3 рабочих дня. Полная система с управлением направлением, fallback, тестами и поддержкой Safari — 3–4 рабочих дня.