Hacker NewsがCSSのクラス接頭辞セレクターに注目、だが本当の試練はこれから
Hacker Newsでは、開発者の不満から受け入れられた標準化の方向性へと、2年以上をかけて進んできたCSS提案が取り上げられた。クラス接頭辞セレクターは、.icon-* のような簡潔な構文により、接頭辞を共有する別々のクラストークンを著者が照合できるようにするものだ。
これは小さな利便性に思えるかもしれない。より深い対立点は、ユーティリティフレームワーク、アイコンライブラリ、アプリケーションチームがすでに広く用いている命名パターンを、ブラウザが理解すべきかどうかにある。
現状、著者は関連するクラスをすべて列挙するか、共通のベースクラスを追加するか、脆弱な属性セレクターによる回避策に頼らなければならない。CSS Working Groupは基礎となるユースケースを受け入れたが、受け入れはブラウザサポートを意味しない。テスト、仕様文書、実装作業、相互運用性など、提案と本番Webサイトの間にはなお課題が残っている。
Hacker NewsがCSS提案で実際に見つけたもの
ニュースは、ブラウザが突然ワイルドカードのクラスセレクターを実装したことではない。重要な変化は、CSS Working Groupがこの問題を受け入れたことだ。
Lea Verouは、2024年2月26日に基礎となるCSSWG提案を公開した。彼女は、接頭辞を共有する個別のクラス名を照合する必要性が繰り返し生じると説明した。
このissueは、参加者がユースケース、構文、より広範な属性セレクターの問題を議論する間、オープンのままだった。現在は「Accepted by CSSWG Resolution」ラベルが付き、Selectors Level 5に割り当てられた状態でクローズされている。
このステータスは重要だ。これは、ワーキンググループがCSSでこのユースケースに対応すべきだと合意したことを意味する。暫定的な .prefix-* 記法が安定したWeb標準になったことを意味するわけではない。
このissueには「Needs Testcase (WPT)」ラベルも付いている。WPTはWeb Platform Testsを指し、ブラウザが相互運用可能な挙動を確認するために利用する共有テストスイートだ。
開発セクションには、関連するプルリクエストは記載されていない。公開されているSelectors Level 5ドラフトも、この機能を完成済みでデプロイ可能なセレクターとしてはまだ提示していない。
これらの詳細が実際の出来事を示している。長期にわたる提案が重要な標準化の節目を越えた一方で、実装パイプラインはまだ完了していない。
この提案は、完全な class 属性内の任意のテキストではなく、クラストークンに焦点を当てている。この違いが、その有用性と現行の回避策の不十分さの両方を説明する。
次のマークアップを考えてみよう。
開発者は、icon- で始まるすべてのクラストークンに1つのルールを一致させたいかもしれない。目的とするファミリーには、icon-alert、icon-search、さらに数百の追加アイコンが含まれ得る。
提案されているクラス接頭辞セレクターは、このファミリーを直接表現する。
この例は、本番投入可能な構文ではなく、意図されたモデルを説明するものだ。著者は、仕様、テスト、ブラウザでその挙動が合意されるまで、これをデプロイすべきではない。
既存の属性セレクターは、一見すると非常によく似ている。
しかし、^= は完全な属性値が指定したテキストで始まるかを確認する。各クラストークンを個別に調べるわけではない。
このルールは次の要素に一致する。
次の要素には一致しない。
開発者はしばしば、2つのセレクターで補っている。
1つ目は先頭にある一致トークンを処理し、2つ目はスペースの後にある一致トークンを探す。
このパターンは一般的なHTMLケースでは機能するが、開発者にシリアライズされたテキストについて考えることを求める。クラスセレクターはクラスについて判断すべきだ。
したがって、この提案はドキュメントモデルとセレクター言語の間にある実際の隔たりを対象にしている。HTMLは class をスペースで区切られたトークンの集合として扱う一方、部分文字列セレクターはシリアライズされた属性値を操作する。
提供されたスナップショットでは、Hacker Newsの投稿は6ポイントと1件のコメントを得た。議論は限定的であり、幅広い開発者の合意を示すものではない。
その価値は別のところにある。この投稿は、数年にわたるGitHub issueの中に埋もれかねない標準化判断へ注目を向けた。
ユーティリティフレームワークとアイコンライブラリが圧力を感じる理由
この提案は、1つの概念的なクラスファミリーを表現するために、共有スタイルを重複させたり追加のマークアップを必要としたりするライブラリに圧力をかける。
ユーティリティフレームワークは、pt-6 や space-y-4 のような名前に、プロパティと値の関係を埋め込んでいる。アイコンシステムは fa-* や bi-* のようなファミリーを使用する。
これらの命名システムは、2種類のスタイリングを生む。各クラスには値に固有の宣言が必要である一方、ファミリー全体ではベースラインの宣言を共有することが多い。
たとえばアイコンファミリーには、共通の表示、サイズ、配置、レンダリングのルールが必要になる場合がある。個別のアイコンクラスは、その後に別々のグリフまたは画像参照を提供する。
接頭辞照合がなければ、ライブラリ著者にはいくつかの不完全な選択肢がある。すべてのクラスを列挙する、別のベースクラスを必須にする、または属性文字列全体を操作する方法だ。
列挙では、次のようなセレクターが生まれる。
ビルドツールでこのリストを生成することはできる。生成により入力の手間は減るが、生成されたバイト列や、著者が維持すべき関係までなくなるわけではない。
2つ目の手法は、共通の挙動を個別の値から分離する。
この設計は明示的であり、多くの場合に理にかなっている。ただし、利用者には、1つの可視コンポーネントのために2つのクラスを覚えることを求める。
Bootstrap Iconsは、ベースの bi クラスと特定のアイコンクラスによる、この一般的なパターンに従っている。CSSWG提案は、このようなシステムを、不足しているセレクターが実際の著者の摩擦を生む証拠として用いている。
クラス接頭辞セレクターがあれば、次のマークアップが可能になる。
ファミリーセレクターが共有の挙動を提供し、.icon-alert が固有の宣言を提供できる。
だからといって、単一クラスのマークアップが自動的に優れているわけではない。ベースクラスは意図を伝えやすく、デバッグを簡単にし、過度に広いファミリールールを防げる。
この提案は、著者に別の表現方法を与えるものだ。ライブラリは、明示的なベースクラスと推論された接頭辞ファミリーのどちらが契約に最も適するかを判断できる。
ユーティリティファーストCSSも同様の圧力を生む。pt- のような接頭辞はプロパティカテゴリを表し、接尾辞は値を識別する。
フレームワークはファミリーセレクターを使って、共通のカスタムプロパティ、containmentルール、またはその他のベースライン挙動を確立できる。特定のクラスは個別の値を提供できる。
直接的な削減効果は控えめに見えるかもしれない。より重要なのは構造上の利点であり、スタイルシートがクラス名にすでに埋め込まれているグループ化を表現できるようになる。
このため、この提案は単なるシンタックスシュガーではない。著者が生成リストや冗長なマークアップを取り除けるようになるとき、構文の変更はアーキテクチャ上の変更となる。
ただし、この機能はTailwind、Bootstrap、Sass、PostCSS、ビルド時抽出を置き換えるものではない。これらのツールは、1つのトークン接頭辞の照合よりはるかに広い問題を解決している。
たとえばTailwindは、設定されたユーティリティと検出された利用状況に基づいて宣言を生成する。ネイティブセレクターは、各ユーティリティの値固有の宣言を生成しない。
ブラウザは .pt-* に一致させられるが、すべての接尾辞の意味を推論することはできない。スタイルシートには、サポート対象の名前を有効なプロパティ値に対応付けるルールが依然として必要だ。
したがってクラス接頭辞セレクターが扱うのはグループ化であり、任意のユーティリティ生成ではない。CSSビルドツールを不要にするとする主張は、その範囲を過大評価している。
影響を受けるのはフレームワークの保守者だけではない。アプリケーションチームも、status-*、theme-*、language-*、priority-* のような名前を頻繁に使う。
ドキュメントシステムは、コードブロックに language-javascript や language-python のクラスを出力する場合がある。HTML仕様自体も、コードサンプルに language- の命名規則を推奨している。
その後、シンタックスハイライターは、他のクラスが前に置かれている場合でも言語トークンを識別する必要がある。VerouはこれをPrismにとって実用的な問題として挙げた。
大規模なフロントエンドを保守するチームが気にかけるべき理由は、規則がインフラになるからだ。何千ものテンプレートが命名パターンに依存するようになると、あらゆる回避策の変更が難しくなる。
こうした判断を維持するには、信頼できる社内ドキュメントも必要になる。検索可能なエンジニアリング知識ベースは、セレクターの規則をコンポーネントや移行に関するメモとともに保持できる。
この標準化判断がフレームワークとライブラリの保守者にかけるのは、即時の移行圧力ではなく長期的な圧力だ。接頭辞による関係が意味のある公開契約なのかを判断しなければならない。
この仕組みが解決するのは短い構文だけでなくトークン照合
中心となる仕組みはトークンを認識する接頭辞照合であり、`class` 属性の生テキストを検索することとは根本的に異なる。
CSSにはすでに複数の属性セレクターが含まれている。セレクター仕様では、完全一致の値、空白区切りのトークン、接頭辞、接尾辞、部分文字列のための演算子が定義されている。
各演算子は異なる問いに答える。[class~="button"] は完全な button トークンを見つける一方、[class^="button-"] は属性値全体の先頭を確認する。
CSSに欠けているのは、これらを組み合わせた操作だ。著者は、空白区切りのリストから1つのトークンを選択し、そのトークンが接頭辞で始まるかを検査する必要がある。
元のissueでは、2つの経路が検討された。1つは、.foo-* のように、馴染みのあるクラスセレクターをワイルドカード構文で拡張する方法だ。
もう1つは、~= と ^= の挙動を組み合わせる属性演算子を追加する方法である。提案された形式には ~^=、^~=、^~ が含まれていた。
クラス記法は、CSSの既存のクラスセレクター語彙の中に収まるため読みやすい。ドットで始まるルールは、クラスを対象にしていることを明確に伝える。
組み合わせた属性演算子は、より汎用的になる。スペース区切りの値を含む class 以外の属性にも適用できる可能性がある。
汎用性には独自のコストもある。新しい演算子はCSSの構文解析ルールに適合し、理解しやすく、すでに複数の属性演算子を学んでいる著者を混乱させない必要がある。
ワイルドカードのクラス構文も、見た目を超えた疑問を提起する。仕様はエスケープ、照合境界、大文字・小文字の区別、無効な入力、詳細度を定義しなければならない。
詳細度は、複数のセレクターが一致したときにどの宣言が勝つかを決定する。新しいセレクターには、通常のクラス、属性、疑似クラス、ネストされたルールと並んでも予測可能な挙動が必要だ。
標準化プロセスでは、ブラウザAPIを通じてこのセレクターがどう振る舞うかも決めなければならない。querySelector()、matches()、スタイルシートの構文解析はいずれもセレクター構文を受け取る。
未対応の構文がセレクターリストを無効にする可能性があるため、無効なセレクターの挙動は重要だ。著者には、無関係なルールを誤って失わずにこの機能を使うための、信頼できる方法が必要になる。
機能検出も実用上の論点だ。CSSは、ブラウザがセレクターを認識するかを確認するために @supports selector(...) をサポートしている。
将来のプログレッシブエンハンスメントのパターンは、次のようになるかもしれない。
この例は、最終的な文法が公開されるまでは仮説にとどまる。開発者が安全なフォールバックを書けるようになる前に、構文解析の詳細が重要である理由を示している。
パフォーマンスに関する疑問は慎重に扱うべきだが、憶測にしてはならない。ブラウザはすでに、クラスおよび属性照合のために最適化された仕組みを維持している。
トークンを認識する接頭辞操作が、自動的に遅くなるわけではない。そのコストは、エンジンのインデックス戦略、スタイルシートのパターン、最終的な仕様の選択に左右される。
同様に、この機能がすべてのスタイル再計算で、すべての要素にあるすべてのクラスを、すべてのセレクターのために走査するようブラウザに本質的に強いるわけではない。実装者はインデックスや照合のショートカットを開発できる。
これらの前提を検証できるのは、ブラウザのプロトタイプと Web Platform Tests だけだ。標準への採択は方向性を示すものであり、性能の証拠ではない。
この提案で最も説得力があるのは、意味論との整合性だ。開発者は class="card icon-alert muted" を、空白を含む1つの文字列ではなく、3つのトークンとして捉えている。
通常の .icon-alert も、すでにそのトークンモデルを用いている。これをクラスファミリーへ拡張すれば、メンタルモデルの一貫性を保てる。
この意味論的な適合性は、レビューのしやすさも高める。.icon-* は意図された名前空間やファミリーを即座に示す一方、属性を組み合わせた回避策では、より注意深い確認が必要になる。
ただし、簡潔な構文は広いマッチ対象を覆い隠しうる。単一のファミリールールが、アプリケーション全体で短い接頭辞から始まるすべてのクラスに影響する可能性がある。
それはパーサーの欠陥ではない。広範な型セレクターや曖昧な命名のカスタムプロパティと同様、スタイルシートのガバナンスに関する問題だ。
この仕組みは CSS により洗練されたプリミティブを与える。しかし、チームがそのプリミティブを慎重に使うかどうかまでは決めない。
本当のリスクはワイルドカード文字ではなく、漏れ出す CSS にある
接頭辞セレクターは壊れやすいコードを減らせる一方で、意図しない結合を起こしやすくする。そのため、導入後は命名規律がより重要になる。
懐疑的な反応はわかりやすい。セレクターが無制限のファミリーにマッチするなら、将来追加されるクラスが、その作者の想定しなかったスタイルを継承する可能性がある。
たとえば、デザインシステムが次のルールを定義しているとする。
数か月後、別のチームが分析やアプリケーション状態のために card-payment-error を追加する。このクラスは別の目的を持つにもかかわらず、スタイリングファミリーに加わってしまう。
ベースクラスなら、この曖昧さを避けられる。
マークアップは、その要素がカードであることを明示する。個別のクラスは、別の意味を追加する。
接頭辞マッチングは、スペルから所属を推測する。簡潔にはなるが、命名規則を実行可能な関係へと変えてしまう。
この違いは、プログラミングにおける構造的型付けに似ている。作者が明示的に所属を宣言したからではなく、期待される形状を持つために名前が適格となる。
これは管理された名前空間の中では有効に機能しうる。短い接頭辞が製品、レガシーモジュール、サードパーティ製ウィジェット、独立して管理されるチームにまたがる場合は、リスクになる。
この懸念は、リンク先の投稿をめぐる初期の公開反応にも表れていた。ある Reddit のコメント投稿者は、この不安を「leaky css」の機会が増えることだと要約した。
この反応は標準への反証ではない。これは、仕様がアプリケーションチームのために解決できないトレードオフを示している。
ライブラリは、接頭辞ファミリーを安定した API として文書化する必要がある。.icon-* に共通の振る舞いを持たせた時点で、icon- で始まる新しいクラスはすべてその契約に加わる。
リファクタリングも局所的ではなくなる。1つのクラス名を変更すると、その固有ルールだけでなく、それにマッチするすべてのワイルドカードファミリールールにも影響しうる。
開発者ツールは、これらの関係を明確に示す必要がある。インスペクターは .icon-alert が完全一致のセレクターだけでなく、ファミリーセレクターにもマッチしたことを表示すべきだ。
検索ツール、リンター、コードインテリジェンスにも同様の更新が必要になるかもしれない。セレクターが固定名ではなく拡張し続ける集合を表す場合、静的解析はより難しくなる。
この提案は、作者がクラス名の中にさらに多くのデータを符号化することを促す可能性もある。このパターンはすでに一般的だが、ネイティブサポートにより魅力が増すかもしれない。
CSSWG の参加者は、一部のキー・バリュー関係を代わりに data-* 属性に置くべきではないかと疑問を呈した。たとえば、data-pt="6" ではプロパティと値が構造的に分離される。
この表現はより明示的だが、その分だけ冗長でもある。既存のフレームワーク規約やクラスベースのツールと統合できない場合もある。
どちらのモデルも、あらゆる場面で優れているわけではない。クラスはグループ化やスタイリングフックに適しており、データ属性は状態やアプリケーションデータを表現できる。
クラス接頭辞セレクターを、あらゆる状態を圧縮したクラス名へ移す口実にすべきではない。ネイティブマッチングによって、意味論的設計の選択が不要になるわけではない。
移行期間には互換性のリスクもある。作者は、標準への採択が構文のブラウザ横断での動作を意味すると考えてはならない。
フォールバックなしで未認識のセレクターを使うと、意図したスタイルが黙って失われる可能性がある。本番導入は、文書化されたサポートと相互運用性の証拠が整うまで待つべきだ。
開発者は、安定化前の例示構文を安易にコピーすることも避けるべきだ。Issue では .foo-* が提案されているが、ワーキンググループは仕様の編集中に文法を改訂できる。
あるエンジンが機能を実装した後でも、チームは他のエンジンがエッジケースを同じようにマッチさせるか確認すべきだ。CSS の歴史には、信頼できる相互運用性に達するまで何年もかかった機能がある。
Hacker News 的な切り口は、こうした段階を1つの見出しに圧縮しがちだ。「未来の CSS」という表現は妥当だが、「今すぐ使える新しい CSS」は誤解を招く。
保守的なアプリケーションチームは、その構造が重要な意味を伝える場合、明示的なベースクラスを引き続き使うべきだ。クラスファミリーが有限なら、生成されたセレクターリストも依然として有効である。
現在の属性ベースの回避策も、管理されたマークアップでは利用できる。作者は、それが直接的なトークン意味論ではなく、空白と属性のシリアライズに依存していることを覚えておく必要がある。
すべてのコードベースに当てはまる移行ルールはない。この機能は利用可能な言語を改善するが、それがアプリケーションを改善するかは依然としてアーキテクチャ次第だ。
クラス接頭辞セレクターが実装される前に必要なこと
採択されたアイデアが信頼できる CSS になるかは、仕様テキスト、共有テスト、相互運用可能なブラウザ実装という3つのシグナルによって決まる。
最初のシグナルは、Selectors Level 5 への具体的な編集だ。ドラフトには、リンクされた GitHub の決議だけでなく、規範的な文法とマッチングルールが必要になる。
規範的テキストは、準拠実装が何をしなければならないかを定義する。セレクター形式、トークン境界、エスケープ、詳細度、セレクター API における挙動を確定させるべきだ。
その編集により、.prefix-*、あるいは後継構文が実装へ向かっているという見方は強まる。別の文法になれば、現在の例に基づく前提は弱まる。
2つ目のシグナルは、Web Platform Tests における進展だ。Issue のテストラベルは、ワーキンググループが実行可能なカバレッジを期待していることを示している。
テストには、属性内の異なる位置にあるクラス、複数のマッチするトークン、エスケープ文字、大文字・小文字の挙動、無効な構文を含めるべきだ。
JavaScript のセレクター API も対象にする必要がある。スタイルシートと querySelector() が同じ文法について一致しなければ、CSS 機能は不完全なままだ。
幅広いテストスイートは、ブラウザチームが1つの解釈を共有しているという確信を強める。テストが欠けている、あるいは繰り返し変更される場合は、未解決の設計詳細を示すだろう。
3つ目のシグナルは、ブラウザエンジンをまたぐ実装だ。1つの実験的ビルドは実現可能性を示せるが、Web 互換性を確立することはできない。
開発者は Chromium、Gecko、WebKit の Issue トラッカーで実装作業を注視すべきだ。リリースノートと互換性データは、ソーシャル上の注目より重要になる。
エンジン横断で利用可能になれば、この提案のアーキテクチャ上の価値は強まる。長期にわたる単一エンジンのみのサポートでは、プログレッシブエンハンスメントの領域に留まる。
フレームワークの実験は、この3つの技術的シグナルに続くものではあるが、追加の導入手掛かりとなる。メンテナーは、ファミリーセレクターが出力を減らすか、公開マークアップを簡素化するかを検証できる。
有用な測定項目には、生成されるセレクターのサイズ、ビルドの複雑さ、移行コスト、デバッグの明瞭さがある。こうした結果は、1つのセレクター内の文字数を数えることより重要だ。
この機能の成功にフレームワークの採用は必須ではない。より小さなデザインシステム、アイコンライブラリ、シンタックスハイライターも独立して恩恵を受けられる。
HTML の言語クラス例は、特に有益なものになるかもしれない。これは、トークンを意識したマッチングが、ユーティリティファーストなスタイリングの外側にある確立済みの慣習を改善するかを試すものだ。
開発者は、この提案が任意のパターンマッチングを生むと期待すべきではない。議論の対象は個々のクラストークン上の接頭辞であり、CSS 内の正規表現ではない。
また、接尾辞および部分文字列のワイルドカードが同時に導入されると想定すべきでもない。より広範なワイルドカード設計には、別個の正当化と仕様策定が必要になる。
現時点では、本番コードにおいてこのセレクターを、開発中の採択済み方向性として扱うべきだ。チームは、未サポートの構文を出荷せずに命名規則を評価できる。
その準備にも価値はある。接頭辞が意図的なファミリーなのか、偶発的な類似なのか、あるいはその混在なのかを監査しよう。
どの接頭辞が公開スタイリング契約として機能しているかを文書化する。推論によって隠されてしまう意味を、ベースクラスが伝えている箇所を特定する。
現在の属性ベースの回避策を、クラスの並び順変更や予期しない空白に対してテストする。多くのコードベースでは、いわゆる接頭辞マッチングがトークン位置に依存していることがわかるだろう。
ネイティブサポートが到来したら、移行は狭く、明確な所有者がいる名前空間から始めるべきだ。アイコンファミリーや生成された言語識別子は、汎用的な接頭辞より明確な境界を提供する。
サポートがまだ不均一な間は、機能検出を使う。対象ユーザーのブラウザが一貫して動作することを互換性データが示すまで、フォールバックを維持する。
ブラウザのプロトタイプが登場すれば、Hacker News はおそらくこのセレクターを再び取り上げるだろう。その際の議論は、新奇性だけでなく、テスト、挙動、相互運用性に焦点を当てるべきだ。
この提案の重要性は、現代の CSS に繰り返し現れるパターンにある。ブラウザは、かつて作者がプリプロセッサ、生成コード、壊れやすいセレクターの工夫で近似していた機能を取り込みつつある。
この変更は、ネスト、コンテナクエリ、:has() より範囲が狭い。その小さなスコープは、問題と意図された挙動が非常に具体的であるため、利点になりうる。
残る作業も具体的だ。編集者はルールを書き、テスト作成者はエッジケースを捉え、ブラウザチームは同じ結果を実装しなければならない。
これらの段階が揃えば、開発者は複数の CSS クラスを接頭辞で直接ターゲットにする手段を得る。食い違えば、明示的なベースクラスがより安全な契約であり続ける。
今日取るべき行動は、即時の置き換えではなく観察だ。提案を確認し、クラス名前空間を調べ、トークンを意識したマッチングが実際の保守コストを減らせる箇所を特定しよう。
次に、この3つのシグナルを順に見守る。規範的な仕様テキスト、包括的なテスト、複数のブラウザ実装だ。あなた自身のコードベースでは、どの接頭辞ファミリーが最も明確な相互運用性テストを提供するだろうか。



