發布日期:2025 年 8 月 28 日
Google 搜尋是全球觸及範圍最廣的平台之一,因此使用者體驗的變更可能會影響數十億使用者。我們一直希望網路體驗能更貼近現代需求,也更像應用程式。在開發 AI 模式時,我們希望為使用者打造流暢的體驗,讓他們從標準搜尋模式切換到 AI 模式時,感覺自然而連貫。我們聽說了跨文件檢視畫面轉場效果,就知道這項功能與該效果是天作之合。這份個案研究將分享我們在推出 AI 模式時,一併新增轉場功能的心得。
就原生瀏覽器工具而言,跨文件檢視區塊轉換是劃時代的技術,我們很期待這項技術如何塑造未來的網路。
改變現狀
Google 搜尋對瀏覽器支援有嚴格且保守的要求。一般來說,使用限量供應功能會受到限制。就跨文件檢視區塊轉換而言,我們發現填補程式不可行,主要阻礙是沒有像素快照 API,且複製整個檢視區塊會造成重大效能問題。因此,以漸進增強功能的形式推出,是與 AI 模式一同發布的最佳方式。由於檢視區塊轉換建立的動畫不會直接影響網站功能,因此對於不支援的流量,系統只會停用動畫,這與目前沒有轉換動畫的正式版狀態相同。
我們首先對內部使用者測試這項漸進增強策略。這項測試讓我們獲得了早期意見回饋,而且絕大多數都是正面的。我們收到的意見回饋也指出了一些錯誤,包括效能問題,以及與其他功能 (例如重疊的堆疊環境) 之間非預期的互動。
我們發現這項策略相當成功,相信未來會將這項策略套用至其他新的瀏覽器功能。
我們遇到的困難及解決方法
延遲、轉譯封鎖和監控計時器
整體而言,對於 99% 的用途來說,MPA 檢視區塊轉換造成的延遲時間可忽略不計,尤其是在現代硬體上。不過,Google 搜尋對延遲時間的要求極高,我們致力於打造適用於所有裝置的優質使用者體驗。對我們來說,即使是幾毫秒的延遲也很重要,因此我們必須投入資源,確保正確導入跨文件檢視畫面轉場效果,同時不影響任何人的使用者體驗。
轉譯封鎖技術與跨文件檢視畫面轉換功能搭配使用效果良好。傳入文件的虛擬元素快照只能顯示已轉譯的內容。因此,如要為傳入文件中的內容製作動畫,您需要算繪區塊,直到要製作動畫的目標元素算繪完成為止。如要這麼做,請在 HTMLLinkElement 上使用blocking 屬性。等待即將傳入的文件 DOM 樹狀結構中位於後方的元素,可能會大幅影響延遲時間,因此算是一種缺點。我們必須相應地平衡這項取捨,並只在網頁生命週期極早算繪的元素上算繪區塊。
<!-- Link tag in the <head> of the incoming document -->
<link blocking="render" href="#target-id" rel="expect">
<!-- Element you want to animate in the <body> of the incoming document -->
<div id="target-id">
some content
</div>
在某些情況下,精確指出要將哪個元素算繪為區塊,並不足以解決問題。即使元素附近的 DOM 樹狀結構開頭有算繪封鎖,特定裝置或連線仍會出現延遲。為處理這些情況,我們編寫了監控計時器指令碼,在經過一段時間後移除 HTMLLinkElement,強制解除封鎖傳入文件的算繪作業。
簡單做法如下:
function unblockRendering() {
const renderBlockingElements = document.querySelectorAll(
'link[blocking=render]',
);
for (const element of renderBlockingElements) {
element.remove();
}
}
const timeToUnblockRendering = t - performance.now();
if (timeToUnblockRendering > 0) {
setTimeout(unblockRendering, timeToUnblockRendering);
} else {
unblockRendering();
}
保固範圍限制
我們遇到的另一個問題是,文件中的跨文件檢視畫面轉場效果 @ 規則 navigation: auto 會在全域層級發生。目前沒有內建方法可將跨文件檢視畫面轉場效果的啟用範圍,限制在特定點擊目標。由於這項變更規模龐大,我們無法在 Google 搜尋中對所有導覽啟用跨文件檢視畫面轉場效果。我們需要根據使用者互動的功能,動態啟用或停用跨文件檢視區塊轉換。在本例中,我們只針對 AI 模式的切換啟用這些事件。我們根據點選或輕觸的目標,以程式輔助方式更新導覽 @ 規則。
如要切換檢視區塊轉場效果 @ 規則,請按照下列步驟操作:
let viewTransitionAtRule: HTMLElement | undefined;
const DISABLED_VIEW_TRANSITION = '@view-transition{navigation:none;}';
const ENABLED_VIEW_TRANSITION = '@view-transition{navigation:auto;}';
function getVtAtRule(): HTMLElement {
if (!viewTransitionAtRule) {
viewTransitionAtRule = document.createElement('style');
document.head.append(viewTransitionAtRule);
}
return viewTransitionAtRule;
}
function disableVt() {
getVtAtRule().textContent = DISABLED_VIEW_TRANSITION;
}
function enableVt() {
getVtAtRule().textContent = ENABLED_VIEW_TRANSITION;
}
卡頓和合成動畫
檢視區塊轉場效果虛擬元素上自動產生的部分動畫,會導致舊裝置掉格,破壞我們想為使用者提供的流暢體驗。為提升動畫效能,我們使用可在合成器上執行的動畫技術,重新編寫動畫。我們檢查了關鍵影格,取得前後快照虛擬元素的尺寸,並使用矩陣數學相應地重寫關鍵影格,因此能夠達成這項作業。以下範例說明如何擷取每個檢視區塊轉場虛擬元素的動畫:
const pseudoElement = `::view-transition-group(${name})`;
const animation = document
.getAnimations()
.find(
(animation) =>
(animation.effect as KeyframeEffect)?.pseudoElement === pseudoElement,
);
如要進一步瞭解如何編寫高效能的檢視區塊轉場效果關鍵影格,請參閱「套用檢視區塊轉場效果:處理含有封鎖的快照」。
其他注意事項
其中一個較明顯的問題是,使用 view-transition-name CSS 屬性標記元素會影響堆疊內容 (檢視畫面轉場效果規格:第 2.1.1 節)。這是多個錯誤的來源,需要修改容器元素的 z-index。
請注意,您可能不想預設將 view-transition-name 值新增至元素。Google 搜尋團隊有許多成員,為避免團隊在元素上設定的 view-transition-name 值,與其他團隊可能使用的值發生衝突,我們利用檢視區塊轉場效果類型,僅在特定檢視區塊轉場效果類型處於啟用狀態時,有條件地新增 view-transition-name 屬性。
以下是 CSS 範例,只有在 ai-mode 的檢視區塊轉場效果類型處於啟用狀態時,才會將 view-transition-name 的 the-element 新增至元素:
html:active-view-transition-type(ai-mode) {
#target {
view-transition-name: the-element;
}
}
為所有檢視區塊轉換設定這些 CSS 規則後,您就能在 pageswap 和 pagereveal 事件期間,動態變更任何導覽的目前檢視區塊轉換類型。
在 pageswap 事件期間,將檢視區塊轉場效果類型更新為 ai-mode 的範例。
function updateViewTransitionTypes(
event: ViewTransitionEvent,
types: string[],
): void {
event.viewTransition.types.clear();
for (const type of types) {
event.viewTransition.types.add(type);
}
}
window.addEventListener(
'pageswap',
(e) => {
updateViewTransitionTypes(
e as ViewTransitionEvent,
['ai-mode'],
);
}
);
這樣一來,我們就能避免命名衝突,並防止不必要的元素快照,這些元素不需要在進入和離開 AI 模式時快照。
最後,任何堆疊內容問題只會在檢視畫面轉場期間出現。如要解決這些問題,我們可以指定產生的虛擬元素的 z-index,而不是任意修改原始元素的 z-index,只為在使用檢視區塊轉換時解決這個問題。
::view-transition-group(the-element) {
z-index: 100;
}
後續步驟
我們計畫在 Google 搜尋中使用跨文件檢視區塊轉換,包括與 Navigation API 整合 (一旦該 API 支援跨瀏覽器)。敬請期待我們接下來會打造什麼!