CSSの:has()がブラウザで使用できるかを@supportsで検出するには、:has(*)ではなく、:has(+ *)にする必要がある
Post on:2023年1月17日
CSSの@supports selector()
で検出するには、:has(*)
ではなく、:has(+ *)
が必要です。
これは2023年現在、:has()
はFirefoxを除くすべての主要ブラウザでサポートされていますが、Firefoxで実験的な機能としてサポートされているためです。
CSS :has() feature detection with @supports(selector(…)): You want :has(+ *), not :has(*)
by @Bramus
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
CSSの@supports selector()
で検出するには:has(*)
ではなく、:has(+ *)
が必要です。
:has(+ *)
に注目!
CSSの:has()を検出するには
CSSの:has()
セレクタをブラウザで使用できるか検出するには、@supports(selector(…))
を使用することができます。その際、引数に有効なセレクタを含めることが重要です。
以前にもツイートしましたが、機能クエリで使用する場合は*
などのセレクタを:has()
に渡す必要があります。
1 2 3 4 5 6 7 8 9 |
/* ❌ これは常に false と評価されます。 */ @supports selector(:has()) { … } /* ✅ これは:has()をサポートするブラウザで true と評価されます。 */ @supports selector(:has(*)) { … } |
💁♂️ 当初このセレクタの要件はSafariだけのものでしたが、仕様レベルで調整され、他のすべてのブラウザの要件となりました。
私はこのテクニックを使用して、:has()
を使用した条件付きでメッセージを表示するデモを作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* 表示するメッセージ */ .no-support { margin: 1em 0; padding: 1em; border: 1px solid #ccc; background-color: #ff00002b; display: block; } /* :has()のサポートが検出された場合にメッセージを非表示にします */ @supports selector(:has(*)) { .no-support { display: none; } } |
:has()
をブラウザがサポートしていない場合、そのことを伝えるメッセージが表示されます。下記はFirefoxの場合で、2023年1月現在Firefoxはまだ:has()
をサポートしていません。
Firefoxでデモページを表示
Firefoxは:has()をサポートしてないため、デモを表示するとメッセージが表示されます。
:has(*)を使用した場合の問題点
前述の方法で:has()
を機能的に検出することはできますが、100%ではありません。その犯人はFirefoxで、実験的な機能でサポートされているからです。
Firefoxでlayout.css.has-selector.enabled
のフラグをオンにすると、@supports selector(:has(*))
を使用したときにサポートされていると主張します。しかし、この実験的な実装では相対セレクタの解析が(まだ)サポートされていないという事実は説明されていません。
前述のデモでは:has()
内で相対セレクタを使用しているので、フラグがオンになっている場合でもメッセージを表示させたいと考えます。そのための解決策は:has()
の引数に+ *
のような相対セレクタを記述することです。
1 2 3 4 5 6 |
/* 相対セレクタを含む:has()のサポートが検出された場合にメッセージを非表示にします */ @supports selector(:has(+ *)) { .no-support { display: none; } } |
デモとコード
デモで使用している完全コードは、下記の通りです。この記述で両方のレベルのサポートを検出することができ、またサポートが要求された場合には特定のボックスを表示することもできます。
まずは、メッセージのHTML。
1 2 |
<div class="no-support" data-support="css-has-basic"><p>🚨 Your browser does not support CSS <code>:has()</code>, so this demo will not work correctly.</p></div> <div class="no-support" data-support="css-has-relative"><p>🚨 Your browser does not support relative selectors in CSS <code>:has()</code>, so this demo will not work correctly.</p></div> |
メッセージのスタイルと:has()
の検出方法のCSS。
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 27 28 29 30 31 32 33 |
.no-support, .has-support { margin: 1em 0; padding: 1em; border: 1px solid #ccc; } .no-support { background-color: #ff00002b; display: block; } .has-support { background-color: #00ff002b; display: none; } @supports selector(:has(*)) { .no-support[data-support="css-has-basic"] { display: none; } .has-support[data-support="css-has-basic"] { display: block; } } @supports selector(:has(+ *)) { .no-support[data-support="css-has-relative"] { display: none; } .has-support[data-support="css-has-relative"] { display: block; } } |
終わりに
@supports
を使用して:has()
の機能を検出する場合、セレクタを:has()
に渡す必要があります。引数は*
でもかまいませんが、:has()
内で使用される相対セレクタに依存している場合は、@supports selector(:has(+ *))
を使用してください。これは2023年1月現在相対セレクタのサポートがない:has()
を実験的なサポートをオンにしたFirefoxを除外するために行う必要があります。
sponsors