Visual Viewport API

模板/側邊欄的 slug 無效:Visual Viewport

Visual Viewport API 提供了一種明確的機制,用於查詢和修改視窗的 視覺視口 屬性。視覺視口是螢幕上不包括螢幕鍵盤、捏合縮放區域外的區域或與頁面尺寸不縮放的任何其他螢幕假象的可見部分。

概念與用法

移動 Web 包含兩個視口:佈局視口和視覺視口。佈局視口涵蓋頁面上的所有元素,而視覺視口是螢幕上實際可見的部分。當用戶捏合縮放頁面時,視覺視口會縮小,但佈局視口保持不變。螢幕鍵盤 (OSK) 等使用者介面功能可以縮小視覺視口,而不影響佈局視口。

當網頁元素需要無論在螢幕可見部分的哪個位置都能顯示時,會發生什麼?例如,如果您需要一組影像控制元件在裝置的捏合縮放級別下始終保持在螢幕上,該怎麼辦?當前瀏覽器處理此問題的方式各不相同。Visual Viewport API 使 Web 開發者可以透過相對於螢幕顯示內容來定位元素來解決此問題。

要訪問視窗的視覺視口,您可以透過 window.visualViewport 屬性獲取一個 VisualViewport 物件。該物件包含一組描述視口屬性的屬性。它還增加了三個事件:resizescrollscrollend。這些事件分別在視覺視口被調整大小、滾動以及完成滾動操作時觸發。

前兩個事件允許您相對於視覺視口進行元素定位,因為它是被滾動或縮放的,這通常會錨定到佈局視口。scrollend 事件允許您在滾動操作完成後更新元素。例如,您可以使用這些事件來使元素在捏合縮放和滾動時固定在視覺視口上,並在滾動結束時更新它。

介面

VisualViewport

代表給定視窗的視覺視口。視窗的 VisualViewport 物件提供有關視口位置和大小的資訊,並接收 resizescrollscrollend 事件。

其他介面的擴充套件

Window.visualViewport 只讀

對視窗的 VisualViewport 物件的只讀引用。如果此屬性不存在,則表示 API 不受支援。

示例

我們的 Visual Viewport API 示例提供了視覺視口不同功能如何工作的基本演示,包括三種事件型別。在支援的桌面和移動瀏覽器中載入頁面,然後嘗試滾動頁面和捏合縮放。在 resizescroll 事件上,資訊框會被重新定位以保持相對於視覺視口的位置,並且其中顯示的內容和滾動資訊也會更新。此外,在 resizescroll 事件上,我們改變資訊框的顏色以指示正在發生某些事情,並在 scrollend 事件上恢復原色。

您會發現,在桌面瀏覽器上,當視窗滾動時,Window.scrollXWindow.scrollY 值會更新——視覺視口位置不變。然而,在移動瀏覽器上,VisualViewport.offsetLeftVisualViewport.offsetTop 值通常會更新——通常是視覺視口發生變化,而不是視窗位置。

示例 HTML 如下所示。資訊框由一個 idoutput<div> 表示。

html
<p id="instructions">
  Try scrolling around and pinch-zooming to see how the reported values change.
</p>
<div id="output">
  <p id="visual-info"></p>
  <hr />
  <p id="window-info"></p>
</div>

為簡潔起見,我們不解釋示例的 CSS — 它對於理解演示並不重要。您可以在上面的示例連結中檢視它。

在 JavaScript 中,我們首先獲取對我們將要更新的資訊框的引用,以便在頁面縮放和滾動時更新,以及其中包含的兩個段落。第一個段落將包含報告的 VisualViewport.offsetLeftVisualViewport.offsetTop 值,而第二個段落將包含報告的 Window.scrollXWindow.scrollY 值。

js
const output = document.getElementById("output");
const visualInfo = document.getElementById("visual-info");
const windowInfo = document.getElementById("window-info");

接下來,我們定義當事件觸發時將執行的兩個關鍵函式。

  • scrollUpdater() 函式將在 resizescroll 事件上觸發:此函式透過查詢 VisualViewport.offsetTopVisualViewport.offsetLeft 屬性並使用它們的值來更新相關 插入屬性 的值,從而更新資訊框相對於視覺視口的位置。我們還更改資訊框的背景顏色以指示正在進行某些操作,並執行 updateText() 函式來更新框中顯示的值。
  • scrollEndUpdater() 函式將在 scrollend 事件上觸發:此函式將資訊框恢復到其原始顏色,並執行 updateText() 函式以確保在 scrollend 事件上顯示最新值。
js
const scrollUpdater = () => {
  output.style.top = `${visualViewport.offsetTop + 10}px`;
  output.style.left = `${visualViewport.offsetLeft + 10}px`;
  output.style.background = "yellow";
  updateText();
};

const scrollendUpdater = () => {
  output.style.background = "lime";
  updateText();
};

updateText() 函式如下所示 — 它將第一個段落的 HTMLElement.innerText 設定為顯示當前的 VisualViewport.offsetLeftVisualViewport.offsetTop 值,並將第二個段落的 HTMLElement.innerText 設定為顯示當前的 Window.scrollXWindow.scrollY 值。在定義 updateText() 之後,我們立即呼叫它,以便資訊框在頁面載入時正確顯示。

js
function updateText() {
  visualInfo.innerText = `Visual viewport left: ${visualViewport.offsetLeft.toFixed(2)}
    top: ${visualViewport.offsetTop.toFixed(2)}`;
  windowInfo.innerText = `Window scrollX: ${window.scrollX.toFixed(2)}
    scrollY: ${window.scrollY.toFixed(2)}`;
}

updateText();

注意:我們使用 Number.toFixed() 方法將所有值截斷到小數點後兩位,因為某些瀏覽器會將其顯示為亞畫素值,可能帶有大量小數位。

現在,我們在視覺視口和 Window 物件上設定事件處理程式屬性,以便在適當的時間在移動和桌面裝置上執行關鍵函式。

  • 我們在 window 上設定處理程式,以便在常規視窗滾動操作(例如在桌面瀏覽器上滾動頁面)時,資訊框的位置和內容會更新。
  • 我們在 visualViewport 上設定處理程式,以便在視覺視口滾動/縮放操作(例如在移動瀏覽器上滾動和捏合縮放頁面)時,資訊框的位置和內容會更新。
js
visualViewport.onresize = scrollUpdater;
visualViewport.onscroll = scrollUpdater;
visualViewport.onscrollend = scrollendUpdater;
window.onresize = scrollUpdater;
window.onscroll = scrollUpdater;
window.onscrollend = scrollendUpdater;

scrollUpdater() 將在 resizescroll 事件上觸發,而 scrollEndUpdater() 將在 scrollend 事件上觸發。

規範

規範
CSSOM 檢視模組
# visualViewport

瀏覽器相容性

api.VisualViewport

api.Window.visualViewport