什麼是 CSS 特性檢測?我們知道,前端技術日新月異的今天,各種新技術新屬性層出不窮。在 CSS 層面亦不例外。
一些新屬效能極大提升使用者體驗以及減少工程師的工作量,並且在當下的前端氛圍下:
- 很多實驗性功能未成為標準卻被大量使用;
- 需要相容多終端,多瀏覽器,而各瀏覽器對某一新功能的實現表現的天差地別;
所以有了優雅降級和漸進增強的說法,在這種背景下,又想使用新的技術給使用者提供更好的體驗,又想做好回退機制保證低版本終端使用者的基本體驗,CSS 特性檢測就應運而生了。
CSS 特性檢測就是針對不同瀏覽器終端,判斷當前瀏覽器對某個特性是否支援。運用 CSS 特性檢測,我們可以在支援當前特性的瀏覽器環境下使用新的技術,而不支援的則做出某些回退機制。
本文將主要介紹兩種 CSS 特性檢測的方式:
@supports
- modernizr
CSS @supports
傳統的 CSS 特性檢測都是通過 javascript 實現的,但是未來,原生 CSS 即可實現。
CSS @supports
通過 CSS 語法來實現特性檢測,並在內部 CSS 區塊中寫入如果特性檢測通過希望實現的 CSS 語句。
語法:
1 2 3 |
@supports <supports_condition> { /* specific rules */ } |
舉個例子:
1 2 3 4 5 6 7 8 9 |
{ position: fixed; } @supports (position:sticky) { div { position:sticky; } } |
上面的例子中,position: sticky
是 position 的一個新屬性,用於實現黏性佈局,可以輕鬆實現一些以往需要 javascript 才能實現的佈局(戳我瞭解詳情),但是目前只有在 -webkit- 核心下才得到支援。
上面的寫法,首先定義了 div 的 position: fixed
,緊接著下面一句 @supports (position:sticky)
則是特性檢測括號內的內容,如果當前瀏覽器支援 @supports
語法,並且支援 position:sticky
語法,那麼 div 的 則會被設定為 position:sticky
。
我們可以看到,@supports
語法的核心就在於這一句:@supports (...) { }
,括號內是一個 CSS 表示式,如果瀏覽器判斷括號內的表示式合法,那麼接下來就會去渲染括號內的 CSS 表示式。除了這種最常規的用法,還可以配合其他幾個關鍵字:
@supports not
&& @supports and
&& @supports or
@supports not
— 非
not 操作符可以放在任何表示式的前面來產生一個新的表示式,新的表示式為原表示式的值的否定。看個例子:
1 2 3 4 5 |
@supports not (background: linear-gradient(90deg, red, yellow)) { div { background: red; } } |
因為新增了 not 關鍵字,所以與上面第一個例子相反,這裡如果檢測到瀏覽器不支援線性漸變 background: linear-gradient(90deg, red, yellow)
的語法,則將 div 的顏色設定為紅色 background: red
。
h3>@supports and
— 與
這個也好理解,多重判斷,類似 javascript 的 &&
運算子符。用 and 操作符連線兩個原始的表示式。只有兩個原始表示式的值都為真,生成的表示式才為真,反之為假。
當然,and 可以連線任意多個表示式看個例子:
1 2 3 4 5 6 7 8 9 10 11 |
p { overflow: hidden; text-overflow: ellipsis; } @supports (display:-webkit-box) and (-webkit-line-clamp:2) and (-webkit-box-orient:vertical) { p { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } } |
上面同時,檢測 @supports (display:-webkit-box) and (-webkit-line-clamp:2) and (-webkit-box-orient:vertical)
了三個語法,如果同時支援,則設定三個 CSS 規則。這三個語法必須同時得到瀏覽器的支援,如果表示式為真,則可以用於實現多行省略效果:
See the Pen @supportAnd by Chokcoco (@Chokcoco) on CodePen.
@supports or
— 或
理解了 @supports and
,就很好理解 @supports or
了,與 javascript 的 ||
運算子類似,表示式中只要有一個為真,則生成表示式表示式為真。看例子:
1 2 3 4 5 6 |
@supports (background:-webkit-linear-gradient(0deg, yellow, red)) or (background:linear-gradient(90deg, yellow, red)){ div { background:-webkit-linear-gradient(0deg, yellow, red); background:linear-gradient(90deg, yellow, red) } } |
上面的例子中,只有檢測到瀏覽器支援 background:-webkit-linear-gradient(0deg, yellow, red)
或者(or) background:linear-gradient(90deg, yellow, red)
其中一個,則給 div 元素新增漸變。
See the Pen @supports or by Chokcoco (@Chokcoco) on CodePen.
當然,關鍵字 not
還可以和 and
或者 or
混合使用。感興趣的可以嘗試一下。
Can i use?
相容性來看,先看看 Can i use 吧:
這仍是一個實驗中的功能,雖然大部分瀏覽器都已經支援了,但是目前看來,即是在移動端想要全部相容仍需要等待一段時間。
但是我們已經可以開始使用起來了,使用 @supports
實現漸進增強的效果。
漸進增強(progressive enhancement):針對低版本瀏覽器進行構建頁面,保證最基本的功能,然後再針對高階瀏覽器進行效果、互動等改進和追加功能達到更好的使用者體驗:
CSS.supports()
談到了 @supports
,就有必要再說說 CSS.supports()
。
它是作為 @supports
的另一種形式出現的,我們可以使用 javascript 的方式來獲得 CSS 屬性的支援情況。
可以開啟控制檯,輸入 CSS.supports
試試:
如果沒有自己實現 CSS.supports 這個方法,輸出上述資訊,表示瀏覽器是支援 @supports
語法的,使用如下:
1 2 |
CSS.supports('display', 'flex') // true CSS.supports('position', 'sticky') // true |
那它有什麼用呢?如果你的頁面需要動態新增一些你不確定哪些瀏覽器支援的新的屬性,那它也許會派上用場。以及,它可以配合我們下文即將要講的 modernizr 。
modernizr
上面介紹了 CSS 方式的特性檢測,在以前,通常是使用 javascript 來進行特性檢測的,其中 modernizr 就是其中最為出色的佼佼者。
modernizr(戳我檢視 Github )是一個開源的 javascript 庫。有著將近 2W 的 star ,其優秀程度可見一斑。
簡單看看使用方法,假設頁面已經引用了 modernizr ,語法如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
// Listen to a test, give it a callback Modernizr.on('testname', function( result ) { if (result) { console.log('The test passed!'); } else { console.log('The test failed!'); } }); // 或者是類似 CSS.supports() Modernizr.testAllProps('background', 'linear-gradient(90deg, #888, #ccc)'); // true |
舉個實際的例子,假設我們希望對是否支援漸變這個樣式瀏覽器下的一個 div 區別對待,有如下 CSS:
1 2 3 4 5 6 7 |
div { background: #aaa; } .linear-gradient div{ background: linear-gradient(90deg, #888, #ccc); } |
使用 Modernizr 進行判斷,如果支援漸變,則在根元素新增一個 .linear-gradient
樣式,方便示例,使用了 jquery 語法:
1 2 3 |
if (Modernizr.testAllProps('background', 'linear-gradient(90deg, #888, #ccc)')) { $('html').addClass('linear-gradient'); } |
See the Pen modernizr by Chokcoco (@Chokcoco) on CodePen.
當然,Modernizr 還有很多其他的功能,可以去翻翻它的 API 。
特性檢測原理
如果嫌引入整一個 Modernizr 庫太大,頁面又不支援 @supports
,其實我們自己用簡單的 javascript 實現也非常方便簡單。
想要知道瀏覽器支援多少 CSS 屬性,可以在除錯視窗試試:
1 2 3 4 5 |
var root = document.documentElement; //HTML for(var key in root.style) { console.log(key); } |
上面圖片擷取的只是列印出來的一小部分。如果我們要檢測某個屬性樣式是否被支援,在任意的 element.style 檢測它是否存在即可,即上面程式碼示例的 root
可以替換成任意元素。
當然,元素可能有 background
屬性,但是不支援具體的 linear-gradinet()
屬性值。這個時候該如何檢測呢?只需要將具體的值賦值給某一元素,再查詢這個屬性值能否被讀取。
1 2 3 4 5 6 7 8 9 |
var root = document.documentElement; root.style.backgroundImage = 'linear-gradient(90deg, #888, #ccc)'; if(root.style.backgroundImage) { // 支援 } else { // 不支援 } |
所以上面 Modernizr 的例子裡,javascript 程式碼可以改成:
1 2 3 4 5 6 |
var root = document.documentElement; root.style.backgroundImage = 'linear-gradient(90deg, #888, #ccc)'; if(root.style.backgroundImage) { $('html').addClass('linear-gradient'); } |
當然,做這種特定屬性值判斷的時候由於有個 CSS 賦值操作,所以我們選取用於判斷的元素應該是一個隱藏在頁面上的元素。
各種方式間的優劣
- 原生的
@supports
的效能肯定是最好的,而且無需引入外部 javascript ,首推這個,但是無奈相容問題,目前來看不是最好的選擇。
- Modernizr 功能強大,相容性好,但是需要引入外部 javascript,多一個 http 請求,如果只是進行幾個特性檢測,有點殺雞用牛刀的感覺。
- 針對需要的特性檢測,使用 javascript 實現一個簡單的函式,再把上面用到的方法封裝一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/** * 用於簡單的 CSS 特性檢測 * @param [String] property 需要檢測的 CSS 屬性名 * @param [String] value 樣式的具體屬性值 * @return [Boolean] 是否通過檢查 */ function cssTest(property, value) { // 用於測試的元素,隱藏在頁面上 var ele = document.getElementById('test-display-none'); // 只有一個引數的情況 if(arguments.length === 1) { if(property in ele.style) { return true; } // 兩個引數的情況 }else if(arguments.length === 2){ ele.style[property] = value; if(ele.style[property]) { return true; } } return false; } |
簡單測試一下:
軟體工程沒有銀彈,所以無論哪種方式,都有適合的場景,我們要做的就是掌握瞭解它們的原理,根據不同的場景靈活運用即可。
系列 CSS 文章彙總在我的 Github 。
到此本文結束,如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式