一.作用
與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布局:

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