乗りこなせ! モダンフロントエンド

Cascade Sorting Order/CSSの適用順序を学び直す
[CSS Modern Features no.6]

こんにちは! サイボウズ フロントエンドエキスパートチームの麦島です。

CSS Modern Features、最終回となる今回のテーマはCascade Sorting Orderです。

CSS適用順序を構成する仕様の増加

突然ですが、⁠CSSの適用順序」と言われると、どこまで説明できるでしょうか?

次のようなものは広く知られており、イメージしやすいかもしれません。

  • 詳細度がより高いほうが優先される
  • 同じ詳細度の場合は、後に記述された宣言が優先される
  • style属性による宣言は詳細度よりも優先される
  • !importantを付与すると、詳細度やstyle属性より優先される

しかし、昨今では適用順序に関連するCSSの機能は増えています。

たとえば、開発時に次のような問いが発生する可能性が考えられ、従来の知識だけではこれらに回答することは難しいでしょう。

  • Cascade LayersとScoped Stylesを併用した場合にどちらが優先されるか
  • Cascade Layersを利用した場合と利用しない場合でどちらが優先されるか
  • style属性と組み合わせた場合の優先順位はどうなるか
  • 詳細度が同じ場合にScoped Stylesはどう処理されるか
  • !importantを付与した場合の優先順位はどうなるか

これらすべてを把握していないとすぐに開発できなくなる、ということはないと思われますが、ライブラリやフレームワークがアップデートによりモダンな機能を導入するケースもあり、知らず知らずの間に新しい機能を利用することもありえます。そういった場合に適用順序を把握していないと、期待するスタイルを実現できなかったり、思わぬ不具合につながる可能性もあるでしょう。

従来の知識に加えて、本連載でここまで取り上げた機能も含めたCSSの適用順序に関する仕様をいま一度再確認してみましょう。

Cascade Sorting Order

CSSの適用順序はCascade Sorting Orderと呼ばれる仕様に基づきます。一つの要素に対して2つ以上のCSS宣言があったときに、どれを優先して適用するかはこのルールに従って判断されます。

現在勧告されているCascade Sorting Orderに関する仕様は、W3CのCSS Cascading and Inheritance Level 4で定義されています。CSSの仕様は更新のたびにLevelと呼ばれる数値が上がっていき、本連載でも紹介したCascade LayersやScoped Stylesといった機能をすべて含めた仕様はLevel 6にて策定が進められています。

本記事ではLevel 6の内容をベースに解説します(本記事の掲載時点では、Level 6の仕様はWorking Draftであり、今後内容が変更される可能性がある点に注意してください⁠⁠。

Cascade Sorting Orderの構成要素

Cascade Sorting Orderでは、次の基準に沿って、上から順に判断して適用順序を並び替える仕様となっています。

  1. Origin and Importance/CSSの起源と!importantの付与
  2. Context/Shadow DOM内のスタイル
  3. The Style Attribute/style属性での宣言
  4. Layers/Cascade Layersの順序
  5. Specificity/詳細度
  6. Scope Proximity/スコープの近接性
  7. Order of Appearance/宣言された順序

あるスタイルが2箇所で宣言されていた場合の適用順序の判定を例に考えてみると、まずはOrigin and Importanceがチェックされ、Origin and Importance内で優劣がつかない場合には、次にContextをチェックします。これをどこかで優劣がつくまで繰り返し、いずれでも判断がつかない場合には最終的にOrder of Appearanceに従い、より後に宣言されたスタイルが優先される、といったイメージです。

従来CSSの適用順序といえば詳細度がピックアップされるケースが多かったように思います。しかし、Cascade Sorting Order全体を見てみると、詳細度は適用順序を決める中での一部分でしかなく、詳細度以外にも多くの要素が関わっていることがわかります。

以降は、Cascade Sorting Orderに定義される個々の要素について、内容を確認してみましょう。

Origin and Importance/CSS の起源と!importantの付与

Cascade Sorting Orderの先頭に位置し、最も優先して判断されるのがOrigin and Importanceです。名前の通り、OriginとImportanceの2つの概念が含まれるため、それぞれ確認してみましょう。

Origin/CSSの起源⁠定義元

CSSには、その定義がどこから来たものか起源を表すOrigin(オリジン)と呼ばれる概念があり、すべてのCSSはいずれかのOriginに属します。Originの中でも特に把握しておきたいのが、Author Origin・User Origin・User-Agent Originの3つです(厳密にはアニメーションなどに関係するAnimation OriginとTransition Originも存在しますが、この説明については後述します⁠⁠。

それぞれ次のように分類されます。

  • Author Origin: ページ作成者が提供するもの。普段我々が書くCSSはすべてここに属します。
  • User Origin: ブラウザ利用者が独自で設定したスタイル。ブラウザの拡張機能などで設定されます。
  • User-Agent Origin: ブラウザがデフォルトで提供するスタイル。

ここで重要なのが、Origin間の優先順位もこの順番と同じで次のようになる点です。

  1. Author Origin
  2. User Origin
  3. User-Agent Origin

これを実感できる例としては、ブラウザスタイルの上書きが挙げられます。次のような無効化されたボタンを考えてみましょう。

<button disabled>ボタン</button>

Google Chromeで確認した場合、User-Agent Originに属するブラウザ標準のスタイルにより、グレーアウトされて表示されます。

図1 無効化されたボタンのブラウザ標準での表示

このスタイルは、ブラウザ側で次のように定義されています[1]

button:disabled {
  background-color: light-dark(rgba(239, 239, 239, 0.3), rgba(19, 1, 1, 0.3));
  border-color: light-dark(rgba(118, 118, 118, 0.3), rgba(195, 195, 195, 0.3));
  color: light-dark(rgba(16, 16, 16, 0.3), rgba(255, 255, 255, 0.3));
}

ここで、buttonに対して次のようなスタイルを独自で定義してみます。

button {
  background-color: black;
  color: white;
}

実際に見た目を確認すると、独自で定義したスタイルが優先され、ブラウザ標準のスタイルが上書きされます。

図2 独自のスタイルを足した後の無効化されたボタンの表示

普段CSSを書いていれば、このような挙動は当たり前のように感じるかもしれません。

しかし、よく考えてみると、ブラウザ側のCSSはbutton:disabledと宣言されており、これは詳細度で表すと0-1-1です。一方、独自で定義したスタイルはbuttonのみを対象に宣言しているため詳細度は0-0-1となり、ブラウザ側のスタイルよりも詳細度が低く、詳細度だけで比較した場合ではスタイルを上書きすることはできないはずです。それでも確実に上書きできるのは、Cascade Sorting OrderにおいてSpecificity(詳細度)よりもOrigin and Importanceのほうが先に判定され、その上でOrigin間の優先順位で上回ることができるためです。

Importance/!importantの有無

Origin and ImportanceのうちImportanceに該当するのが!important付与の有無です。

!importantについては「付与すれば問答無用で優先されるもの」といった認識の方もいるかもしれません。なぜ!importantを付与すると優先されるかを掘り下げてみると、!importantが該当するOrigin and Importanceの判定がCascade Sorting Orderの中で最上位に位置するから、ということがわかります。

これを把握していれば、たとえば「Cascade Layersにおいて優先順位が低いレイヤーでも!importantが付与されたスタイルは優先されるか?」という問いにも答えられます。以下が、実際の実行例です。

/* レイヤーの優先順位は layer2 → layer1 */
@layer layer1 {
  .text-a {
    color: red;
  }
  .text-b {
    color: red !important;
  }
}
@layer layer2 {
  .text-a {
    color: blue;
  }
  .text-b {
    color: blue;
  }
}
<div class="text-a">テキスト</div>
<div class="text-b">テキスト</div>
図3 Cascade Layersと
!importantを組み合わせた場合の表示

!importantが付与されているスタイルは、レイヤーの優先順位が下回っていても適用されていることがわかります。これも、Cascade Sorting Orderの中で、Origin and Importanceの判定がLayersよりも上に位置するから、と考えると納得の行く挙動ですね。

なお、!importantが付与されたスタイル同士の適用順序においては、OriginやCascade Layersなどによって少し特殊な動作をします。これについては本記事の後半で解説しています。

Context/Shadow DOM内のスタイル

Origin and Importanceで判断がつかなかった場合、次はContextが判定されます。

Contextを理解するためには、Shadow DOMでのスタイル定義について知る必要があります。

Shadow DOMはWeb Componentsを構成する要素のひとつで、DOMツリーをメインのDOMツリーとは切り離してカプセル化します。このとき、CSSについても完全に分離されます。

次の例では、Shadow DOMの内外でスタイルを定義していますが、それぞれ互いに干渉していないことがわかります。

div {
  color: red !important;
}
<my-element>
  <template shadowrootmode="closed">
    <style>
      div {
        color: blue;
      }
    </style>
    <div>Shadow DOM TEXT</div>
  </template>
</my-element>

<div>DOM TEXT</div>
図4 Shadow DOMでスタイルが閉じられている表示例

このとき、Shadow DOMがアタッチされている要素はShadow Hostと呼ばれ、通常の要素と同じようにスタイリングが可能です。次の例では、テキストを表示するだけのShadow DOMを持つカスタム要素に対して、ボーダーや余白を設定しています。

my-element {
  display: inline-block;
  border: 1px solid black;
  padding: 8px;
}
<my-element>
  <template shadowrootmode="closed">
    <div>Shadow DOM TEXT</div>
  </template>
</my-element>

しかし、Shadow DOM側で「デフォルトのスタイルを定義したい」というケースもありえるでしょう。そういったケースでは、Shadow DOM内でのスタイリング時に:host擬似クラスを利用します。

先ほどと同じスタイルを:host擬似クラスを利用して再現すると次のようになります。

<my-element>
  <template shadowrootmode="closed">
    <style>
      :host {
        display: inline-block;
        border: 1px solid black;
        padding: 8px;
      }
    </style>
    <div>Shadow DOM TEXT</div>
  </template>
</my-element>
図5 Shadow Hostへのスタイリング例

Shadow Hostに対するスタイル指定の方法を2パターン紹介しましたが、ここで「カスタム要素への直接のスタイル指定と:host擬似クラスのスタイル指定が両方存在していた場合、どちらが優先されるか?」という疑問が生じます。前置きが長くなりましたが、このどちらで定義されているかがCascade Sorting OrderにおけるContextに該当します。

Contextの比較が生じた場合、通常では外側からの宣言が優先されます。つまり、:host擬似クラスの指定よりも、外部からのスタイル指定が優先されます。

次の例を見てみると、外部からのスタイルが適用されていることがわかります。

my-element {
  display: inline-block;
  border: 5px dashed blue;
  padding: 16px;
}
<template shadowrootmode="closed">
  <style>
    :host {
      display: inline-block;
      border: 1px solid black;
      padding: 8px;
    }
  </style>
  <div>Shadow DOM TEXT</div>
</template>
図6 Shadow Hostへのスタイル指定で外部からのスタイルが優先される例

:hostではデフォルトのスタイルを定義しておき、利用側で柔軟にカスタマイズすることができる、と理解しておくとよいでしょう。

The Style Attribute/style属性での宣言

続いて判定されるのがThe Style Attribute = style属性での宣言です。

<!-- style 属性でのスタイル宣言 -->
<div style="color: red;">テキスト</div>

style属性自体については従来から存在するため解説を省きますが、Cascade Layersよりも優先される点は覚えておくと良いでしょう。

なお余談ですが、仕様のLevel 4以前ではCascade Sorting Order上にThe Style Attributeという項目はなく、代わりにSpecificity(詳細度)の中で「style属性での宣言はどのセレクタよりも高い詳細度を持つとみなされる」といった旨の記述がありました[2]

しかし、Level 5以降においてstyle属性と詳細度の間に位置する形でCascade Layersが登場したことで、従来の形で仕様を記述することは不可能となりました。結果として、Cascade Sorting Order内におけるstyle属性に関する仕様はThe Style Attributeとして独立して定義されるようになりました[3]

Layers/Cascade Layersの順序

The Style Attribute(style属性)とSpecificity(詳細度)の間に位置するのが、Layers = Cascade Layersです。

Cascade Layersそのものについては、本連載のCascade Layers/レイヤーによる優先順位の制御もあわせてチェックしてみてください。

より後に宣言されたレイヤーが優先される

Cascade Layersで覚えておきたいポイントは次の2点です。

  • より後に宣言されたレイヤーが優先される
  • レイヤーに属さないスタイルは、明示的にレイヤーに含めたスタイルより優先される

レイヤーは宣言順が重要で、より後に宣言されたレイヤーのほうが優先されます。Cascade Sorting OrderにおいてLayersはSpecificity(詳細度)よりも上に位置するため、詳細度が下回っていたとしても、レイヤーの優先順位が高ければそちらが適用されます。

また、レイヤーに含めずに宣言したスタイルに関しては、すべて「暗黙のレイヤー」と呼ばれるレイヤーに属します。暗黙のレイヤーは最も後に宣言されたレイヤーとみなされるため、結果として、明示的に宣言したレイヤーのスタイルよりも優先されます。

次の例の場合、.textクラスが付与された要素のカラーは"black"となります。

@layer layer1, layer2, layer3;

/* 暗黙の最終レイヤーに属するため最優先となる */
.text {
  color: black;
}

/* layer3 → layer2 → layer1 の順で優先される */
@layer layer1 {
  .text {
    color: red;
  }
}
@layer layer2 {
  .text {
    color: blue;
  }
}
@layer layer3 {
  .text {
    color: green;
  }
}

サブレイヤーを含めた適用順序

Cascade Layerでは、レイヤー配下にレイヤーを含めるサブレイヤーを利用でき、これも適用順序に関与します。サブレイヤーは親レイヤーごとにグループ化された中で順序が判断されますが、通常のレイヤーと同様、こちらもより後に宣言されたほうが優先されます。

また、⁠親レイヤーに含まれるがサブレイヤーに含まれないスタイル」については、サブレイヤーよりも優先されます。これは、通常のレイヤーにおける暗黙のレイヤーのように、暗黙のサブレイヤーに定義され、最後に宣言されたサブレイヤーであるとみなされるためです。

次のスタイルで考えてみましょう。

@layer parent1 {
  .text {
    color: black;
  }

  @layer sub1 {
    .text {
      color: red;
    }
  }
  @layer sub2 {
    .text {
      color: blue;
    }
  }
}

@layer parent2 {
  .text {
    color: gray;
  }

  @layer sub1 {
    .text {
      color: yellow;
    }
  }
  @layer sub2 {
    .text {
      color: green;
    }
  }
}

この場合、レイヤーの優先順位は次の通りとなり、.textクラスが付与された要素のカラーは"gray"となります。

  1. 暗黙のレイヤー(今回の例ではスタイルは未定義)
  2. parent2(後に宣言された親レイヤ内の暗黙のサブレイヤー)
  3. parent2.sub2(後に宣言された親レイヤ内の最後のレイヤー)
  4. parent2.sub1(後に宣言された親レイヤ内の最初のレイヤー)
  5. parent1(先に宣言された親レイヤ内の暗黙のサブレイヤー)
  6. parent1.sub2(先に宣言された親レイヤ内の最後のレイヤー)
  7. parent1.sub1(先に宣言された親レイヤ内の最初のレイヤー)

なお、この適用順序はGoogle ChromeでのDevToolsでも確認できます(数字が大きいほうがより優先されるレイヤーです⁠⁠。

図7 Cascade Layersの適用順序をDevToolsで確認した際の表示例

Specificity/詳細度

ここまでで適用順序が確定しなかった場合、いよいよSpecificity(詳細度)で判定されます[4]

CSSセレクタに含まれる内容から重み付けが行われ、詳細度が高いものから順に優先度も高くなります。

/** 詳細度 1-0-0(最も詳細度が高い) */
#id {
  color: red;
}

/** 詳細度 0-1-0(2番目に詳細度が高い) */
.class {
  color: blue;
}

/** 詳細度 0-0-1(最も詳細度が低い) */
div {
  color: green;
}

仮に2つのCSS定義で優先度を判断するケースをCascade Sorting Order全体で考えてみると、詳細度を用いた比較が行われるまでには、ここまでに紹介した内容から次の判断がされていることになります。

  • ともに!importantが付与されている、あるいはともに付与されていない
  • 宣言されているOriginが同じである
  • Shadow DOMを考慮した宣言コンテキストが同じである
  • ともにstyle属性での宣言である、あるいはともにstyle属性での宣言ではない
  • Cascade Layersにおいて宣言が属するレイヤーが同一である

CSSの適用順序をコントロールするための中心的な位置付けとして広く利用される詳細度ですが、それよりも先に多くの基準によって判断がされた上で利用されていることを把握しておくと良いでしょう。

Scope Proximity/スコープの近接性

詳細度も一致した場合には、Scope Proximity = スコープの近接性の判定が行われます。スコープの近接性とはScoped Styles@scopeで用いられる仕様であり、スタイルが複数のスタイルに該当した場合に、よりスコープのルートに近いスタイルが優先して適用されるものです。

@scope (.parent) {
  p {
    color: red;
  }
}
@scope (.child) {
  p {
    color: blue;
  }
}
<div class="parent">
  <!-- この p 要素からは @scope (.parent) のほうが近接性が高い -->
  <p>Parent Text</p>
  <div class="child">
    <!-- この p 要素からは @scope (.child) のほうが近接性が高い -->
    <p>Child Text</p>
  </div>
</div>
図8 スコープの近接性が異なる2つのスタイルの表示例

Cascade Sorting Orderでの観点で重要となるのは、スコープの近接性よりも詳細度のほうが優先度が高い点でしょう。該当のポイントも含めてScoped Styles自体の仕様については本連載のScoped Styles/スコープ付きスタイルルールにて詳細に解説しているため、あわせて確認してみてください。

!importantによる優先順位の逆転

!importantはOrigin and ImportanceとしてCascade Sorting Orderの先頭で判断される旨について解説しました。しかし、!importantは単純に適用順位が上がるだけでなく、利用されるシチュエーションによっては優先順位を逆転させるケースがあります。

一般的な開発プラクティスとして!importantの濫用は避けるべきと言われることもあり、日常の開発では頻繁に出会う挙動ではないかもしれません。ただ、特殊な挙動であるがゆえに、意図せず遭遇すると判断や対処が難しい部分でもあるため、詳細を確認してみましょう。

Originと!important

Origin and Importanceの解説において、次の3つのOriginについて紹介しました。

  • Author Origin
  • User Origin
  • User-Agent Origin

通常の優先順位はAuthor Origin → User Origin → User-Agent Originであり、詳細度などを気にすることなくブラウザ標準のスタイルシートを上書きできます。しかし、!importantが付与された宣言では優先順位が逆転し、User-Agent Origin → User Origin → Author Originの順となります。

つまり、ブラウザ標準のスタイルシートで!importantが付与されていると、ページ作成者が提供するCSSでの上書きは不可能となります。

ひとつ例を挙げると、CSSのoverlayプロパティが該当します。overlayプロパティはポップオーバーやダイアログといった要素で用いられ、値にautoを指定すると要素の重なりにおいて最上位に描画されるようになります。ChromiumでのUser-Agent Originに相当するスタイルを確認してみると、<dialog>要素のモーダル状態での表示時のスタイルとして次の宣言が含まれ、autoに対して!importantが付与されています[5]

dialog:modal {
  overlay: auto !important;
}

この指定により、<dialog>をモーダル状態で利用すると、最上位に表示されダイアログ以外の操作がブロックされます。そしてこのスタイルはUser-Agent Origin上で!importantが付与されているため上書きできず、ブラウザ側で動作が保証されている部分となります。

例外的にoverlayプロパティを制御する方法としてtransitionによる状態のコントロールが挙げられます。<dialog>の非表示時にアニメーションを追加したいケースにおいて、transitionによってoverlayプロパティの変化を遅延させることで、アニメーションが完了するまで確実に最上位に描画しておくことができます。

そして、このtransitionによるプロパティの制御も、実はCascade Sorting Orderで説明できます。Origin and ImportanceにおけるOriginには、先に挙げたAuthor Origin・User Origin・User-Agent Origin以外にも次のものが存在します。

  • Animation Origin
  • Transition Origin

そして、これら2つのOriginと、先に述べた!important付与の有無もすべて考慮したOriginの優先順位は次のとおりです(上のほうが優先されます⁠⁠。

  1. Transition Origin
  2. User-Agent Origin!important
  3. User Origin!important
  4. Author Origin!important
  5. Animation Origin
  6. Author Origin
  7. User Origin
  8. User-Agent Origin

transitionへの指定はTransition Originに相当します。Transition Originは!importantが付与されたどのOriginよりも優先順位で上回るため、例外的に制御が可能となります。

普段の開発においてUser-Agent Originのスタイルで付与された!importantを意識することはそれほど多くありませんが、ブラウザ側が挙動を担保したいものについては!importantが付与されている可能性がある点を覚えておくと良いでしょう。

Contextと!important

Contextにおいて、:host擬似クラスでのスタイル指定よりも、外部からのスタイル指定が優先される旨の解説をしましたが、ここでも!importantが付与されている場合には優先順位が逆転します。

Contextの例で挙げたコードをベースに、すべてのスタイルに!importantを付与してみます。

my-element {
  display: inline-block !important;
  border: 5px dashed blue !important;
  padding: 16px !important;
}
<my-element>
  <template shadowrootmode="closed">
    <style>
      :host {
        display: inline-block !important;
        border: 1px solid black !important;
        padding: 8px !important;
      }
    </style>
    <div>Shadow DOM TEXT</div>
  </template>
</my-element>
図9 Shadow Hostへのスタイリングに!importantを組み合わせた例

ともに!importantを付与しましたが、:host擬似クラスのスタイルが優先されるようになりました。これはつまり、:host擬似クラスでのスタイル指定において!importantを付与すると、外部からのスタイル指定を無効化できることを意味します。

Shadow DOMにおいて確実に保証したい要件がある場合に、:host擬似クラスと!importantを用いることで外部からの上書きを抑制し、提供時に期待する表示を担保する、といったユースケースが考えられます。

Cascade Layersと!important

Cascade Layersにおいても、!importantが付与されたスタイルにおいてはレイヤーの優先順位が逆転します。

Cascade Layersはそもそも「Origin間の優先順位相当の仕組みを、単一のOrigin内で独自に定義可能とする」といった機能である側面を持ち、仕様においても次のように言及されています。

In the same way that cascade origins provide a balance of power between user and author styles, cascade layers provide a structured way to organize and balance concerns within a single origin.

Originの仕様において!importantが付与されている場合には優先順位が逆転し、ベースとなるUser-Agent Originが優先される旨の解説をしましたが、Cascade Layersにおいてもこれを踏襲するような仕様となっています。

通常、より後に宣言されたレイヤーが優先されますが、!importantが付与されたスタイルにおいては、より先に宣言されたレイヤーのほうが優先されます。暗黙のレイヤーなども加味してすべてを列挙すると、次のような優先順位となります(上のほうが優先されます⁠⁠。

  1. より先に宣言されたレイヤー!important
  2. より後に宣言されたレイヤー!important
  3. 暗黙のレイヤー!important
  4. 暗黙のレイヤー
  5. より後に宣言されたレイヤー
  6. より先に宣言されたレイヤー

次のような.textクラスが付与された要素のスタイル定義を例に考えてみると、文字カラーは通常のレイヤーの優先順に従いblackが適用されますが、文字サイズについては!importantが付与されているためレイヤーの優先順位が逆転し、最も最初に宣言されたレイヤー内の14pxが適用されます。

@layer layer1, layer2, layer3;

.text {
  color: black; /* color 指定の中で優先度が最も高い */
  font-size: 12px !important;
}

@layer layer1 {
  .text {
    color: red;
    font-size: 14px !important; /* font-size 指定の中で優先度が最も高い */
  }
}
@layer layer2 {
  .text {
    color: blue;
    font-size: 16px !important;
  }
}
@layer layer3 {
  .text {
    color: green;
    font-size: 18px !important;
  }
}

利用ケースとしては、User-Agent Originでの!important宣言のように、後続のレイヤーに上書きされたくないスタイルに対しての!importantの付与が考えられます。

しかし、これは適用順序の中でもかなり強い宣言となります。もともと!important自体、むやみに利用すべきものではないですが、Cascade Layersと組み合わせる場合はさらに慎重にすべきでしょう。仮に、最初に明示的に宣言したベースとなるレイヤー上で!importantを付与してしまうと、暗黙的なレイヤーを含む他のいずれのレイヤーでも優先順位で上回ることは不可能となります。

/** 明示的に宣言したレイヤーはこの 3 つの他に存在しないと仮定する */
@layer layer1, layer2, layer3;

.text {
  color: black;
}

@layer layer1 {
  .text {
    /** このスタイルは暗黙のレイヤーを含む他のレイヤーからは上書きできない */
    color: red !important;
  }
}
@layer layer2 {
  .text {
    color: blue;
  }
}
@layer layer3 {
  .text {
    color: green;
  }
}

これを上書きするためには、同じレイヤー内で先に!importantを付与して宣言するか、新しく先に宣言するレイヤーを追加して!importantを付与する必要があり、容易ではありません。もし!importantを付与したくなった際には、今まで以上に「本当に必要か?」を落ち着いて検討してみましょう。

まとめ

実際のところCSSの適用順序については雰囲気で理解していた方も多いかもしれません。しかし、掘り下げてみると様々な仕様が絡み合い判定されており、広く知られている詳細度などの知識は、適用順序においてもごく一部の話であることがわかりました。また、!importantの特殊な挙動を知らずに利用すると、意図せず上書き不可能なスタイルを生み出してしまうなど、厄介なことになりかねません。しかし、Cascade Sorting Orderの仕様から理解していると、トリッキーな挙動に出会ったとしても驚くことなく対処できたり、そもそも問題自体を回避できる設計を行うこともできるでしょう。

私個人がCascade Sorting Orderについて調べた最初のきっかけは!importantでも上書きできないスタイルってあるのだろうか?」という単純な疑問からでしたが、その後CSS Cascading and Inheritance Level 6を読んでいるうちに、今まで自分が知らなかった仕様が多くあることに気づきました。仕様を読むことで得られる新しい知見は確実に存在しますので、ぜひ興味がある機能があれば、みなさん少し深くまで潜って仕様を辿ってみるのはいかがでしょうか?

さて、全6回でお送りしてきましたCSS Modern Featuresですが、これにて終了となります。ここまでお付き合い頂きありがとうございました!

次回からの「乗りこなせ!モダンフロントエンド」は、私と同じサイボウズ フロントエンドエキスパートチームのメンバーから、テーマを変えてJavaScriptのモダン機能を中心に新シリーズでの連載お届けする予定です。すこし時間をおくことになりますが、お楽しみに!

おすすめ記事

記事・ニュース一覧