天天看點

CSS Feature Query

一.作用

與media query(媒體查詢)類似,feature query(特性查詢)也是一種條件樣式,僅在支援特定樣式規則的環境應用指定的一組樣式:

等等,這種能力似乎CSS生來就有:

為了保證新屬性和新值将來可以添在現有的屬性上,使用者代理必須忽略一份非法樣式表的某一部分,如含有未知屬性的聲明、含有非法值的聲明、含有未知@關鍵字的@規則等等。

P.S.具體見4.2 處了解析錯誤的規則

CSS從設計之初就是容錯的,目前環境下支援的樣式規則會被正确應用,不支援的會被靜默忽略掉:

比如經常見到的:

我們知道在支援box-shadow的環境下會呈現陰影,使之看起來像是一張懸浮的卡片,在不支援的環境則隻剩下外邊距與邊框,變成扁平的普通矩形塊,算是天然的樣式降級。這種包容能力,讓新特性的應用少了一些憂慮(大不了不支援,回到降級方案)

那麼,feature query帶來了什麼能力?

相當于内置了友好的漸進增強機制,之前通常用Modernizr來做的事情,現在多了一種選擇,比如:

與之前的差別在于,就影響範圍而言,容錯降級隻會影響應用了這些不支援樣式的元素,而特性查詢降級能夠影響一組任意元素,例如:

P.S.嚴格地講,容錯降級一般是聲明級的(一些聲明被忽略或應用),而特性查詢降級是規則集級的(一些規則集被忽略或應用):

聲明要麼為空要麼由一個後面跟着冒号(:)和屬性值的屬性名組成,之間可以有空白字元

規則集(也叫“規則”),由後面跟着一個聲明塊的選擇器組成

二.文法

文法層面,feature query稱為@supports CSS at-rule,與media query對比如下:

長得很像,都表示@關鍵字後面的條件成立時,應用{...}裡的樣式規則。二者都是條件分組規則(conditional group rules):

另外,條件部分支援與(and)或(or)非(not)邏輯運算:

P.S.僅支援屬性名-值對兒形式的條件,不支援其它形式的,比如:

三.用法

實際場景中,一般模式(最佳實踐)為:

需要注意的是,不支援某特性并不等價于否定形式的feature query(@supports not):

無法如預期地篩選出不支援vh的環境,因為如果連@supports都不支援,整個@規則都會被忽略,包括這組降級樣式。也就是說,這個判斷不可靠,會漏掉一部分(既不支援@supports也不支援vh的環境)

同樣,肯定形式的feature query也不是完全可靠的,例如:

在不支援@supports但支援vh的環境,就不符合預期。但這通常不足為慮,因為一般需要判斷支援性的特性比feature query更前沿一些

四.優雅降級與漸進增強

針對浏覽器不一緻的問題,這是兩種類似的應對政策,差別在于:

優雅降級:高端環境優先,妥協讓步低端環境(特效全開,低端環境進行特效降級,底線是保證可用)

漸進增強:低端環境優先,特殊照顧高端環境(先保證可用的底線,再考慮加特技)

Modernizer

Modernizr,一般特性檢測方案,通過JS來檢查運作環境是否支援指定特性:

簡言之,Modernizr有助于區分高端與低端環境,這樣就允許我們針對低端環境進行降級(fallback),或者打更新檔(polyfill)。例如:

作為一種JS方案,優勢是足夠靈活,不僅支援查詢CSS特性,還支援所有可以通過JS檢測的特性,例如:

但存在幾個問題:

性能:需要引入額外JS,需檢測的新特性會越來越多,體積勢必越來越大,存在性能負擔

擴充性:依賴第三方支援,最新的特性可能需要等待一段時間才有對應的特性檢測,相當于(更新Modernizr版本)手動擴充

易用程度:通過查表得到目标特性的名稱(如batteryapi、flexbox等,更多名稱見Features detected by Modernizr)後,才能檢查該特性,不很友善

特性粒度:以上面提到的特性名稱為最小檢測單元,并不一定合适,比如justify-content: space-evenly可能沒有與之對應的特性名稱

可靠性:依靠輔助手段來檢測特性支援性,并不百分百靠譜,比如部分實作的版本,可能無法準确區分出來

CSS Feature Query

浏覽器内置的CSS特性檢測支援。是否支援某樣式規則,最清楚這件事的當然是浏覽器自己,隻是這次通過feature query把這種内部狀态暴露出來了而已

對比Modernizer,有幾個優勢:

性能更優:純CSS方案,不需要JS參與

擴充性良好:作為浏覽器的基礎能力,任意新特性釋出後都立即可檢測,不需要手動擴充

文法自然:以樣式聲明作為查詢條件,而不需要查表獲得特性名

細粒度:屬性名-值對兒粒度,足夠靈活

可靠:支援不支援是浏覽器自己說的,絕對靠譜

當然,缺點是隻支援樣式特性查詢,對于非CSS特性則無能為力。是以就功能而言,Modernizer是CSS feature query的超集

五.相容性

桌面:Firefox、Chrome、[Safari 9+]、[Edge 12+]([IE 11-]都不支援)

移動:[iOS 9.0+]、[Android 4.4+]

P.S.具體見Can I use

移動端基本可以放心使用了,即便不支援@supports,也沒有實質影響(隻是會忽略這組樣式,與低端環境的表現一緻)

特殊的,需要注意幾點:

feature query無助于識别存在bug的特性實作,與某些不完整的特性實作(比如不支援某種機制,但無法從屬性名/值上區分出來)

feature query特性自身的相容性問題會導緻某些場景不符合預期(比如支援某特性,卻由于不支援@supports而被忽略掉了),但不會造成嚴重影響

一個典型的例子是Safari 8支援flexbox,但不支援feature query,就會出現bad case:

例如:

在Safari 8下就呈現降級樣式了,雖然它支援flexbox

六.應用場景

就應用場景而言,feature query用來解決新特性相容性方面的憂慮,作為漸進增強的一種手段,一般用法:

漸進增強,意味着要接受多環境下的不一緻。實際上,對于陰影、圓角、動畫之類的很容易接受這種不一緻(在不友好的環境去掉這些錦上添花的效果),而對于flexbox、grid等布局方案,似乎很難與漸進增強聯系起來,因為布局通常是不可或缺的,而不隻是錦上添花

漸進使用grid特性

Is There A CSS Grid Polyfill?

盡管很遺憾,但grid布局确實沒有CSS polyfill。那麼,非得等到多年以後才能使用這個強大的特性嗎?

當然不是。至少有兩種選擇:

漸進地(僅在支援的環境)使用grid特性(即接受不同環境下的布局存在差異)

JS更新檔方案沒什麼好說的,對于漸進方案,關鍵在于接受這種差異:

把布局效果也當做一種增強樣式(像陰影、圓角等效果一樣),允許在低端環境展示另一種不同的降級(布局)效果。例如:

對應樣式為:

(摘自display: feature queries demo)

在支援Grid的環境下,呈現為漂亮的泾渭分明的3列等比布局,在不支援的環境,降級到稍顯擁擠的float布局:

CSS Feature Query

grid-layout-css-polyfill

差強人意,但在不改變結構、不借助JS的前提下,float方案差不多隻能做到這種程度了。如果能夠接受類似差異的話,通過feature query漸進使用,新特性的相容問題将不再重要

檢查是否支援自定義屬性

利用CSS變量,很容易把換膚功能作為一種增強效果來提供

首字母下沉效果

在支援initial-letter的環境(如Safari)很容易實作這種常見的排版效果(段落首字母下沉4行):

不支援的話,用正常方式來實作:

P.S.更多案例見參考資料中feature query相關的,如mix-blend-mode等

參考資料

@supports

Using Feature Queries in CSS

How to use CSS Feature Queries

Using CSS Grid: Supporting Browsers Without Grid

Basic grid layout with fallbacks using feature queries