Google 如何使用檢視畫面轉場效果,為全新 AI 模式打造連線體驗

發布日期:2025 年 8 月 28 日

Google 搜尋是全球觸及範圍最廣的平台之一,因此使用者體驗的變更可能會影響數十億使用者。我們一直希望網路體驗能更貼近現代需求,也更像應用程式。在開發 AI 模式時,我們希望為使用者打造流暢的體驗,讓他們從標準搜尋模式切換到 AI 模式時,感覺自然而連貫。我們聽說了跨文件檢視畫面轉場效果,就知道這項功能與該效果是天作之合。這份個案研究將分享我們在推出 AI 模式時,一併新增轉場功能的心得。

這段影片顯示使用 Google 搜尋的過程,以及從搜尋結果切換至 AI 模式的畫面。轉場效果使用檢視區塊轉場。

就原生瀏覽器工具而言,跨文件檢視區塊轉換是劃時代的技術,我們很期待這項技術如何塑造未來的網路。

Browser Support

  • Chrome: 126.
  • Edge: 126.
  • Firefox: not supported.
  • Safari: 18.2.

Source

改變現狀

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 支援跨瀏覽器)。敬請期待我們接下來會打造什麼!