CSSの継承とカスケード
同じ段落の色を変更し、computed styleで実際に使われる値を取得します。継承と直接指定から始め、詳細度・記述順・インライン指定・レイヤーへ順に条件を増やします。styleOfは対象文書のgetComputedStyleからプロパティ値を取り出す関数です。
説明
一つの要素に複数のCSS宣言が関わると、優先順位に従って使う値が決まります。親からの継承、セレクタの詳細度、記述順、!important、カスケードレイヤーはそれぞれ異なる段階の仕組みです。常に「後に書いた方が勝つ」とは限りません。
同じ段落の色を変更し、computed styleで実際に使われる値を取得します。継承と直接指定から始め、詳細度・記述順・インライン指定・レイヤーへ順に条件を増やします。styleOfは対象文書のgetComputedStyleからプロパティ値を取り出す関数です。
1親から継承する色
段落自身には色を指定せず、親の色を赤にします。
(globalThis.doc=createFormDocument独立した表示文書を作成('<!doctype html><html lang="ja"><head><style>body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee}</style></head><body><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>'),globalThis.sheet=doc.createElement("style"),doc.head.append(sheet),styleOf("#sample","color")段落の計算済みの色)段落の色はrgb(220, 80, 80)です。colorは継承されるプロパティなので、段落への指定がなければ親の値を使います。marginやborderなど、すべてのプロパティが同じように継承されるわけではありません。
2直接指定は継承値より先に使う
段落に青を直接指定します。
(sheet.textContent="p{color:rgb(80,150,230)}子自身への直接指定",styleOf使われる値を確認("#sample","color"))段落は青になります。親のstyle属性が強い指定だから子も必ず赤になる、という計算ではありません。子自身へ使う宣言を決める処理と、子に値がない場合の継承は別です。
3同じ条件なら記述順
同じ.noteセレクタを二つ書きます。
(sheet.textContent=".note{color:rgb(80,150,230)}先に書いた宣言 .note{color:rgb(80,200,140)}後に書いた宣言",styleOf("#sample","color"))同じ起点・重要度・レイヤー・詳細度などの条件では、後の緑が採用されます。記述順は常に最初に比較する条件ではありません。
4idとclassの詳細度
idの赤を先に書き、その後へclassの青を置きます。
(sheet.textContent="#sample{color:rgb(220,80,80)}idによる指定 .note{color:rgb(80,150,230)}後にあるclass指定",styleOf("#sample","color"))赤が採用されます。idの詳細度(1,0,0)はclassの(0,1,0)より高いためです。この組は桁ごとに比較するもので、classを十個書けばid一個と同点になる十進数の点数ではありません。
5:whereは詳細度を増やさない
idを:whereの中へ入れます。
(sheet.textContent=":where(#sample)idを選ぶが詳細度は0{color:rgb(220,80,80)} .noteclassの詳細度{color:rgb(80,150,230)}",styleOf("#sample","color"))今度は青になります。:where自身と引数の詳細度は0なので、.noteのclass指定が上回ります。同じ要素を選ぶセレクタでも、詳細度は異なり得ます。
6:isは引数の詳細度を使う
:whereを:isへ変えます。
(sheet.textContent=":is(#sample)引数のidの詳細度を使う{color:rgb(220,80,80)} .note{color:rgb(80,150,230)}",styleOf("#sample","color"))赤へ戻ります。:isは引数のうち最も高い詳細度を使うため、この指定はidの詳細度を持ちます。:isと:whereは対象の選び方が似ていても、優先順位の設計では同じではありません。
7style属性で指定
段落自身のstyle属性に緑を指定します。
(doc.getElementById("sample").style.color="rgb(80,200,140)"段落自身のインライン指定,styleOf("#sample","color"))通常の作者スタイルの範囲では、インラインのstyle指定がスタイルシートの通常宣言より優先されます。親のstyleからの継承ではなく、段落自身への指定である点も確認します。
8!importantの段階
スタイルシートの宣言に!importantを付けます。
(sheet.textContent="p{color:rgb(230,180,60) !important重要宣言として扱う}",styleOf("#sample","color"))黄色が採用されます。この!important宣言は通常のインライン指定より優先されます。!importantはセレクタの詳細度を少し増やす指定ではなく、カスケードの重要度に関わります。
9インラインの重要宣言
段落のstyleにもimportant付きの色を設定します。
(doc.getElementById("sample").style.setProperty("color","rgb(200,100,200)","important")重要度付きのインライン指定,styleOf("#sample","color"))この作者スタイル同士の比較では、インラインの重要宣言が採用されます。利用者・UAの重要宣言やトランジションなどを含むカスケード全体を、インラインが何より強いという一言では表せません。
10レイヤー順は詳細度より先
インライン指定を除き、base・themeの二レイヤーで競合させます。
(doc.getElementById("sample").removeAttribute("style")インライン指定を除去,sheet.textContent="@layer base,themeレイヤー順を定義; @layer base{#sample{color:rgb(220,80,80)}} @layer theme後のレイヤー{p{color:rgb(80,150,230)}}",styleOf("#sample","color"))通常宣言では後のthemeレイヤーが優先され、pの青になります。base内のidの方が詳細度は高くても、異なるレイヤー間ではその比較より先にレイヤー順が決まります。
11レイヤー外の通常宣言
同じスタイルにレイヤー外の通常宣言を追加します。
(sheet.textContent+=レイヤー外へ通常宣言を追加" p{color:rgb(80,200,140)}",styleOf("#sample","color"))レイヤーに属さない通常宣言の緑が、レイヤー内の通常宣言より優先されます。レイヤーを導入するときは、既存のレイヤー外の指定が残っていないかも確認します。
12重要宣言ではレイヤー順が逆転
すべてを重要宣言にして、base・theme・レイヤー外を比較します。
(sheet.textContent="@layer base,theme同じレイヤー順; @layer base{p{color:rgb(220,80,80) !important}}最初のレイヤーの重要宣言 @layer theme{#sample{color:rgb(80,150,230) !important}} p{color:rgb(80,200,140) !important}",styleOf("#sample","color"))最初のbaseレイヤーの赤が採用されます。重要宣言ではレイヤーの優先順が逆転し、レイヤー内の重要宣言はレイヤー外の重要宣言より優先されます。通常宣言の順序をそのまま当てはめることはできません。
まとめ
子への直接指定と親からの継承は別で、使う宣言がない場合に継承値が関わります。
重要度やレイヤーなどを決めた後、詳細度・記述順を比較します。
通常宣言と重要宣言ではレイヤーの優先順が異なります。computed styleで最終値を確認します。
操作履歴と解説を振り返れます。
ブラウザ / HTML・DOM
(globalThis.doc=createFormDocument('<!doctype html><html lang="ja"><head><style>body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee}</style></head><body><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>'),globalThis.sheet=doc.createElement("style"),doc.head.append(sheet),styleOf("#sample","color"))"rgb(220, 80, 80)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
(sheet.textContent="p{color:rgb(80,150,230)}",styleOf("#sample","color"))"rgb(80, 150, 230)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} p{color:rgb(80,150,230)} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
(sheet.textContent=".note{color:rgb(80,150,230)} .note{color:rgb(80,200,140)}",styleOf("#sample","color"))"rgb(80, 200, 140)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} .note{color:rgb(80,150,230)} .note{color:rgb(80,200,140)} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
(sheet.textContent="#sample{color:rgb(220,80,80)} .note{color:rgb(80,150,230)}",styleOf("#sample","color"))"rgb(220, 80, 80)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} #sample{color:rgb(220,80,80)} .note{color:rgb(80,150,230)} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
(sheet.textContent=":where(#sample){color:rgb(220,80,80)} .note{color:rgb(80,150,230)}",styleOf("#sample","color"))"rgb(80, 150, 230)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} :where(#sample){color:rgb(220,80,80)} .note{color:rgb(80,150,230)} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
(sheet.textContent=":is(#sample){color:rgb(220,80,80)} .note{color:rgb(80,150,230)}",styleOf("#sample","color"))"rgb(220, 80, 80)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} :is(#sample){color:rgb(220,80,80)} .note{color:rgb(80,150,230)} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
(doc.getElementById("sample").style.color="rgb(80,200,140)",styleOf("#sample","color"))"rgb(80, 200, 140)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} :is(#sample){color:rgb(220,80,80)} .note{color:rgb(80,150,230)} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note" style="color: rgb(80, 200, 140);">参加案内</p></div></body></html>
(sheet.textContent="p{color:rgb(230,180,60) !important}",styleOf("#sample","color"))"rgb(230, 180, 60)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} p{color:rgb(230,180,60) !important} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note" style="color: rgb(80, 200, 140);">参加案内</p></div></body></html>
(doc.getElementById("sample").style.setProperty("color","rgb(200,100,200)","important"),styleOf("#sample","color"))"rgb(200, 100, 200)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} p{color:rgb(230,180,60) !important} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note" style="color: rgb(200, 100, 200) !important;">参加案内</p></div></body></html>
(doc.getElementById("sample").removeAttribute("style"),sheet.textContent="@layer base,theme; @layer base{#sample{color:rgb(220,80,80)}} @layer theme{p{color:rgb(80,150,230)}}",styleOf("#sample","color"))"rgb(80, 150, 230)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} @layer base,theme; @layer base{#sample{color:rgb(220,80,80)}} @layer theme{p{color:rgb(80,150,230)}} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
(sheet.textContent+=" p{color:rgb(80,200,140)}",styleOf("#sample","color"))"rgb(80, 200, 140)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} @layer base,theme; @layer base{#sample{color:rgb(220,80,80)}} @layer theme{p{color:rgb(80,150,230)}} p{color:rgb(80,200,140)} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
(sheet.textContent="@layer base,theme; @layer base{p{color:rgb(220,80,80) !important}} @layer theme{#sample{color:rgb(80,150,230) !important}} p{color:rgb(80,200,140) !important}",styleOf("#sample","color"))"rgb(220, 80, 80)"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/1.5 system-ui;margin:16px;background:#111;color:#eee} @layer base,theme; @layer base{p{color:rgb(220,80,80) !important}} @layer theme{#sample{color:rgb(80,150,230) !important}} p{color:rgb(80,200,140) !important} :root{}</style></head><body inert><div id="parent" style="color:rgb(220,80,80)"><p id="sample" class="note">参加案内</p></div></body></html>
演習完了