實現特性檢測
特性檢測涉及確定瀏覽器是否支援某個程式碼塊,並根據瀏覽器是否支援(或不支援)執行不同的程式碼,以便瀏覽器始終能夠提供正常的工作體驗,而不是在某些瀏覽器中崩潰/出錯。本文詳細介紹瞭如何編寫自己的簡單特性檢測、如何使用庫來加速實現,以及用於特性檢測的原生特性,例如@supports。
| 先決條件 | 熟悉核心HTML、CSS和JavaScript語言;瞭解跨瀏覽器測試原則的高階概念。 |
|---|---|
| 目標 | 瞭解特性檢測的概念,並能夠在 CSS 和 JavaScript 中實現合適的解決方案。 |
特性檢測的概念
特性檢測背後的思想是,您可以執行測試以確定當前瀏覽器是否支援某個特性,然後有條件地執行程式碼以在支援該特性的瀏覽器和不支援該特性的瀏覽器中提供可接受的體驗。如果不這樣做,不支援程式碼中使用的特性的瀏覽器可能無法正確顯示您的網站,或者可能完全失敗,從而導致糟糕的使用者體驗。
讓我們回顧一下,並看看我們在處理常見 JavaScript 問題中提到的示例——地理位置 API(它公開了 Web 瀏覽器正在執行的裝置的可用位置資料)將其使用作為主要入口點,其全域性Navigator物件上有一個geolocation屬性可用。因此,您可以使用如下所示的內容來檢測瀏覽器是否支援地理位置:
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(function (position) {
// show the location on a map, such as the Google Maps API
});
} else {
// Give the user a choice of static maps
}
在繼續之前,我們想預先說明一點——不要將特性檢測與瀏覽器嗅探(檢測訪問網站的具體瀏覽器)混淆——這是一種糟糕的做法,應不惜一切代價避免。請參閱不要瀏覽器嗅探以獲取更多詳細資訊。
編寫你自己的特性檢測測試
在本節中,我們將探討如何在 CSS 和 JavaScript 中實現自己的特性檢測測試。
CSS
您可以透過測試element.style.property(例如paragraph.style.rotate)在 JavaScript 中是否存在來編寫 CSS 特性的測試。
一個經典的例子可能是測試瀏覽器是否支援Subgrid;對於支援grid-template-columns和grid-template-rows的subgrid值的瀏覽器,我們可以在我們的佈局中使用 subgrid。對於不支援的瀏覽器,我們可以使用常規網格,它工作良好,但外觀不如酷炫。
以這個為例,如果支援該值,我們可以包含一個 subgrid 樣式表,如果不支援,則包含一個常規網格樣式表。為此,我們可以在 HTML 檔案的頭部包含兩個樣式表:一個用於所有樣式,另一個在不支援 subgrid 時實現預設佈局。
<link href="basic-styling.css" rel="stylesheet" />
<link class="conditional" href="grid-layout.css" rel="stylesheet" />
這裡,basic-styling.css處理我們想要賦予每個瀏覽器的所有樣式。我們還有兩個額外的 CSS 檔案,grid-layout.css和subgrid-layout.css,其中包含我們想要根據瀏覽器的支援級別有選擇地應用於瀏覽器的 CSS。
我們使用 JavaScript 測試對 subgrid 值的支援,然後根據瀏覽器支援更新條件樣式表的href。
我們可以向我們的文件新增一個<script></script>,其中包含以下 JavaScript 程式碼
const conditional = document.querySelector(".conditional");
if (CSS.supports("grid-template-columns", "subgrid")) {
conditional.setAttribute("href", "subgrid-layout.css");
}
在我們的條件語句中,我們使用CSS.supports()測試grid-template-columns屬性是否支援subgrid值。
@supports
CSS 具有原生特性檢測機制:@supports at-規則。它的工作方式類似於媒體查詢,只不過它不是根據解析度、螢幕寬度或縱橫比等媒體特性有選擇地應用 CSS,而是根據 CSS 特性是否受支援有選擇地應用 CSS,類似於CSS.supports()。
例如,我們可以重寫前面的示例以使用@supports
@supports (grid-template-columns: subgrid) {
main {
display: grid;
grid-template-columns: repeat(9, 1fr);
grid-template-rows: repeat(4, minmax(100px, auto));
}
.item {
display: grid;
grid-column: 2 / 7;
grid-row: 2 / 4;
grid-template-columns: subgrid;
grid-template-rows: repeat(3, 80px);
}
.subitem {
grid-column: 3 / 6;
grid-row: 1 / 3;
}
}
此 at-規則塊僅在當前瀏覽器支援grid-template-columns: subgrid;宣告時才應用其中的 CSS 規則。要使帶值的條件起作用,您需要包含完整的宣告(不僅僅是屬性名稱)並且不要在末尾包含分號。
@supports還提供了AND、OR和NOT邏輯——如果 subgrid 選項不可用,則另一個塊將應用常規網格佈局。
@supports not (grid-template-columns: subgrid) {
/* rules in here */
}
這比前面的示例更方便——我們可以在 CSS 中完成所有特性檢測,無需 JavaScript,並且可以在單個 CSS 檔案中處理所有邏輯,從而減少 HTTP 請求次數。因此,它是確定瀏覽器對 CSS 特性支援的首選方法。
JavaScript
我們之前已經看到了 JavaScript 特性檢測測試的示例。通常,此類測試通過幾種常見模式之一完成。
可檢測特性的常見模式包括
- 物件的成員
-
檢查其父
Object中是否存在特定方法或屬性(通常是使用您正在檢測的 API 或其他特性的入口點)。我們之前的示例使用此模式透過測試
navigator物件是否存在geolocation成員來檢測地理位置支援。jsif ("geolocation" in navigator) { // Access navigator.geolocation APIs } - 元素的屬性
-
使用
Document.createElement()在記憶體中建立元素,然後檢查其上是否存在屬性。此示例顯示了一種檢測Canvas API支援的方法。
jsfunction supports_canvas() { return !!document.createElement("canvas").getContext; } if (supports_canvas()) { // Create and draw on canvas elements } - 元素上方法的特定返回值
-
使用
Document.createElement()在記憶體中建立元素,然後檢查其上是否存在方法。如果存在,請檢查它返回的值。有關此模式的示例,請參閱深入瞭解 HTML 影片格式檢測中的特性測試。 - 元素保留分配的屬性值
-
使用
Document.createElement()在記憶體中建立元素,將屬性設定為特定值,然後檢查該值是否保留。有關此模式的示例,請參閱深入瞭解 HTML <input> 型別檢測中的特性測試。
請記住,但是,已知某些特性是無法檢測的。在這些情況下,您需要使用不同的方法,例如使用polyfill。
matchMedia
我們還想在此處提及Window.matchMedia JavaScript 特性。這是一個允許您在 JavaScript 中執行媒體查詢測試的屬性。它看起來像這樣
if (window.matchMedia("(max-width: 480px)").matches) {
// run JavaScript in here.
}
例如,我們的Snapshot演示利用它有選擇地應用 Brick JavaScript 庫並使用它來處理 UI 佈局,但僅適用於小屏幕布局(480px 寬或更小)。我們首先使用media屬性僅在頁面寬度為 480px 或更小時將 Brick CSS 應用於頁面。
<link
href="dist/brick.css"
rel="stylesheet"
media="all and (max-width: 480px)" />
然後,我們在 JavaScript 中多次使用matchMedia(),僅在小屏幕布局上執行 Brick 導航功能(在較寬的屏幕布局中,所有內容都可以一次看到,因此我們不需要在不同的檢視之間導航)。
if (window.matchMedia("(max-width: 480px)").matches) {
deck.shuffleTo(1);
}