View Transition API 可讓您輕鬆透過單一步驟變更 DOM,同時在兩種狀態之間建立動畫轉場。適用於 Chrome 111 以上版本。
為什麼需要這項功能?
頁面轉場效果不僅美觀,還能傳達流程的方向,並確保每個頁面和頁面之間的元素相關。甚至可以在資料擷取期間發生,從而更快地察覺效能。
不過,我們已在網路上提供動畫工具,例如 CSS 轉場效果、CSS 動畫和 Web Animation API,那麼為什麼我們需要新的東西來移動內容?
事實上,即使使用已經擁有的工具,狀態轉換也不太容易。
就算只是簡單的交叉漸變效果,仍會同時出現這兩個狀態。這會造成可用性上的問題,例如處理傳出元素的額外互動。此外,以輔助裝置使用者來說,我們則會同時將「前後對照」狀態儲存在 DOM 中,因此在樹狀圖中移動的位置可能會看起來很清楚,但很容易造成閱讀位置和焦點消失。
如果兩個狀態在捲動位置不同,處理狀態變更就特別困難。而且,如果元素從一個容器移至另一個容器,您可能會遇到 overflow: hidden
和其他形式的裁剪問題,這表示您必須重新建構 CSS 才能達到想要的效果。
這個過程並不不可能,只是非常困難。
「檢視畫面轉換」可讓您更輕鬆地變更 DOM,使狀態之間不會重疊,但可使用快照檢視畫面建立狀態之間的轉場動畫。
此外,雖然目前的導入方式是指定單頁應用程式 (SPA),但我們也會擴充這項功能,讓應用程式在載入完整頁面時執行轉換,這是目前不可能實現的目標。
標準化狀態
這項功能正在 W3C CSS Working Group 中開發,做為草稿規格。
在我們滿意 API 設計後,就會啟動必要的程序和檢查,讓這項功能穩定地推出。
開發人員的意見十分重要,因此請在 GitHub 上提出問題,並附上建議和問題。
最簡單的轉場方式:交叉淡出
預設的檢視畫面轉換效果為交叉淡出,因此適合用來熟悉 API:
function spaNavigate(data) {
// Fallback for browsers that don't support this API:
if (!document.startViewTransition) {
updateTheDOMSomehow(data);
return;
}
// With a transition:
document.startViewTransition(() => updateTheDOMSomehow(data));
}
其中 updateTheDOMSomehow
會將 DOM 變更為新狀態。您可以視需要執行此動作:新增/移除元素、變更類別名稱、變更樣式等等。
這樣頁面就會交叉淡出:
好,交叉漸變的淡出效果並不讓人印象深刻。幸好,您可以自訂轉場效果,但在開始這麼做之前,我們需要瞭解這種基本交叉漸變的運作方式。
轉換作業的運作方式
從上方擷取程式碼範例:
document.startViewTransition(() => updateTheDOMSomehow(data));
呼叫 .startViewTransition()
時,API 會擷取網頁目前狀態。包括擷取螢幕截圖。
完成後,系統會呼叫傳遞至 .startViewTransition()
的回呼。這時 DOM 就會改變。接著,API 會擷取網頁的新狀態。
擷取狀態後,API 會建構虛擬元素樹狀結構,如下所示:
::view-transition
└─ ::view-transition-group(root)
└─ ::view-transition-image-pair(root)
├─ ::view-transition-old(root)
└─ ::view-transition-new(root)
::view-transition
位於頁面上其他地區的疊加層中。如果您想為轉場效果設定背景顏色,這個方法就非常實用。
::view-transition-old(root)
是舊檢視畫面的螢幕截圖,而 ::view-transition-new(root)
是新檢視畫面的「即時」表示法。兩者都會顯示為 CSS 的「替換內容」(例如 <img>
)。
舊檢視畫面會從 opacity: 1
到 opacity: 0
的動畫效果,新檢視畫面會從 opacity: 0
到 opacity: 1
的動畫呈現,形成交叉淡出。
所有動畫都是透過 CSS 動畫執行,因此可使用 CSS 加以自訂。
易於自訂
上述所有虛擬元素都可透過 CSS 指定,而且由於動畫是使用 CSS 定義,因此您可以使用現有的 CSS 動畫屬性進行修改。例如:
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 5s;
}
隨著這項變更,漸進效果真的會非常緩慢:
嗯,還不算滿意。而是實作 Material Design 的共用軸轉換:
@keyframes fade-in {
from { opacity: 0; }
}
@keyframes fade-out {
to { opacity: 0; }
}
@keyframes slide-from-right {
from { transform: translateX(30px); }
}
@keyframes slide-to-left {
to { transform: translateX(-30px); }
}
::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
結果如下:
轉換多個元素
在先前的示範中,整個網頁都涉及到共用軸轉換。這適用於網頁上的大部分內容,但並不適合該標題,因為投影片會再次滑出。
為了避免這種情況,請從網頁的其他部分擷取標頭,然後為標題個別建立動畫。方法是為元素指派 view-transition-name
。
.main-header {
view-transition-name: main-header;
}
view-transition-name
的值不限,但 none
除外,這表示沒有轉換名稱。可用於「不重複」來識別轉場效果中的元素。
結果:
現在標頭會留在原位,並轉換成交叉淡出。
該 CSS 宣告導致虛擬元素樹狀結構變更:
::view-transition
├─ ::view-transition-group(root)
│ └─ ::view-transition-image-pair(root)
│ ├─ ::view-transition-old(root)
│ └─ ::view-transition-new(root)
└─ ::view-transition-group(main-header)
└─ ::view-transition-image-pair(main-header)
├─ ::view-transition-old(main-header)
└─ ::view-transition-new(main-header)
現在有兩個轉換群組。一個用於標頭,另一個用於標頭。這些廣告單元可透過 CSS 單獨指定,並根據不同的轉場效果進行指定。不過,在本範例中,main-header
是預設的轉場效果,也就是交叉淡出。
好吧,預設轉場效果並非只有交錯淡出,::view-transition-group
也會進行轉換:
- 位置和轉換 (透過
transform
) - 寬度
- 身高
這個問題到目前為止仍然重要,因為標題大小和位置在 DOM 改變的兩邊相同。但我們也可以擷取標頭中的文字:
.main-header-text {
view-transition-name: main-header-text;
width: fit-content;
}
使用 fit-content
,因此元素是文字的大小,而不是延展至剩餘的寬度。如未加入這個屬性,返回箭頭可以縮小標題文字元素的大小,而我們希望兩個頁面中的頁面大小一致。
現在可分成三個部分:
::view-transition
├─ ::view-transition-group(root)
│ └─ …
├─ ::view-transition-group(main-header)
│ └─ …
└─ ::view-transition-group(main-header-text)
└─ …
但這一次,直接採用預設值:
這樣一來,標題文字看起來會很美觀滑過,騰出空間供返回按鈕使用。
偵錯轉場效果
由於 View 轉場效果是以 CSS 動畫為基礎,因此 Chrome 開發人員工具的「Animations」面板很適合用來偵錯轉場效果。
您可以使用「動畫」面板暫停下一個動畫,然後來回切換動畫。在這段期間,您可以在「Elements」(元素) 面板中找到轉場虛擬元素。
轉換元素不需要使用相同的 DOM 元素
目前,我們已經使用 view-transition-name
建立獨立的標頭和標頭文字的轉換元素。從概念上來說,這些元素在 DOM 變更前後都是相同的,但您可以在不同情況下建立轉場效果。
舉例來說,您可以用 view-transition-name
指定主要影片嵌入:
.full-embed {
view-transition-name: full-embed;
}
接著,只要有人點選縮圖,就能在轉場期間使用相同的 view-transition-name
:
thumbnail.onclick = async () => {
thumbnail.style.viewTransitionName = 'full-embed';
document.startViewTransition(() => {
thumbnail.style.viewTransitionName = '';
updateTheDOMSomehow();
});
};
結果:
縮圖隨即轉換為主要圖片。即使在概念上 (且基本上) 不同元素,轉換 API 會將這些元素視為相同,因為它們共用相同的 view-transition-name
。
實際的程式碼應該比上面的簡單範例稍微複雜一些,因為它還處理了返回縮圖頁面的轉換過程。如需完整導入詳情,請參閱原始碼。
自訂進入和退出轉場效果
請看以下範例:
側欄是轉換的其中一環:
.sidebar {
view-transition-name: sidebar;
}
不過,與前例不同的標題不同,側欄不會顯示在所有頁面上。如果兩個狀態都同時有側欄,轉換虛擬元素如下所示:
::view-transition
├─ …other transition groups…
└─ ::view-transition-group(sidebar)
└─ ::view-transition-image-pair(sidebar)
├─ ::view-transition-old(sidebar)
└─ ::view-transition-new(sidebar)
不過,如果側欄只存在於新頁面,就不會顯示 ::view-transition-old(sidebar)
虛擬元素。由於側欄沒有「舊」圖片,因此圖片組合只會有 ::view-transition-new(sidebar)
。同樣地,如果側欄僅存在於舊頁面,則圖片組合只會包含 ::view-transition-old(sidebar)
。
在上方的示範中,側欄的轉場效果會因為進入、離開或同時處於這兩個狀態而有不同。它會保持原狀,從右側滑動到淡入,然後向右滑入,並淡出,讓它在兩個狀態都處於原位。
如要建立特定進入和結束轉場效果,您可以在是影像配對中唯一的子項時,使用 :only-child
虛擬類別指定舊/新虛擬元素:
/* Entry transition */
::view-transition-new(sidebar):only-child {
animation: 300ms cubic-bezier(0, 0, 0.2, 1) both fade-in,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
/* Exit transition */
::view-transition-old(sidebar):only-child {
animation: 150ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-right;
}
在這種情況下,由於兩個狀態皆顯示側欄,因此沒有特定的轉換效果,因為預設值是完美的。
非同步 DOM 更新,正在等待內容
傳遞至 .startViewTransition()
的回呼可能會傳回承諾,藉此執行非同步 DOM 更新,並等待重要內容準備就緒。
document.startViewTransition(async () => {
await something;
await updateTheDOMSomehow();
await somethingElse;
});
這項轉換必須等到承諾符合項目後才會開始。在這段期間,網頁將會凍結,因此請盡量縮短延遲時間。具體來說,網路擷取應在呼叫 .startViewTransition()
前完成,且頁面仍具備完整互動功能,而非將其當做 .startViewTransition()
回呼的一部分進行。
如果您決定等待圖片或字型準備就緒,請務必設定積極的逾時時間:
const wait = ms => new Promise(r => setTimeout(r, ms));
document.startViewTransition(async () => {
updateTheDOMSomehow();
// Pause for up to 100ms for fonts to be ready:
await Promise.race([document.fonts.ready, wait(100)]);
});
但在某些情況下,最好能完全避免延遲,並利用您已有的內容。
充分運用現有內容
如果縮圖轉換為較大圖片:
預設的轉場效果為交叉淡出,也就是說,縮圖在尚未載入的完整圖片中可能會交叉淡出。
處理這種情況的其中一種方法是等到完整圖片載入後,再開始轉換。理想情況下,系統會在呼叫 .startViewTransition()
前完成這項操作,以便讓頁面維持互動狀態,並顯示旋轉圖示,告知使用者目前正在載入內容。不過,還有更好的方式:
::view-transition-old(full-embed),
::view-transition-new(full-embed) {
/* Prevent the default animation,
so both views remain opacity:1 throughout the transition */
animation: none;
/* Use normal blending,
so the new view sits on top and obscures the old view */
mix-blend-mode: normal;
}
現在縮圖不會淡出,只要貼在整張圖片下方即可。也就是說,如果新檢視畫面尚未載入,縮圖在轉換期間仍會顯示。這表示轉場效果可以立即開始,而整張圖片則可自行載入。
新的檢視畫面無法在採用透明度的新檢視畫面中執行,但在這種情況下,我們確認這一點是無法進行的,讓我們據此進行最佳化。
處理顯示比例的變化
簡單來說,到目前為止,所有轉場效果都是為了具有相同顯示比例的元素,但並非一定如此。如果縮圖是 1:1,主要圖片是 16:9,該怎麼辦?
在預設的轉場效果中,群組會以動畫之前的大小轉換成之後的大小。新舊檢視畫面、群組寬度和自動高度皆為 100%,代表無論群組大小為何,兩者的長寬比都會維持不變。
這是很好的預設值,但並非本例的需求。舉例來說:
::view-transition-old(full-embed),
::view-transition-new(full-embed) {
/* Prevent the default animation,
so both views remain opacity:1 throughout the transition */
animation: none;
/* Use normal blending,
so the new view sits on top and obscures the old view */
mix-blend-mode: normal;
/* Make the height the same as the group,
meaning the view size might not match its aspect-ratio. */
height: 100%;
/* Clip any overflow of the view */
overflow: clip;
}
/* The old view is the thumbnail */
::view-transition-old(full-embed) {
/* Maintain the aspect ratio of the view,
by shrinking it to fit within the bounds of the element */
object-fit: contain;
}
/* The new view is the full image */
::view-transition-new(full-embed) {
/* Maintain the aspect ratio of the view,
by growing it to cover the bounds of the element */
object-fit: cover;
}
這表示縮圖在寬度展開時會保持在元素中央,但在從 1:1 到 16:9 時,整個圖片會「取消裁剪」。
根據裝置狀態變更轉場效果
建議您在行動裝置和電腦上使用不同的轉場效果,例如以下示範在行動裝置上從側邊播放整張投影片,不過在電腦上是效果較簡單的投影片:
方法是使用一般媒體查詢:
/* Transitions for mobile */
::view-transition-old(root) {
animation: 300ms ease-out both full-slide-to-left;
}
::view-transition-new(root) {
animation: 300ms ease-out both full-slide-from-right;
}
@media (min-width: 500px) {
/* Overrides for larger displays.
This is the shared axis transition from earlier in the article. */
::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
}
您可能也會想根據相符的媒體查詢,變更指派 view-transition-name
的元素。
回應「減少動作」偏好設定
使用者可指出自己偏好透過作業系統降低動態效果,且偏好設定是透過 CSS 公開。
您可以選擇禁止以下使用者轉換:
@media (prefers-reduced-motion) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
不過,「減少動作」的偏好設定並不代表使用者需要無動態效果。與其使用上述方法,您可以選擇一個更細緻的動畫,但這仍能表示元素與資料流間的關係。
根據導覽類型變更轉場效果
有時候,從某類網頁前往另一個網頁時,應該特別適合使用轉換功能。或者,「上一頁」瀏覽方式應與「向前」瀏覽不同。
處理這些情況的最佳方式是在 <html>
上設定類別名稱,也稱為文件元素:
if (isBackNavigation) {
document.documentElement.classList.add('back-transition');
}
const transition = document.startViewTransition(() =>
updateTheDOMSomehow(data)
);
try {
await transition.finished;
} finally {
document.documentElement.classList.remove('back-transition');
}
此範例使用了 transition.finished
,承諾會在轉場效果達到結束狀態時解決。請參閱 API 參考資料,瞭解這個物件的其他屬性。
您現在可以在 CSS 中使用該類別名稱來變更轉換:
/* 'Forward' transitions */
::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 300ms
cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
/* Overrides for 'back' transitions */
.back-transition::view-transition-old(root) {
animation-name: fade-out, slide-to-right;
}
.back-transition::view-transition-new(root) {
animation-name: fade-in, slide-from-left;
}
與媒體查詢一樣,具有這些類別也可以用來變更哪些元素會取得 view-transition-name
。
在不凍結其他動畫的情況下進行轉場效果
請觀看以下示範影片轉場位置的示範影片:
你是否看到任何錯誤?如果不是,也不必擔心。速度就從這裡慢慢開始:
移轉期間,影片會立刻停止播放,而播放版本的影片會淡入。這是因為 ::view-transition-old(video)
是舊檢視畫面的螢幕截圖,而 ::view-transition-new(video)
是新檢視畫面的「即時」圖片。
您可以修正這個問題,但請先考慮是否需要自行調整。如果在轉場效果以正常速度播放時,沒有出現「問題」,我應該不會為了改變而改變。
如果您希望修正,請不要顯示 ::view-transition-old(video)
;請直接切換至 ::view-transition-new(video)
。方法是覆寫預設樣式和動畫:
::view-transition-old(video) {
/* Don't show the frozen old view */
display: none;
}
::view-transition-new(video) {
/* Don't fade the new view in */
animation: none;
}
這樣就大功告成了!
現在影片會在轉場期間播放。
使用 JavaScript 建立動畫
到目前為止,所有轉場效果都是使用 CSS 定義,但有些 CSS 還不夠:
其中幾個部分無法只靠 CSS 完成:
- 動畫會從點擊位置開始。
- 動畫結尾為圓形,半徑與最遠角。但我們希望 CSS 日後有機會達成這項目標。
幸好,您可以使用 Web Animation API 建立轉場效果!
let lastClick;
addEventListener('click', event => (lastClick = event));
function spaNavigate(data) {
// Fallback for browsers that don't support this API:
if (!document.startViewTransition) {
updateTheDOMSomehow(data);
return;
}
// Get the click position, or fallback to the middle of the screen
const x = lastClick?.clientX ?? innerWidth / 2;
const y = lastClick?.clientY ?? innerHeight / 2;
// Get the distance to the furthest corner
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y)
);
// With a transition:
const transition = document.startViewTransition(() => {
updateTheDOMSomehow(data);
});
// Wait for the pseudo-elements to be created:
transition.ready.then(() => {
// Animate the root's new view
document.documentElement.animate(
{
clipPath: [
`circle(0 at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`,
],
},
{
duration: 500,
easing: 'ease-in',
// Specify which pseudo-element to animate
pseudoElement: '::view-transition-new(root)',
}
);
});
}
此範例使用了 transition.ready
,此承諾會在成功建立轉換虛擬元素後解決。請參閱 API 參考資料,瞭解這個物件的其他屬性。
轉換做為強化項目
View Transition API 旨在「包裝」 DOM 變更,並為其建立轉場效果。不過,請將轉場效果視為強化;就像這樣,如果 DOM 變更成功,但轉換失敗,您的應用程式就不應進入「error」狀態。理想情況下,轉換作業應不會失敗,但如能順利轉換,應該也不會導致其餘使用者體驗中斷。
為了將轉場效果視為強化效果,請小心不要使用轉換承諾,避免在轉換失敗時擲回應用程式。
async function switchView(data) { // Fallback for browsers that don't support this API: if (!document.startViewTransition) { await updateTheDOM(data); return; } const transition = document.startViewTransition(async () => { await updateTheDOM(data); }); await transition.ready; document.documentElement.animate( { clipPath: [`inset(50%)`, `inset(0)`], }, { duration: 500, easing: 'ease-in', pseudoElement: '::view-transition-new(root)', } ); }
這個範例的問題是,如果轉換作業無法達到 ready
狀態,switchView()
將拒絕,但這並不代表檢視畫面無法切換。DOM 可能已成功更新,但有重複的 view-transition-name
,因此系統略過轉場效果。
請改採以下做法:
async function switchView(data) { // Fallback for browsers that don't support this API: if (!document.startViewTransition) { await updateTheDOM(data); return; } const transition = document.startViewTransition(async () => { await updateTheDOM(data); }); animateFromMiddle(transition); await transition.updateCallbackDone; } async function animateFromMiddle(transition) { try { await transition.ready; document.documentElement.animate( { clipPath: [`inset(50%)`, `inset(0)`], }, { duration: 500, easing: 'ease-in', pseudoElement: '::view-transition-new(root)', } ); } catch (err) { // You might want to log this error, but it shouldn't break the app } }
此範例使用 transition.updateCallbackDone
等待 DOM 更新,失敗時就會拒絕。轉換失敗時,switchView
不會再拒絕,且會在 DOM 更新完成時拒絕,失敗則會拒絕。
如果希望 switchView
在新的檢視畫面「settled」時解析,就像在任何動畫轉場完成或略過一樣,請將 transition.updateCallbackDone
替換為 transition.finished
。
不是 polyfill,但...
我認為這個功能不能以任何有用的方式完成,但我也很開心能證明這個功能出錯了!
不過,在不支援觀看轉場功能的瀏覽器中,這個輔助函式會簡化後續作業:
function transitionHelper({
skipTransition = false,
classNames = [],
updateDOM,
}) {
if (skipTransition || !document.startViewTransition) {
const updateCallbackDone = Promise.resolve(updateDOM()).then(() => {});
return {
ready: Promise.reject(Error('View transitions unsupported')),
updateCallbackDone,
finished: updateCallbackDone,
skipTransition: () => {},
};
}
document.documentElement.classList.add(...classNames);
const transition = document.startViewTransition(updateDOM);
transition.finished.finally(() =>
document.documentElement.classList.remove(...classNames)
);
return transition;
}
使用方式如下:
function spaNavigate(data) {
const classNames = isBackNavigation ? ['back-transition'] : [];
const transition = transitionHelper({
classNames,
updateDOM() {
updateTheDOMSomehow(data);
},
});
// …
}
在不支援檢視畫面轉場的瀏覽器中,系統仍會呼叫 updateDOM
,但不會呈現動畫轉場效果。
您也可以提供在轉場期間為 <html>
加入一些 classNames
,以便根據導覽類型變更轉場效果。
如果不想使用動畫,也可以將 true
傳遞至 skipTransition
,即使瀏覽器支援檢視畫面轉場效果也一樣。如果網站有使用者偏好停用轉場功能,這項功能就能派上用場。
使用架構
如果您使用的是程式庫或架構,而該程式庫或架構可以抽離 DOM 變更,最困難的部分就是瞭解 DOM 何時完成 DOM。以下為在不同架構中使用上述輔助程式的範例。
- React (回應):這裡
flushSync
會同步套用一組狀態變更。是,使用該 API 受到重大警告,但 Dan Abramov 保證就我的情況很適當。和 React 和非同步程式碼一樣,使用startViewTransition
傳回的各種承諾時,請確保程式碼以正確的狀態執行。 - Vue.js:這裡的鍵是
nextTick
,在 DOM 更新後執行此金鑰。 - Svelte:與 Vue 類似,但等待下次變更的方法為
tick
。 - Lit:這裡的關鍵是元件中的
this.updateComplete
承諾,在 DOM 更新後執行此訊息。 - Angular:這個索引鍵是
applicationRef.tick
,用於清除待處理的 DOM 變更。自 Angular 17 版起,您可以使用@angular/router
隨附的withViewTransitions
。
API 參考資料
const viewTransition = document.startViewTransition(updateCallback)
建立新的
ViewTransition
。擷取文件目前的狀態時,系統會呼叫
updateCallback
。然後,當
updateCallback
傳回的承諾執行完畢時,轉換會在下一個影格中開始。如果updateCallback
傳回的承諾拒絕,系統將放棄轉換。
ViewTransition
的執行個體成員:
viewTransition.updateCallbackDone
updateCallback
傳回的承諾在執行時履行,或拒絕時拒絕的承諾。View Transition API 會納入 DOM 變更並建立轉場效果。然而,有時您並不在意轉換動畫的成功/失敗情況,只需要瞭解 DOM 是否發生變更以及何時發生。
updateCallbackDone
適用於該用途。viewTransition.ready
轉換的虛擬元素建立,且動畫即將開始時,即完成的承諾。
如果無法開始轉場,就會遭到拒絕。這可能是因設定錯誤 (例如重複的
view-transition-name
),或是updateCallback
傳回遭拒的承諾所導致。這項設定適合如何使用 JavaScript 為轉換虛擬元素建立動畫效果。
viewTransition.finished
在使用者完全看到結束狀態且可互動後實現的承諾。
只有
updateCallback
傳回遭拒的承諾時才會遭到拒絕,因為這表示尚未建立結束狀態。否則,如果轉場效果無法開始,或在轉場過程中略過,則仍會達到結束狀態,因此
finished
就會執行。viewTransition.skipTransition()
略過轉場動畫的部分。
這不會略過呼叫
updateCallback
,因為 DOM 變更是獨立的轉換。
預設樣式和轉換參照
::view-transition
- 用於填滿可視區域的根虛擬元素,並包含每個
::view-transition-group
。 ::view-transition-group
明確定位。
在「之前」和「之後」狀態之間轉換
width
和height
。在可視區域空間四點之間轉換
transform
。::view-transition-image-pair
絕對是填滿團體的理想位置。
含有
isolation: isolate
,可限制plus-lighter
混合模式對新檢視畫面和新檢視畫面的影響。::view-transition-new
和::view-transition-old
絕對位於包裝函式的左上角。
填滿群組寬度的 100%,但設為自動高度,因此會維持群組的顯示比例,而非填滿群組。
使用
mix-blend-mode: plus-lighter
,允許真實的交叉淡出。舊的檢視畫面從
opacity: 1
轉換至opacity: 0
。新的檢視畫面從opacity: 0
轉換至opacity: 1
。
意見回饋:
在這個階段,開發人員的意見十分重要,因此請前往 GitHub 回報問題,並提供建議和問題。