Распространенным шаблоном для веб-страниц является использование JavaScript для динамической замены содержимого страницы без загрузки нового полного HTML-документа. Это называется одностраничным приложением (SPA). Переходы между представлениями позволяют продемонстрировать преемственность или контекст между страницами в SPA.
Полные переходы страниц
Когда пользователь переходит к новому представлению в вашем SPA, фреймворк заменяет DOM новым контентом. В результате контент просто отображается, но что, если вам нужно обеспечить переход между текущим и новым контентом?
Переходы часто отображают одновременно как старый, так и новый вид, например, плавное исчезновение старого вида и появление нового. Поскольку существующий контент заменяется, это представляло собой проблему до появления переходов между видами.
Чтобы использовать переходы между представлениями, необходимо обернуть логику изменения DOM в обратный вызов. Для этих примеров мы используем базовую реализацию маршрутизатора, предоставляемую веб-компонентом MyRouter
. Способ включения переходов между представлениями зависит от используемого маршрутизатора и фреймворка.
document.startViewTransition(() => updateTheDOMSomehow());
Это включает переход по умолчанию, при котором старый вид постепенно исчезает, а новый вид постепенно появляется.
Что здесь происходит? При вызове document.startViewTransition()
браузер делает снимок старого представления. Затем он вызывает переданную вами функцию обратного вызова, которая обновляет DOM в соответствии с новым представлением (но пока не отображает его). После завершения функции обратного вызова браузер начинает переход к новому контенту.
// Fallback for browsers that don't support this API:
if (!document.startViewTransition) {
updateTheDOMSomehow();
return;
} else {
// With a View Transition:
document.startViewTransition(() => updateTheDOMSomehow());
}
Настройка перехода
Как вы видели в предыдущем примере, стандартный переход между представлениями плавно затухает старое представление и постепенно появляется новое. Вы можете настроить переход в соответствии со стилем вашего сайта, стилизовав псевдоэлементы, создаваемые при переходах между представлениями.
Вы можете указать исходящий переход с помощью ::view-transition-old()
и входящий переход с помощью ::view-transition-new()
. Вы также можете указать значения для обоих переходов с помощью ::view-transition-group()
.
В этом примере старый вид будет скрыт с помощью перехода slide-out-to-left
, а новый — с помощью перехода slide-in-from-right
. Длительность обоих переходов составит 200 миллисекунд.
::view-transition-group(root){
animation-duration: 200ms;
}
::view-transition-old(root) {
animation-name: slide-out-to-left;
}
::view-transition-new(root) {
animation-name: slide-in-from-right;
}
Различные переходы в зависимости от контекста
Возможно, вам захочется реализовать разные переходы в зависимости от действий пользователя. Например, если при нажатии на ссылку на главной странице открывается новое представление справа, можно ожидать, что при нажатии на ссылку для возврата на главную страницу откроется главное представление слева.
Вы можете задать различные анимации, используя псевдокласс :active-view-transition-type()
.
html:active-view-transition-type(forwards) {
&::view-transition-old(root) {
animation-name: slide-out-to-left;
}
&::view-transition-new(root) {
animation-name: slide-in-from-right;
}
}
Затем вы можете выбрать, какой тип перехода представления использовать при вызове document.startViewTransition()
.
const direction = next === 'home' ? 'backwards' : 'forwards';
document.startViewTransition({
update: updateTheDOMSomehow,
types: [direction],
});
Переход определенных элементов
До сих пор вы применяли переход только к корневому элементу для анимации всего представления. Но вы также можете использовать переходы представлений для анимации отдельных частей страниц.
Например, в старом представлении может быть контент, совпадающий с контентом в новом представлении. Это может быть название контента или изображение. В старом представлении это может быть даже миниатюра, а в новом — видео.
Во-первых, необходимо указать, какие элементы будут переходить, используя свойство view-transition-name
. Для работы переходов между представлениями для каждого view-transition-name
должен быть ровно один элемент до вызова document.startViewTransition()
и ровно один элемент после завершения обратного вызова в document.startViewTransition()
.
В этом примере музыкальный проигрыватель отображает обложку альбома, название и имя исполнителя. В другом представлении тот же контент отображается в переработанном виде, с добавлением текстов песен.
В предыдущем примере в старом и новом представлениях присутствует ровно по одному элементу каждого из перенесённых элементов, и у них даже одинаковые селекторы. Элементы, подвергшиеся переходу, как будто меняют свои размеры и положение. Неперенесённые элементы представления плавно появляются и исчезают.
Рассмотрим более сложный пример. Например, на главной странице блога могут отображаться заголовок и изображение для каждой записи, и они также присутствуют в полноэкранном режиме просмотра записи. При переходе с главной страницы к конкретной записи можно сделать так, чтобы заголовок и изображение перемещались в новое место, чтобы обеспечить контекст.
Чтобы сделать это для заголовка, необходимо задать для элемента title свойство view-transition-name
, уникальное в старом представлении, общее для элемента title в новом представлении и уникальное для нового представления. Это сложная задача, поскольку на главной странице несколько заголовков и изображений, и неизвестно, на какое из них нажмёт пользователь.
Есть два варианта решения этой проблемы. Вы можете добавить уникальное имя view-transition-name
для каждой публикации на главной странице, а затем сопоставлять это имя с каждой публикацией на полной странице. Вы можете сгенерировать имя view-transition-name, используя идентификатор публикации. Другой вариант — использовать универсальное view-transition-name
, но применять его только после того, как пользователь нажмёт на публикацию, но до вызова document.startViewTransition()
.
Проектирование переходов
Переходы между представлениями — это набор инструментов, которые можно использовать для ориентации пользователей и предоставления дополнительных подсказок по бренду или контексту. Скорее всего, вы будете использовать несколько методов, чтобы найти подходящие для вашего сайта переходы.
В зависимости от желаемого эффекта вам может потребоваться настроить элементы или анимацию. В предыдущем примере для достижения плавных переходов было изменено несколько стилей.
Заголовок имеет правило width: fit-content
, что является полезным стилем при переходе текста, который не переносится (или имеет одинаковый перенос как в старом, так и в новом представлении). В противном случае переход может осуществляться между элементами с разной шириной, что сделает переход менее плавным.
Изображение также имеет разное соотношение сторон в старом и новом представлениях. В этом примере изменены анимация и свойство object-fit
, чтобы переход выглядел плавным.
Уважение prefers-reduced-motion
Одна из распространённых причин, по которой пользователи запрашивают уменьшение анимации, заключается в том, что полноэкранная анимация, например, та, которая достигается при смене вида, может вызывать дискомфорт у людей с вестибулярными двигательными нарушениями. Вы можете отключить анимацию с помощью медиазапроса prefers-reduced-motion
. Вы также можете выбрать альтернативную анимацию, которая будет менее выраженной, но при этом будет передавать взаимосвязь элементов.
@media (prefers-reduced-motion) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
Проверьте свое понимание
Каково имя псевдоэлемента, представляющего представление до вызова document.startViewTransition()
?
::view-transition-previous
::view-transition-prior
::view-transition-old
::view-transition-initial
Какая анимация используется по умолчанию для перехода между представлениями?
Какое view-transition-name
страницы используется по умолчанию?
document
shadow-root
root
body