在 CSS 中使用功能查詢

在 CSS 裏,有一個你可能沒有聽過的工具,可是它已經出現一段時間了,並且很是強大。也許,它會成爲 CSS 中你最喜歡的東西之一。css

那麼,是什麼呢?就是 @support,也就是功能查詢。web

經過 @support,你能夠在 CSS 中使用一小段的測試來查看瀏覽器是否支持一個特定的 CSS 功能(這個功能能夠是 CSS 的某種屬性或者某個屬性的某個值),而後,根據測試的結果來決定是否要應用某段樣式。好比:npm

@supports ( display: grid ) {
    // 若是瀏覽器支持 Grid,這裏面的代碼纔會執行
}

若是瀏覽器可以理解 display: grid,那麼,大括號裏的代碼都會被應用,不然,這些樣式就會被跳過。gulp

如今,對於功能查詢是什麼,你也許還有一點疑惑。這並非經過某種額外的驗證來分析瀏覽器是否已經確切的實現了某個 CSS 屬性。若是你須要查看額外的驗證,能夠查看 Test the Web Forward瀏覽器

功能查詢讓瀏覽器本身就可以表現出是否支持某個 CSS 屬性或者 CSS 屬性值。而後經過這個結果來判斷是否要應用某段 CSS。若是一個瀏覽器沒有正確的(或者徹底的)實現一個 CSS 屬性,那麼,@supports 就沒有什麼用了。它並非一個可以讓瀏覽器的 bug 消失的魔杖。ide

可是,我已經發現 @supports 是那麼難以置信的有幫助。比起之前沒有這個屬性的時候,@supports 可以讓我一再的使用新的 CSS 功能。grunt

多年以來,開發者們都在使用 Modernizr 來實現功能查詢,可是 Modernizr 須要 JavaScript。雖然這部分 JavaScript 很小,可是,CSS 結構中添加了 Modernizr 的話,在 CSS 被應用以前,就須要下載 JavaScript 而後等待執行完成。比起使用 CSS,加入了 JavaScript 老是會更慢。並且,要是 JavaScript 執行失敗了呢?另外,Modernizr 還須要一層額外複雜的、不少項目都沒法理解的東西。相比之下,功能查詢更快,功能更強大,使用起來更簡單。工具

你也許注意到了,@supports 的寫法和媒體查詢很相似,我以爲他們可能就是堂兄弟的關係。佈局

@supports ( display: grid ) {
    main {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    }
}

大多數時候,你其實不須要這樣的測試。好比,你能夠直接這樣寫:測試

aside {
    border: 1px solid black;
    border-radius: 1em;
}

若是瀏覽器可以理解 border-radius,那麼,在相應的容器上就會應用圓角樣式。若是它不能理解這個屬性,那麼,就會直接跳過並繼續執行下面的語句。容器的邊緣也就保持直角了。徹底沒有必要使用功能查詢或者測試,CSS 就是這樣運做的。這是屬於 CSS 中穩固設計,漸進加強的一個基本的原則。瀏覽器會直接跳過他們沒法解析的語句,不會拋出任何錯誤。

大多數瀏覽器都會應用 border-radius: 1em;,而後展現出右邊的效果。可是,在 IE6,7,8 上你卻不能看到圓角,你看到的將是左邊的效果。能夠看看這個例子:A Rounded Corner Box

對於這個例子,沒有必需要使用功能查詢。

那麼,何時才須要使用 @supports 呢?功能查詢是將 CSS 聲明綁定在一塊兒的一個工具,以便於這些 CSS 規則可以在某種條件下以一個組合的方式運行。當你須要混合使用 CSS 的新規則和舊規則的時候,而且,僅當 CSS 新功能被支持的時候,就可使用功能查詢了。

譯者注:如下例子中的 initial-letter 屬性如今在全部現代瀏覽器中都不受支持,因此,如下例子中的代碼可能都是無效的代碼。若是下文中有提到此屬性在某某瀏覽器中受支持的話,請忽略。須要瞭解 initial-letter 詳細的說明,能夠參考 initial-letter | MDN

來看一個關於使用 initial-letter 的例子。這個屬性告訴瀏覽器要將特指的那個元素變得更大,就像一個段首大字同樣。在這裏,咱們要作的就是讓段落的第一個字母的大小爲四行文字那麼大。同時,咱們再對它進行加粗,在它的右邊設置一些 margin,還給它設置一個高亮的橘色。OK,很不錯了。

p::first-letter {
    margin-right: 0.5em;
    color: #FE742F;
    font-weight: bold;
    -webkit-initial-letter: 4;
    initial-letter: 4;
}

這是在 Safari 上的效果

讓咱們看看在其餘瀏覽器上的效果。

好吧,簡直無法接受。除了使用 initial-letter 來達到咱們想要的效果以外,咱們並不想要改變字體的 colormargin,和 font-weight。因此,咱們須要一個方法來測試瀏覽器是否支持 initial-letter 這個屬性,而後在瀏覽器支持這個屬性的時候再應用相關的樣式。因此,使用功能查詢:

@supports (initial-letter: 4) or (-webkit-initial-letter: 4) {
    p::first-letter {
        -webkit-initial-letter: 4;
        initial-letter: 4;
        color: #FE742F;
        font-weight: bold;
        margin-right: 0.5em;
    }
}

注意,測試的時候須要進行徹底的測試,CSS 屬性和值都得寫上。一開始我也比較疑惑,爲何非得測試 initial-letter: 4 呢?4 這個值很重要嗎?若是我寫成 17 呢?莫非是須要匹配我即將要應用的 CSS 中的樣式嗎?

緣由是這樣的:@supports 在測試的時候,須要提供屬性和值,由於有時候測試的是屬性,有時候測試的是值。對於 initial-letter ,你輸入多少值並不重要。可是,若是是 @suports ( dislay: grid ) 就不同了,全部瀏覽器都識別 display,可是,並非全部瀏覽器都識別 display: grid

回到咱們的例子,當前的 initial-letter 只在 Safari 9 上受支持,而且須要加前綴。因此,我加了前綴,同時,保持着不加前綴的規則,而且,我還寫了測試來測試另外的屬性。沒錯,在功能查詢中,還可使用 and, or, not 聲明。

下面是新的結果。理解 initial-letter 的瀏覽器會顯示一個巨大加粗高亮的段首大字。其餘瀏覽器的行爲就像是這個段首大字不存在同樣。固然,若是更多的瀏覽器支持了這個屬性,那麼,他們的行爲也將會是有一個段首大字。

組織你的代碼

如今,也許你火燒眉毛的想要使用這個工具來將你的代碼分爲兩個分支,使其變得乾淨一些。「Hey,瀏覽器,若是你識別 Viewport 單位,就執行這個,不然,執行另外的」。感受很不錯,有條理。

@supports ( height: 100vh ) {
    // 支持 viewport height 的樣式
}
@supports not ( height: 100vh ) {
    // 對於舊瀏覽器的替代樣式
}
// 咱們但願是好的,但這是一段爛代碼

這段代碼並很差,至少當前看來是這樣的。發現問題了嗎?

問題就是,並非全部的瀏覽器都支持功能查詢,不理解 @supports 的瀏覽器會直接跳過兩段代碼,這也許就太糟糕了。

意思就是,除非瀏覽器百分之百支持功能查詢,不然咱們就無法使用了嗎?固然不是,咱們徹底可使用功能查詢,並且應該使用功能查詢,只要不像上面那樣寫代碼就行。

那麼,怎麼作纔對呢?其實與使用媒體查詢相似,咱們在瀏覽器徹底支持媒體查詢以前就開始使用了不是嗎?事實上,功能查詢使用起來比媒體查詢更簡單,只要腦子放聰明一點就好了。

你想要讓你的代碼知道瀏覽器是否支持功能查詢或者正在測試的某個功能,我來告訴你怎麼作。

固然,在將來,瀏覽器 100% 支持功能查詢的時候,咱們能夠大量使用 @supports not 來組織咱們的代碼。

功能查詢的支持狀況

因此,@supports 如今支持度什麼樣了呢?

自從 2013 年中,@supports 就可以在 Firefox,Chrome 和 Opera 中使用了。在 Edge 的各個版本中也受支持。Safari 在 2015 年秋季才實現這個功能。具體的支持狀況,請看下面這張圖:

你可能會以爲 IE 不支持此功能會是一個大問題,可是,其實不是這樣的。待會兒就會告訴你緣由。我相信,最大的一個障礙是 Safari 8,咱們須要留意在這個瀏覽器上發生的事情。

讓咱們來看另一個例子。假設咱們有些佈局代碼,爲了正常運行,須要使用 object-fit: cover;。對於不支持這個屬性的瀏覽器,咱們想要使用不一樣的樣式。

因此,咱們能夠這樣寫:

@supports (initial-letter: 4) or (-webkit-initial-letter: 4) {
    p::first-letter {
        -webkit-initial-letter: 4;
        initial-letter: 4;
        color: #FE742F;
        font-weight: bold;
        margin-right: 0.5em;
    }
}

div {
    width: 300px;
    background: yellow;
}
@supports (object-fit: cover) {
    img {
        object-fit: cover;
    }
    div {
        width: auto;
        background: green;
    }
}

會發生什麼呢?@supports 有支持或者不支持的狀況,object-fit 也有支持或者不支持的狀況,因此,就有了四種可能性:

功能查詢支持狀況 屬性(或者值)支持狀況 會發生什麼 是否咱們想要的
支持 不支持 CSS 將會被應用
支持 不支持 CSS 不會被應用
不支持 支持 CSS 不會被應用
不支持 不支持 CSS 不會被應用

最佳實踐

因此,咱們應該怎麼寫功能查詢的代碼呢?像下面這樣:

// fallback code for older browsers

@supports ( display: grid ) {
    // code for newer browsers
    // including overrides of the code above, if needed
}

譯者注:本文的主要內容是介紹功能查詢和 @supports 的使用方法,因此,某些代碼多是沒法運行的,但願讀者們注意。同時,因爲原文中的一些內容顯得比較冗餘,因此部份內容並無翻譯。若是須要了解詳細內容,請查看原文。
翻譯自 Using Feature Queries in CSS

相關文章
相關標籤/搜索