針對傳送門進行實作:順暢瀏覽網頁

瞭解 Portals API 提案如何改善導覽使用者體驗。

Yusuke Utsunomiya
Yusuke Utsunomiya

確保網頁載入速度快,是提供良好使用者體驗的關鍵。不過,頁面轉換是使用者切換頁面時會看到的畫面,也是我們經常忽略的面向。

我們推出名為「Portals」的新網站平台 API 提案,旨在協助您簡化使用者在網站上瀏覽內容的體驗。

瞭解 Portal 的實際應用情形:

Portal 可提供順暢的嵌入和導覽功能。由 Adam Argyle 建立。

入口網站可啟用的功能

單頁應用程式 (SPA) 可提供不錯的轉場效果,但建構成本較高。多頁應用程式 (MPA) 的建構作業較為簡單,但會導致頁面之間出現空白畫面。

入口網站提供兩種優點,即 MPA 的複雜程度較低,且具備流暢的 SPA 技術。可將其視為 <iframe>,因為它們允許嵌入,但與 <iframe> 不同的是,它們還提供導覽至內容的功能。

眼見為憑:請先查看我們在 2018 年 Chrome 開發人員高峰會中展示的內容:

使用傳統版導覽時,使用者必須等待空白畫面,直到瀏覽器轉譯目的地為止。有了入口網站,使用者就能體驗動畫,而 <portal> 則會預先轉譯內容,提供順暢的瀏覽體驗。

在傳送門之前,我們可以使用 <iframe> 轉譯另一個網頁。我們也可以新增動畫,讓框架在頁面中移動。但 <iframe> 無法讓您瀏覽其內容。能量塔則彌補了這個缺口,實現了有趣的用途。

試用入口網站

透過 about://flags 啟用

如要試用 Chrome 85 以上版本中的 Portals,請切換實驗性標記:

  • 為同源導覽啟用 about://flags/#enable-portals 旗標。
  • 如要測試跨原始來源導覽,請另外啟用 about://flags/#enable-portals-cross-origin 標記。

在 Portals 實驗的初期階段,我們也建議您設定 --user-data-dir 指令列標記,為測試使用完全獨立的使用者資料目錄。啟用 Portals 後,請在開發人員工具中確認您有新的閃亮 HTMLPortalElement

開發人員工具主控台的螢幕截圖,其中顯示 HTMLPortalElement

實作入口網站

讓我們來看看一個基本導入範例。

// Create a portal with the wikipedia page, and embed it
// (like an iframe). You can also use the <portal> tag instead.
portal = document.createElement('portal');
portal.src = 'https://en.wikipedia.org/wiki/World_Wide_Web';
portal.style = '...';
document.body.appendChild(portal);

// When the user touches the preview (embedded portal):
// do fancy animation, e.g. expand …
// and finish by doing the actual transition.
// For the sake of simplicity, this snippet will navigate
// on the `onload` event of the Portals element.
portal.addEventListener('load', (evt) => {
   portal.activate();
});

方法就是這麼簡單。在開發人員工具控制台中嘗試使用此程式碼,系統會開啟 Wikipedia 頁面。

預覽入口網站樣式示範的 GIF 圖片

如果您想建構類似上述示範內容,在 Chrome 開發人員高峰會中所展示的內容,就很適合使用以下程式碼片段。

// Adding some styles with transitions
const style = document.createElement('style');
style.innerHTML = `
  portal {
    position:fixed;
    width: 100%;
    height: 100%;
    opacity: 0;
    box-shadow: 0 0 20px 10px #999;
    transform: scale(0.4);
    transform-origin: bottom left;
    bottom: 20px;
    left: 20px;
    animation-name: fade-in;
    animation-duration: 1s;
    animation-delay: 2s;
    animation-fill-mode: forwards;
  }
  .portal-transition {
    transition: transform 0.4s;
  }
  @media (prefers-reduced-motion: reduce) {
    .portal-transition {
      transition: transform 0.001s;
    }
  }
  .portal-reveal {
    transform: scale(1.0) translateX(-20px) translateY(20px);
  }
  @keyframes fade-in {
    0%   { opacity: 0; }
    100% { opacity: 1; }
  }
`;
const portal = document.createElement('portal');
// Let's navigate into the WICG Portals spec page
portal.src = 'https://wicg.github.io/portals/';
// Add a class that defines the transition. Consider using
// `prefers-reduced-motion` media query to control the animation.
// https://developers.google.com/web/updates/2019/03/prefers-reduced-motion
portal.classList.add('portal-transition');
portal.addEventListener('click', (evt) => {
  // Animate the portal once user interacts
  portal.classList.add('portal-reveal');
});
portal.addEventListener('transitionend', (evt) => {
  if (evt.propertyName == 'transform') {
    // Activate the portal once the transition has completed
    portal.activate();
  }
});
document.body.append(style, portal);

您也可以輕鬆執行功能偵測,逐步改善使用 Portal 的網站。

if ('HTMLPortalElement' in window) {
  // If this is a platform that have Portals...
  const portal = document.createElement('portal');
  ...
}

如要快速體驗 Portals 的使用體驗,請試著使用 uskay-portals-demo.glitch.me。請務必使用 Chrome 85 以上版本存取這項工具,並開啟實驗標記

  1. 輸入要預覽的網址。
  2. 網頁會以 <portal> 元素嵌入。
  3. 按一下預覽畫面。
  4. 動畫播放完畢後,系統會啟用預覽畫面。

使用 Portal 的 GIF 圖片,展示 Glitch 示範

查看規格

我們正積極在 Web Incubation Community Group (WICG) 討論Portals 規格。如要快速上手,請查看部分重要情境。以下是三個您需要熟悉的重要功能:

  • <portal> 元素:HTML 元素本身。這個 API 非常簡單。它包含 src 屬性、activate 函式和訊息介面 (postMessage)。activate 會採用選用引數,在啟用時將資料傳遞至 <portal>
  • portalHost 介面:portalHost 物件新增至 window 物件。這樣就能檢查網頁是否以 <portal> 元素嵌入。它也提供介面,可將訊息 (postMessage) 傳回主機。
  • PortalActivateEvent 介面:<portal> 啟用時觸發的事件。您可以使用名為 adoptPredecessor 的簡潔函式,將前一頁擷取為 <portal> 元素。如此一來,您就能在兩個頁面間提供流暢的瀏覽體驗和組合體驗。

讓我們進一步探討基本使用模式。以下列舉 Portal 的功能 (僅列舉部分內容),以及相關程式碼範例。

自訂內嵌為 <portal> 元素時的樣式

// Detect whether this page is hosted in a portal
if (window.portalHost) {
  // Customize the UI when being embedded as a portal
}

<portal> 元素和 portalHost 之間的訊息傳遞

// Send message to the portal element
const portal = document.querySelector('portal');
portal.postMessage({someKey: someValue}, ORIGIN);

// Receive message via window.portalHost
window.portalHost.addEventListener('message', (evt) => {
  const data = evt.data.someKey;
  // handle the event
});

啟用 <portal> 元素並接收 portalactivate 事件

// You can optionally add data to the argument of the activate function
portal.activate({data: {somekey: 'somevalue'}});

// The portal content will receive the portalactivate event
// when the activate happens
window.addEventListener('portalactivate', (evt) => {
  // Data available as evt.data
  const data = evt.data;
});

擷取前置作業

// Listen to the portalactivate event
window.addEventListener('portalactivate', (evt) => {
  // ... and creatively use the predecessor
  const portal = evt.adoptPredecessor();
  document.querySelector('someElm').appendChild(portal);
});

知道你的網頁已採用前身網頁

// The activate function returns a Promise.
// When the promise resolves, it means that the portal has been activated.
// If this document was adopted by it, then window.portalHost will exist.
portal.activate().then(() => {
  // Check if this document was adopted into a portal element.
  if (window.portalHost) {
    // You can start communicating with the portal element
    // i.e. listen to messages
    window.portalHost.addEventListener('message', (evt) => {
      // handle the event
    });
  }
});

只要結合 Portal 支援的所有功能,就能打造出非常精彩的使用者體驗。以下示範示範如何讓入口網站在網站和第三方嵌入內容之間,提供流暢的使用者體驗。

用途和方案

希望你喜歡這次的 Portal 簡介!期待你繼續大展身手!舉例來說,您可能想開始使用 Portal 進行非簡單的導覽,例如:從產品類別產品資訊頁面預先轉譯暢銷產品的網頁。

另外,Portal 可用於跨來源導覽,就像 <iframe> 一樣。因此,如果您有幾個互相參照的網站,也可以使用 Portals 在兩個網站之間建立無縫的導覽功能。這個跨來源使用案例對入口網站來說非常獨特,甚至能改善 SPA 的使用者體驗。

歡迎踴躍提供意見

在 Chrome 85 以上版本中,您可以開始嘗試使用 Portal。社群提供的意見對於新 API 的設計至關重要,歡迎您試用並提供寶貴意見!如有任何功能要求或意見回饋,請前往 WICG GitHub 存放區