このページではCSS 2.1の仕様でも特に重要なCSSの処理モデル、カスケーディング、値の算出について説明します。
CSS 2.1ではユーザーエージェントが以下のようにしてCSSを処理すると想定しています。(実際にユーザーエージェントの実装がそうなっているとは限りません。)
重要なのは4番目のカスケード処理と値の算出です。次にそれらを説明します。
スタイルシートには製作者のスタイルシート、利用者のスタイルシート、ユーザーエージェントのスタイルシートの三つがあります。利用者のスタイルシートは通常ユーザースタイルシート、ユーザーエージェントのスタイルシートはユーザーエジェントのデフォルトスタイルシートと呼ばれます。ユーザースタイルシートは利用者が製作者の作ったスタイルシートを自分の好みに合わせて上書きしたいときなどに利用されます。また、製作者、利用者がスタイルシートを用意しなくても、ユーザーエージェントのデフォルトスタイルシートが適用されるので、ソース文書は利用者に伝わるような形式になってレンダリングされるのです。(例えば、Internet Explorerのデフォルトスタイルシートが適用されると、HTMLで見出しを表すh1
要素は、見出しと分かるよう太い大きな文字で表示されます。)
CSSを書くと、大抵は特定の要素にマッチする規則が複数存在することになります。例えば
<p>文章…</p>
p { color: red }
p.clsX { color: blue }
上の二つの規則はどちらもソース文書中のp要素にマッチします。ことのきどちらの規則が適用されるのかが問題となります。さらに、スタイルシートは製作者、利用者、ユーザーエージェントの三者が用意している可能性があるため、この問題はより複雑になります。どの規則のどの宣言が適用されるのかを決めるのがカスケーディング(cascading)です。
カスケーディングは次の順序で行われます。
!important
がある宣言!important
がある宣言セレクタは詳細度を持ち、上述のプロセスの3番目ではそれが高い規則が優先されます。詳細度は以下のように計算します。
以下はその例です。
セレクタ | a | b | c | d | 詳細度 |
---|---|---|---|---|---|
* |
0 | 0 | 0 | 0 | 0,0,0,0 |
li |
0 | 0 | 0 | 1 | 0,0,0,1 |
li:first-line |
0 | 0 | 0 | 2 | 0,0,0,2 |
ul li |
0 | 0 | 0 | 2 | 0,0,0,2 |
ul > li |
0 | 0 | 0 | 2 | 0,0,0,2 |
h1 + p[title=hoo] |
0 | 0 | 1 | 2 | 0,0,1,2 |
h1 p.clsX |
0 | 0 | 1 | 2 | 0,0,1,2 |
p.clsX.clxY |
0 | 0 | 2 | 1 | 0,0,2,1 |
*#myid |
0 | 1 | 0 | 0 | 0,1,0,0 |
style="" (セレクタではありませんが) |
1 | 0 | 0 | 0 | 1,0,0,0 |
この計算はややこしいので要点を挙げると、
となります。ul li
とul > li
では何となく後者の方が詳細度が高いような気がしますが、実際は同じです。よって後に書かれている規則が優先されます。結合子は詳細度の計算には関係ないことに注意してください。
それでは具体的に、CSSが処理される過程を見てみましょう。ここではサンプルとして、ソース文書となるHTML、製作者のスタイルシート、利用者のスタイルシート、ユーザーエージェントのデフォルトスタイルシートを用意しました。デフォルトスタイルシートはユーザーエージェントの実装によって異なるので、ここでは仕様書のDefault style sheet for HTML 4より必要な箇所を抜粋しました。出力メディアはコンピュータの画面とします。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css" media="screen,print">
<title>サンプルHTML</title>
</head>
<body id="foo">
<h1>サンプルHTML</h1>
<p>簡単なHTMLのサンプルです。</p>
<address>
Last-modified: 2007-01-01
</address>
</body>
</html>
body {
font-size: 12px;
color: black;
background: silver
}
body {
font-size: 16px !important;
}
body#foo {
color: black !important;
color: maroon !important
}
html, address, body, h1, p {
display: block
}
body { margin: 8px }
h1 {
font-size: 2em;
margin: .67em 0;
font-weight: bolder
}
address { font-style: italic }
それではCSSの処理モデルを順に追ってみます。
screen
です。body
要素に注目してみます。すると次のような規則が見つかります。body {
font-size: 12px;
color: black;
background: #eeeeee
}
body {
font-size: 16px !important;
}
body#foo {
color: black !important;
color: maroon !important
}
html, address,
body, h1, p, { display: block }
body { margin: 8px }
宣言 | 出所 |
---|---|
background:#eeeeee |
製作者 |
display:block |
ユーザーエージェント |
margin:8px |
ユーザーエージェント |
!important
がある宣言!important
がある宣言font-size
プロパティについてです。宣言 | 出所 |
---|---|
font-size:12px |
製作者 |
font-size:16px !important |
利用者(!important 付) |
font-size
プロパティの指定値は利用者が!important
付きで指定した16pxに決定しました。次はcolor
プロパティに注目してみましょう。宣言 | 出所 |
---|---|
color:black |
製作者 |
color:black !important |
利用者(!important 付) |
color:maroon !important |
利用者(!important 付) |
color
プロパティは最も重要度の高い規則が二つ残ってしまいました。よってこれは次のプロセスに持ち越されます。宣言 | セレクタ | 詳細度 |
---|---|---|
color:black !important |
body#foo |
1,0,0,0 |
color:maroon !important |
body#foo |
1,0,0,0 |
color:black !important
color:maroon !important
body
要素のcolor
プロパティの値は"maroon
"に決定しました。(ああ長かった…。)これを全ての要素について行います。上記のようにして各要素の各プロパティに値が割り当てられるのですが、以下では値の算出のプロセスを説明します。値の算出には指定値、算出値、利用値、実効値という四つのプロセスを辿ります。
指定値(specified value)は以下のように割り当てられます。
特定の値はカスケーディングの最中に変換され、算出値(computed value)となります。例えば、単位が"em
"や"ex
"である長さはピクセル値や絶対的な長さに、相対URIは絶対URIになります。
<p>指定値は<dfn>算出値</dfn>に変換されます。</p>
p { font-size: 12px }
dfn { font-size: 1.2em }
この例ではp
要素のfont-size
プロパティの指定値は"12px"で、これはこのまま算出値になります。一方、dfn
要素のfont-size
プロパティで使われる"em
"は親要素のfont-size
プロパティの算出値を参照するので、dfn
要素のfont-size
プロパティの算出値は12px * 1.2 = 14.4pxとなります。
要素 | 指定値 | 算出値 |
---|---|---|
p要素 | 12px | 12px |
dfn要素 | 1.2em | 14.4px |
算出値は通常文書を整形することなく扱われますが、中には文書が整形されないと値を決定できないものがあります。例えば、width
プロパティが<パーセント値>で指定されている場合、包含ブロックの幅が決まらないとその値を決められません。そのように、残っている全ての値を絶対的な値へ解決したものが利用値(used value)となります。
文書のレンダリングには原則として利用値が使用されますが、場合によってはユーザーエージェントがその値を利用できないことがあります。例えば、上の14.4pxというフォントサイズは、そのサイズのフォントが存在しなければ14pxに丸められるかもしれません。また、画面の色数が少なければ、<色>は適当な値に変換されるでしょう。そうして実際に使われる値が実効値(actual value)です。
プロパティの中には継承(inheritanhce)を行うものがあります。継承を行うプロパティは、値が指定されなかったとき代わりに親の算出値を用います。
<body><p>継承するときは親の指定値ではなく<em>算出値</em>を使います。</p></body>
body { font-size: 12px }
p { font-size: 1.2em }
この例ではp
要素のfont-size
プロパティの指定値は"1.2em"であり、算出値は12px * 1.2 = 14.4pxとなります。また、em
要素のfont-size
プロパティの指定値は親の算出値を継承して、"14.4px"となります。(指定値"1.2em"を継承するのではありません。)
要素 | 指定値 | 算出値 |
---|---|---|
body要素 | 12px | 12px |
p要素 | 1.2em | 14.4px |
em要素 | 14.4px (継承) | 14.4px |
継承するかしないかはプロパティごとに定められています。例えば、color
プロパティ(文字色)は継承し、border-style
プロパティ(ボーダーのスタイル)は継承しません。継承しないプロパティの値が指定されなかったときは、指定値で述べたようにそのプロパティの初期値が使われます。
値にキーワード"inherit
"を指定すると、継承しないプロパティでも強制的に親の算出値を継承させることができます。