Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

View Transitions

Переход transition анимирует смену свойства: цвета, размера. Но когда содержимое страницы заменяется целиком — новый текст, другой порядок карточек, другая страница, — анимировать нечего. View Transitions (переходы между видами) решают это: браузер запоминает, как страница выглядела до изменения и после, и плавно превращает одно в другое.

Первый переход

Переход запускают из JavaScript методом document.startViewTransition(). Ему передают функцию, которая меняет страницу, — остальное браузер делает сам. Нажмите на кнопку:

<style>
  .tip { padding: 16px; background: lavender; }
</style>
 
<button onclick="nextTip()">Следующий совет</button>
<p class="tip" id="tip">Пейте больше воды.</p>
 
<script>
  const tips = ["Пейте больше воды.", "Делайте перерывы.", "Гуляйте каждый день."];
  let index = 0;
 
  function nextTip() {
    document.startViewTransition(() => {
      index = (index + 1) % tips.length;
      document.querySelector("#tip").textContent = tips[index];
    });
  }
</script>

Старый текст тает, новый проявляется. Без перехода он сменился бы мгновенно.

Псевдоэлементы перехода

На время перехода браузер строит над страницей дерево псевдоэлементов — снимков старого и нового вида. Их оформляют в CSS, как обычные элементы:

ПсевдоэлементЧто это
::view-transitionслой над страницей, в котором идёт переход
::view-transition-group(имя)группа одного элемента, двигает и меняет размер
::view-transition-old(имя)снимок до изменения
::view-transition-new(имя)снимок после изменения

Вся страница по умолчанию называется root. Замедлим переход из прошлого примера до секунды:

<style>
  .tip { padding: 16px; background: lavender; }
  ::view-transition-old(root),
  ::view-transition-new(root) { animation-duration: 1s; }
</style>
 
<button onclick="document.startViewTransition(() => document.querySelector('#tip').textContent = 'Делайте перерывы.')">Сменить совет</button>
<p class="tip" id="tip">Пейте больше воды.</p>

view-transition-name

Свойство view-transition-name даёт элементу собственное имя. Такой элемент анимируется отдельно от страницы: браузер плавно переносит его со старого места на новое и меняет размер:

<style>
  .stage { display: flex; height: 120px; padding: 8px; background: whitesmoke; }
  .ball { width: 40px; height: 40px; border-radius: 50%; background: tomato; view-transition-name: ball; }
  .stage.moved { justify-content: flex-end; align-items: flex-end; }
  .stage.moved .ball { width: 80px; height: 80px; }
</style>
 
<button onclick="document.startViewTransition(() => document.querySelector('#stage').classList.toggle('moved'))">Переместить</button>
<div class="stage" id="stage"><div class="ball"></div></div>

Класс переключается мгновенно, а мяч всё равно летит и растёт — эту анимацию построил браузер.

Поддержка браузерами

Переходы внутри страницы работают во всех основных браузерах с конца 2025 года — Firefox добавил их последним. Для старых браузеров проверяют, есть ли метод, и меняют страницу без анимации:

<button onclick="update()">Обновить</button>
<p id="text">Было</p>
 
<script>
  function update() {
    const change = () => document.querySelector("#text").textContent = "Стало";
    if (!document.startViewTransition) {
      change();
      return;
    }
    document.startViewTransition(change);
  }
</script>

Переходы между страницами

Тот же эффект возможен при переходе по обычной ссылке на другую страницу сайта — без JavaScript. Для этого в CSS обеих страниц пишут правило @view-transition { navigation: auto; }. Браузер свяжет старую и новую страницу, а элементы с одинаковым view-transition-name перелетят на новое место. Показать это в окне примера нельзя: нужны две настоящие страницы одного сайта. На момент написания такие переходы поддерживают Chrome, Edge и Safari, а в остальных браузерах страница просто открывается без анимации.

Частая ошибка

Одно имя у двух элементов. view-transition-name должно быть уникальным на странице: если имя повторяется, браузер отменяет анимацию, и страница меняется рывком:

<style>
  .box { width: 60px; height: 40px; margin: 4px 0; background: steelblue; view-transition-name: box; }
  .wide { width: 200px; }
</style>
 
<button onclick="document.startViewTransition(() => document.querySelectorAll('.box').forEach(b => b.classList.toggle('wide')))">Изменить</button>
<div class="box"></div>
<div class="box"></div>

Блоки расширяются без анимации. Если элементов много, дайте каждому своё имя: card-1, card-2 и так далее.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.