CSS @supportsの知っていると便利な使い方のまとめ
Post on:2019年3月1日
CSSの@supportsは機能クエリと呼ばれ、CSSの特定のプロパティやプロパティと値の組み合わせがブラウザにサポートされているかチェックするための機能です。言い換えると、条件分岐でスタイルを適用することができます。
そんな便利な@supportsの基礎知識と実践的な使い方、そして古い使い方や実は役に立っていない使い方などを紹介します。
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- @supportsの古い活用事例
- @supportsにnotがあるけれど、常に使用するべきという意味ではない
- @supportsのサポートブラウザ
- @supportsが何の役にも立たない使い方
- @supportsで遊ぶための拡張機能
- @supportsのより現実的な活用事例
- @supportsのロジック
- JavaScriptでの変形
- セレクタのサポートをチェック
- 終わりに
はじめに
CSSにはスタイルを適用する前に、特定のプロパティやプロパティと値の組み合わせがサポートされているかチェックするための機能があります。
この機能は@supportsと呼ばれ、下記のようなコードを使用します。
1 2 3 4 5 |
@supports (display: grid) { .main { display: grid; } } |
この機能を使う際は、少し慎重さを要します。個人的には、必要ではない時もあると思います。CSSはブラウザがプロパティや値の組み合わせを理解できない場合はそれらを無視し、何かがあればそれより前に宣言されたものを使用するというフォールバックのメカニズムを持っています。この機能はフォールバックを処理するために使用することができ、最終的な結果は冗長ではありません。確かに、ブラウザごとに同じことをしているわけではありませんが、同様に手の込んだフォールバックを書くわけでもありません。
とは言っても、@supportsには活用事例が確実にあります。私がこの記事を書いている間に見つけた数多くの活用事例を紹介します。
@supportsの古い活用事例
前述したコードは単なる例で、実際には多くのコードを書くのが普通です。少し加えてみました。
1 2 3 4 5 6 7 8 9 |
/* 通常、ここにフォールバックを書きます */ @supports (display: grid) { .photo-layout { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; } } |
CSS Gridは優れた機能を備えていますが、サポートしていないブラウザもあります。
例えば、iOSはバージョン10.2でGridをサポートしましたが、バージョン7以降はFlexboxをサポートしています。これは、FlexboxはサポートしているがGridはサポートしていない古いiOSを使用している人にとっては、かなりのギャップです。私はそのようなギャップがもっとあると確信しています。
I was running on an older version of mobile safari and many many many many many sites were flat out broken that used grid
I’m waiting another year or so before messing about with it
— David Wells (@DavidWells) 2019年2月6日
要件によっては、これに対するフォールバックを無効にしてもよいかもしれません。例えば、マルチカラムのグリッドレイアウトではなく、垂直に積み重ねたブロックレベルの要素です。しかし、フォトギャラリーのようにグリッド構造を絶対に必要とするような場合は適さないでしょう。その場合は、デフォルトとしてFlexboxから始めて、サポートされている場合のみGridの機能を適用するために@supportsを使用する方がうまくいくかもしれません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.photo-layout { display: flex; flex-wrap: wrap; > div { flex: 200px; margin: 1rem; } } @supports (display: grid) { .photo-layout { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; > div { margin: 0; } } } |
フォールバックは通常@supportsブロックより前のコードで、Gridのコードはブロックの内側に記述します。@supportsブロックは詳細度を変更しないので、スタイルの上書きが確実に機能するようにコードの順番が大切です。
注意点として、@supportsブロック内でdivのマージンをリセットする必要があります。これはちょっと面倒かもしれません。それらがお互いにどのように影響を与えるかを十分に認識している必要があります。
スタイルを論理的に分離して記述できたらいいのにな、と思いませんか。
@supportsにnotがあるけれど、常に使用するべきという意味ではない
Jen Simmonsはこの例を「Using Feature Queries in CSS」にまとめています。
1 2 3 4 5 6 7 |
/* 少なくともIE 11とiOS 8以上をサポートしているなら、これは悪い習慣 */ @supports not (display: grid) { /* Gridをサポートしていない場合のコード */ } @supports (display: grid) { /* Gridをサポートしている場合のコード */ } |
最初のブロックのnot演算子に注目してください。これは特定のスタイルを適用するためにGridをサポートしていないブラウザをチェックしています。この方法が悪い習慣であると考えられる理由は、@supports自体に対するブラウザのサポートを考慮しなければならないということです。だからこそ、これは非常に慎重を要します。
論理的に分離された@supportsブロックでコードを書くことは非常に魅力的です。それは毎回ゼロから始まり、前の値を上書きしてそれらの論理的な考え方に対処する必要がないからです。しかし、さきほどと同じiOSの状況に戻りましょう。@supportsはiOS 9でサポートされました(FlexboxがiOS 7にサポートされた時とGridががiOS 10.2にサポートされた時の間)。つまり、not演算子を使用して(display: grid) {}のチェックをしても、@supportsブロック内のフォールバック用のFlexboxのコードは、iOS 7と8のどちらでも機能しません。
@supportsを使用する大きな理由は、コードのブロックが分離されている場合、見た目が簡単になり、実装が区別でき、機能のサポートに応じて異なる実装ができることです。
相互に排他的なブロックを心配することなく使用できるようになるでしょう。どちらを取るかという話なら、、、
@supportsのサポートブラウザ
@supportsは時間が経つにつれて、より有用になる可能性があります。
サポートする必要があるすべてのブラウザで@supportsがサポートされたら、今よりもっと積極的に使い始めることをお勧めします。
基本的に、IE 11とiOS 8で動かなくなったiOSデバイスが問題です。それらをサポートする必要がなければ、@supportsを好きなように使用できます。
皮肉なことに、@supportsの明確な活用事例は多くありません、しかし数は少ないですが、存在することは確かです。
Using it on my wedding website to check for Houdini support 🎩🐰
— Sam Richard (@Snugug) 2019年2月6日
@supportsが何の役にも立たない使い方
@supportsを使用しない場合と全く同じなのに使用しているコードを私はたくさん見かけました。例えば、
1 2 3 4 5 |
@supports (transform: rotate(5deg)) { .avatar { transform: rotate(5deg); } } |
あるレベルでは、完全に論理的な意味があります。tranformがサポートされている場合は、スタイルを適用します。しかし、サポート以外のシナリオで何も変わらない場合は不要です。この場合、@supportsブロックがないとtranformは失敗する可能性があり、結果は同じです。
このような例は他にもあります。
Not regularly, but I've been experimenting with setting a default weight for variable fonts: pic.twitter.com/FA4Cv10LGF
— Chris Silvermαn (@_csilverman) 2019年2月6日
@supportsで遊ぶための拡張機能
2つ紹介します。
どちらも、CSSで@supportsブロックを記述してから、その機能をサポートしているかどうかにかかわらず、ブラウザでコードのレンダリングを見ているかのようにオンとオフを切り替えることができます。
CSS Feature Toggle Extensionで、FlexboxをフォールバックにしたGridの例です。
操作が楽しいだけでなく、技術も非常に確かなものです。もし私がFlexboxを使って同じようにレイアウトをすることができれば、技術的な負荷を軽減することになるでしょう。
Feature Queries Managerはデベロッパーツールの機能拡張で、CSSで実際に書いたfeature queriesを表示し、オンとオフに切り替えるためのトグルを提供します。
@supportsのより現実的な活用事例
Erik Vorhes氏のデモページを見てみましょう。ここでいくつかのチェックボックスとラジオボタンをスタイルしていますが、それらを@supportsブロックで内包しています。@supportsのチェックに合格しない限り、ブロック内にあるスタイルは適用されません。
1 2 3 |
@supports (transform: rotate(1turn)) and (opacity: 0) { /* all the styling for Erik's custom checkboxes and radio buttons */ } |
- Joe Wright氏のツイートとTiago Nunes氏のツイートでは、position: sticky;で使用するとあります。これはposition: sticky;がサポートされていないブラウザのために失敗させることを除いて別の何かをする必要があります。
- Keith Grant氏のツイートとMatthias Ott氏のツイートでは、object-fit: contain;で使用するとあります。デモページもあり、イメージを並べ替えてコンテナを埋めます。このプロパティを使用すると、そのプロパティを使用して簡単かつ適切に実装できます。
- Ryan Filler氏はmix-blend-modeで使用するとあります。要素の不透明度を高めに設定し、mix-blend-modeがサポートされている場合は、要素を少し透けて見ることができます。
123456789.thing {opacity: 0.5;}@supports (mix-blend-mode: multiply) {.thing {mix-blend-mode: multiply;opacity: 0.75;}} - Rik Schennink氏のツイートでは、backdrop-filterで使用するとあります。サポートされている場合は、背景色の不透明度を調整する必要があることがよくあると、彼は言っています。
- Nour Saud氏のツイートでは、@supports (-ms-ime-align:auto) { }特定のベンダ接頭辞付きプロパティを使って、Edgeを検出するために使うことができます。
- Amber Weinberg氏のツイートでは、クリッピングが利用できないときに要素のサイズやパディングを調整することで対応できるので、clip-pathで使用するとあります。
- Ralph Holzmann氏のツイートでは、env変数を使用してスマホにノッチがあるかチェックするとあります。
参考: The Notch and CSS - Stacy Kvernmo氏のツイートでは、ドロップキャップの文字に必要なさまざまなプロパティのためにそれを使うとをあります。Jen Simmons氏はこの事例を記事にしています(Using Feature Queries in CSS)。ドロップキャップにはinitial-letterプロパティがありますが、 initial-letterがサポートされていない場合(またはまったく使用されていない場合)は適用したくない他のプロパティと組み合わせて使用します。
最後に、Nick Colley氏のツイートの例を紹介します。これは@supportsではなく、@mediaを使った場合ですが、考え方は同じです。下記のコードで、タッチデバイスでのスタックホバーを防ぐことができます。
1 2 3 4 5 |
@media (hover: hover) { a:hover { background: yellow; } } |
@supportsのロジック
Basic:
1 2 3 |
@supports (initial-letter: 4) { } |
Not:
1 2 3 |
@supports not (initial-letter: 4) { } |
And:
1 2 3 |
@supports (initial-letter: 4) and (transform: scale(2)) { } |
Or:
1 2 3 |
@supports (initial-letter: 4) or (-webkit-initial-letter: 4) { } |
Combos:
1 2 3 4 5 |
@supports ((display: -webkit-flex) or (display: -moz-flex) or (display: flex)) and (-webkit-appearance: caret) { } |
JavaScriptでの変形
JavaScriptにはこのためのAPIがあります。それが存在するかどうかをテストするには、
1 2 3 4 |
if (window.CSS && window.CSS.supports) { // Apparently old Opera had a weird implementation, so you could also do: // !!((window.CSS && window.CSS.supports) || window.supportsCSS || false) } |
これを使用するには、パラメータでプロパティを渡し、別のパラメータで値を渡します。
1 |
const supportsGrid = CSS.supports("display", "grid"); |
または、CSSの構文を反映した1つの文字列ですべてを指定します。
1 |
const supportsGrid = CSS.supports("(display: grid)"); |
セレクタのサポートをチェック
2019年2月現在、Firefoxだけ(experimental flagで)が@supportでセレクタのチェックをサポートしています。
MDNのデモページ
1 2 |
@supports selector(A > B) { } |
終わりに
わたし達は@supportsの活用事例を見ることが好きです。あなたが使用している例を共有してください。
sponsors