特異性

CSS ポッドキャスト - 003: 限定性

次の HTML と CSS を使用しているとします。

<button class="branding">Hello, Specificity!</button>
.branding {
  color: blue;
}

button {
  color: red;
}

ここでは、同じ要素を対象とする 2 つのルールがあります。 各ルールには、ボタンの色を設定する宣言が含まれています。1 つはボタンを赤色にしようとし、もう 1 つはボタンを青色にしようとしています。 どの宣言が要素に適用されますか?

CSS の限定性アルゴリズムを理解することは、CSS が競合する宣言をどのように決定するかを理解するうえで重要です。

限定性は、カスケードの個別の段階の 1 つです。 カスケードについては、前回のモジュールで説明しました。

限定性のスコアリング

オリジン内の各セレクタルールにはスコアが付けられます。 限定性は合計スコアと考えることができ、各セレクタタイプはそのスコアにポイントを加算します。 限定性が最も高いルールの宣言が優先されます。

実際のプロジェクトで限定性を使用する場合、バランスを取るには、適用する CSS ルールが実際に適用されるようにしつつ、複雑さを防ぐためにスコアを低く保つ必要があります。 限定性は、可能な限り高くするのではなく、必要なだけ高くする必要があります。 今後、本当に重要な CSS を適用する必要が生じる可能性があります。 限定性を最大限に高めると、その作業が難しくなります。

限定性は 10 進数ではなく、ABC の 3 つのコンポーネントで構成される 3 つ組です。

  • A: ID のような限定性
  • B: クラスのような限定性
  • C: 要素のような限定性

多くの場合、(A,B,C) 表記が使用されます。例: (1,0,2)。 代替の A-B-C 表記もよく使用されます。

特異性の 3 つのコンポーネント(A、B、C)を示す図。各コンポーネントについて、図には、そのコンポーネントが表すものと、それに影響するセレクタの例が示されています。
さまざまなセレクタが限定性のどのコンポーネントに影響するかを示す図。

限定性を比較する方法

限定性を比較するには、3 つのコンポーネントを順番に比較します。A の値が大きいほど限定性が高くなります。2 つの A の値が同じ場合は、B の値が大きいほど限定性が高くなります。2 つの B の値も同じ場合は、C の値が大きいほど限定性が高くなります。すべての値が同じ場合、2 つの限定性は等しくなります。

たとえば、(1,0,0)A の値(1)は (0,4,3)A の値(0)よりも大きいため、(1,0,0)(0,4,3) よりも限定性が高いと見なされます。

セレクタは限定性に影響する

限定性の 3 つ組の各部分は 0 の値で始まるため、デフォルトの限定性は (0,0,0) です。セレクタの各部分は限定性を高めます。セレクタのタイプに応じて、ABC のいずれかの値が増加します。

ユニバーサル セレクタ

ユニバーサル セレクタ(`*`)は**限定性を追加しない** ため、値は初期限定性の ` (0,0,0)` のままになります。*(0,0,0)

* {
  color: red;
}

要素セレクタまたは疑似要素セレクタ

要素(タイプ)セレクタまたは疑似要素セレクタは、要素のような限定性 を追加します。これにより、C コンポーネントが 1 ずつ増加します。

次の例の全体的な限定性は (0,0,1) です。

タイプセレクタ

div {
  color: red;
}

疑似要素セレクタ

::selection {
  color: red;
}

クラス、疑似クラス、または属性セレクタ

クラス、疑似クラス、または属性セレクタは、クラスのような限定性 を追加します。これにより、B コンポーネントが 1 ずつ増加します。

次の例の限定性は (0,1,0) です。

クラスセレクタ

.my-class {
  color: red;
}

疑似クラスセレクタ

:hover {
  color: red;
}

属性セレクタ

[href='#'] {
  color: red;
}

ID セレクタ

[ID] セレクタは、ID セレクタ(#myID)を使用し、属性セレクタ([id="myID"])を使用しない限り、A コンポーネントを 1 ずつ増加させるID のような限定性 を追加します。

次の例の限定性は (1,0,0) です。

#myID {
  color: red;
}

その他のセレクタ

CSS には多くのセレクタがあります。限定性を追加するセレクタもあれば、追加しないセレクタもあります。 たとえば、:not() 疑似クラス 自体は、限定性の計算に何も追加しません。

:not() 疑似クラスの限定性は、セレクタのカンマ区切りの引数で最も限定的なセレクタの限定性に置き換えられます。これは、:not(:is(argument)) と記述した場合と同じ限定性を提供します。

div:not(.my-class) {
  color: red;
}

:is() 疑似クラス 自体も、限定性の計算に追加されません。:not() と同様に、最も限定的な引数の限定性が使用されます。

:is(h1, h2, h3) {
  color: blue;
}

このサンプルには 1 種類のセレクタ(type)しかないため、限定性は (0,0,1) です。

id を追加すると、限定性は (1,0,0) に増加します。

:is(h1, h2, h3, #my-heading) {
  color: blue;
}

:where() 疑似クラス は異なります。引数の限定性に関係なく、常に (0,0,0) の限定性になります。

:where(h1, h2, h3, #my-heading) {
  color: blue;
}

:where() を使用して適用される限定性の低いスタイルを使用すると、スタイルシートで後から基本セレクタを使用してこれらのスタイルをオーバーライドできます。

:where(#my-content) {
   color: red;
}

p {
   color: blue;
}

:where() の引数リストに id が含まれていても、限定性は (0, 0, 0) のままなので、基本的な p セレクタがオーバーライドされ、テキストは blue になります。

理解度をチェックしましょう

限定性のスコアリングに関する知識をテストする

a[href="#"] の限定性は何ですか?

(0,0,1)
a(0,0,1) の値ですが、[href="#"](0,1,0) の値です。
(0,1,0)
もう一度考えてみましょう。a(0,0,1) の値ですが、[href="#"](0,1,0) の値です。
(0,1,1)
a(0,0,1) の値で、[href="#"](0,1,0) の値です。合計の限定性は (0,1,1) になります。

限定性に影響しない要因

限定性に影響する次の要因については、一般的な誤解があります。

インラインのスタイル属性

要素の style 属性に直接適用される CSS は、 限定性の前に評価されるカスケードの別のステップであるため、 限定性に影響しません。

<div style="color: red"></div>

スタイルシート内からこの宣言をオーバーライドするには、 カスケードの前のステップで宣言を優先させる必要があります

たとえば、!important を追加して、 作成者の !important オリジンの一部にすることができます。

!important 宣言

CSS 宣言の末尾にある !important は限定性に影響しません が、宣言を別の オリジン作成者の !important)に配置します。

次の例では、.my-class の限定性は、!important 宣言が優先されるかどうかには関係ありません。

.my-class {
  color: red !important;
  color: white;
}

2 つの宣言が !important の場合、カスケードのオリジン ステップでまだ勝者を決定できないため、限定性が再び有効になります。

.branding {
  color: blue !important;
}

button {
  color: red !important;
}

コンテキスト内の限定性

複雑なセレクタまたは複合セレクタを使用すると、セレクタの各部分が限定性に加算されます。 次の HTML の例を考えてみましょう。

<a class="my-class another-class" href="#">A link</a>

このリンクには 2 つのクラスがあります。 次の CSS のルールには 限定性 (0,0,1)があります。

a {
  color: red;
}

セレクタでクラスの 1 つを参照すると、 限定性 (0,1,1)が設定されます。

a.my-class {
  color: green;
}

セレクタに別のクラスを追加すると、 限定性 (0,2,1)が設定されます。

a.my-class.another-class {
  color: rebeccapurple;
}

セレクタに href 属性を追加すると、 限定性 (0,3,1) が設定されます。

a.my-class.another-class[href] {
  color: goldenrod;
}

最後に、これらすべてに :hover 疑似クラスを追加すると、 セレクタの限定性は になります(0,4,1)

a.my-class.another-class[href]:hover {
  color: lightgrey;
}

理解度をチェックしましょう

限定性のスコアリングに関する知識をテストする

次のセレクタのうち、限定性が (0,2,1) のセレクタはどれですか?

article > section
要素は要素のような限定性(`C` コンポーネント)を追加します。セレクタには 2 つの要素があるため、限定性は (0,0,2) になります。
article.card.dark
要素は要素のような限定性(`C` コンポーネント)を追加し、クラスはクラスのような限定性(`B` コンポーネント)を追加します。2 つのクラスと 1 つの要素があるため、このセレクタの限定性は (0,2,1) になります。
article:hover a[href]
要素は要素のような限定性(`C` コンポーネント)を追加し、疑似クラスと属性はクラスのような限定性(`B` コンポーネント)を追加します。要素セレクタが 2 つ(2 × (0,0,1))、属性セレクタが 1 つ((0,1,0))、クラスセレクタが 1 つ((0,1,0))あります。このセレクタの合計限定性は (0,2,2) になります。

限定性を実用的に高める

次のような CSS があるとします。

.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

次のような HTML があります。

<button class="my-button" onclick="alert('hello')">Click me</button>

2 番目のセレクタの限定性が (0,1,1)であるため、ボタンの背景はグレーになります。これは、タイプセレクタ(button)が 1 つ((0,0,1) )と属性セレクタ([onclick])が 1 つ((0,1,0) )あるためです。

前のルール(.my-button)は、クラスセレクタが 1 つしかないため、(0,1,0) になります。これは、(0,1,1) よりも限定性が低くなります。

このルールを強化する場合は、次のようにクラスセレクタを繰り返します。

.my-button.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

これで、新しいセレクタの限定性が (0,2,0) になるため、ボタンの背景は青色になります。

限定性が同じ場合は、カスケードの次のステップにフォールバックする

ボタンの例を続けて、CSS を次のように変更します。

.my-button {
  background: blue;
}

[onclick] {
  background: grey;
}

両方のセレクタの限定性が (0,1,0) で同じ であるため、ボタンの背景はグレーになります。

ソースの順序でルールを切り替えると、ボタンは青色になります。

[onclick] {
  background: grey;
}

.my-button {
  background: blue;
}

これは、両方のセレクタの限定性が同じであるためです。 この場合、カスケードは表示順序のステップにフォールバックします。

リソース