先日、以下の 2 つの Bookmarklet を公開しました。
これらのツールを作成するために、CSS の値の処理について、改めて仕様を読んで学習したのですが、あまり意識しないで書いてきた CSS の値について、いくつか新たな発見がありました。
本記事では、この CSS に指定した値がどのような処理を経て最終的な値に変換されていくのかを、コード例を用いながら説明していきます。
値の処理
見出し「値の処理」CSS の値の処理は W3C 仕様の「CSS Cascading and Inheritance Level 5」内にある「4. Value Processing」が該当します。
CSS の値は以下の段階を経て、ブラウザで描画できる値に変換されていきます。
No. | 値 | 日本語訳 | 概要 |
---|---|---|---|
1 | Declared Value | 宣言値 | 宣言された値 |
2 | Cascaded Value | カスケード値 | カスケードの結果によって適用される値 |
3 | Specified Value | 指定値 | 指定された値 |
4 | Computed Value | 計算値 | 計算された後の値 |
5 | Used Value | 使用値 | レイアウト確定後に計算される値 |
6 | Actual Value | 実効値 | User-Agent によって最終調整される値 |
以下のスタイル指定を例に考えてみます。前提としてビューポート幅は 1000px
とします。
比較する意図で、スタイルが適用されない指定がいくつか含まれています。
このとき、<div class="child">
の inline-size
プロパティの値は、最終的にはどのような値になるでしょうか。順番に見ていきましょう。
Declared Value
見出し「Declared Value」Declared Value は、対象の要素に指定された宣言が該当します。セレクタや @media
などの条件に一致しない場合や、プロパティや値の構文が正しくない場合には除外されます。
また、-webkit-
のようなベンダープレフィックス付きのレガシーな構文が、新しい構文に変換されるのもこのタイミングです。
今回の例では、セレクタにマッチして構文が正しい、以下の 2 つの指定に絞り込まれます。
- Declared Value 宣言値
.child { inline-size: var(--size); } div { inline-size: 100%; }
- Cascade Value カスケード値
- Specified Value 指定値
- Computed Value 計算値
- Used Value 使用値
- Actual Value 実効値
ここで注意する点としては、カスタムプロパティの値が構文として正しいかどうかは、このタイミングでは評価されないということです。例として、以下のスタイルを比較してみます。
無効な値を直接指定した場合には Declared Value の段階で無効だとみなされますが、カスタムプロパティに指定した場合には、そのまま Cascade Value に進みます。
このカスタムプロパティの値の評価については、後述する Computed Value で説明します。
Cascade Value
見出し「Cascade Value」Cascade Value は、カスケードの仕組みによって適用される値を指します。ここでは、詳細度の高い .child
の var(--size)
が適用されます。
- Declared Value 宣言値
- Cascade Value カスケード値
/* 詳細度: 0-1-0 🏆 */ .child { inline-size: var(--size); } /* 詳細度: 0-0-1 */ div { inline-size: 100%; }
- Specified Value 指定値
- Computed Value 計算値
- Used Value 使用値
- Actual Value 実効値
より詳細なカスケードの仕組みについては、「CSS カスケード再入門 #1 基礎編」で詳しく説明しています。
Specified Value
見出し「Specified Value」Specified Value は、プロパティに指定された値そのものです。まだ値は計算されないので、今回の例では var(--size)
のままです。
- Declared Value 宣言値
- Cascade Value カスケード値
- Specified Value 指定値
var(--size)
- Computed Value 計算値
- Used Value 使用値
- Actual Value 実効値
なお、値に initial
、inherit
、unset
、revert
、revert-layer
といった CSS 全体のキーワード(CSS-wide keywords)を指定している場合には、先祖要素やオリジンの指定値に置き換わります。
Computed Value
見出し「Computed Value」Computed Value は、祖先要素のレイアウトが確定する前に計算できる値です。
例えば、font-size: 1rem
の指定は、祖先要素のレイアウトに影響を受けないため、このタイミングで計算され、1rem
(相対値)が 16px
(絶対値)に変換されます。
また、var()
関数でカスタムプロパティを指定している場合には、参照先の値に置き換わります。@property
の構文(syntax
)が検証されるのもこのタイミングです。
今回の例では、var(--size)
が、カスタムプロパティの値である 33.33333%
に変換されます。
- Declared Value 宣言値
- Cascade Value カスケード値
- Specified Value 指定値
- Computed Value 計算値
33.33333%
- Used Value 使用値
- Actual Value 実効値
そもそも計算を必要としない場合には、Specified Value と同じ値になります。
IACVT
見出し「IACVT」カスタムプロパティが評価されるのは Computed Value のタイミングのため、無効な値を指定している場合には、IACVT(Invalid At Computed-Value Time)と呼ばれる状態になります。
IACVT の値は、以下の条件によって決まります。
@property
で定義していないカスタムプロパティや、syntax
が*
(Universal Syntax)の場合にはinitial
になる1- それ以外の場合には、
unset
が指定されているのと同様になる2
なお、すでに Cascade Value によって絞り込まれている状態なので、カスケードのステップをさかのぼって、次に優先度の高いスタイルが適用されることはありません。
加えて、この IACVT ですが、Declared Value の構文エラーと違って、現時点ではデベロッパーツール上では警告が表示されない点にも注意が必要です。
Used Value
見出し「Used Value」Used Value は、祖先要素のレイアウトが確定してから計算される値です。
今回の例では、サイズをパーセント値(%
)で指定しており、親要素のサイズが決まらないと絶対値(px
)に変換することができません。
親要素 .parent
の指定は inline-size: 400px
なので、計算後の値は 133.33332px
です。
- Declared Value 宣言値
- Cascade Value カスケード値
- Specified Value 指定値
- Computed Value 計算値
- Used Value 使用値
/* 400px * 33.33333% */ 133.33332px
- Actual Value 実効値
祖先要素のレイアウトに影響を受けない場合は、Computed Value と同じ値になります。
Actual Value
見出し「Actual Value」最後に、Actual Value は、ブラウザ(User-Agent)によって最終調整される値です。
今回の例では小数点以下の値がブラウザにとって扱いやすい値に丸められ、Google Chrome では 133.328px
、Firefox では 133.317px
、そして Safari では 133.328125px
に変換されます。
- Declared Value 宣言値
- Cascade Value カスケード値
- Specified Value 指定値
- Computed Value 計算値
- Used Value 使用値
- Actual Value 実効値
/* Google Chrome */ 133.328px /* Firefox */ 133.317px /* Safari */ 133.328125px
ここまでの流れを経て、最終的にブラウザに描画されるスタイルの値が決まります。
さらに理解を深めたい場合には、W3C の仕様にもいくつか例が掲載されているので、こちらもあわせて参考にするとよいかもしれません。
getComputedStyle()
で取得した値はどの値?
この見出しのリンクJS で計算済みのスタイルの値を取得するには、以下の 2 つのメソッドを使用します。
getComputedStyle()
で、対象の要素に指定されたスタイルを取得getPropertyValue()
で、指定したプロパティの値を取得
ここで得られる値はブラウザごとに異なり、Google Chrome では 133.328px
、Firefox では 133.317px
、そして Safari では 133.328125px
なので、Actual Value と一致します。
しかし、W3C の仕様3や MDN では、Actual Value(実効値)とは明示されておらず、Resolved Value(解決値)という用語が使用されています。
ちなみに、JS やデベロッパーツールを介して、Computed Value(計算値)や Used Value(使用値)をピンポイントに取得する方法は現時点では見当たりません。
おわりに
見出し「おわりに」普段 CSS のコードを書くときに、Specified Value 以降の処理を意識することはほとんどないでしょう。しかし、カスタムプロパティや @property
を使用する機会が増えていくなかで、その仕組みを理解しておくことは重要であると考えています。
最後に、今回のダイジェストを掲載します。
- Declared Value 宣言値
.child { inline-size: var(--size); } div { inline-size: 100%; }
- Cascade Value カスケード値
/* 詳細度: 0-1-0 🏆 */ .child { inline-size: var(--size); } /* 詳細度: 0-0-1 */ div { inline-size: 100%; }
- Specified Value 指定値
var(--size)
- Computed Value 計算値
33.33333%
- Used Value 使用値
/* 400px * 33.33333% */ 133.33332px
- Actual Value 実効値
/* Google Chrome */ 133.328px /* Firefox */ 133.317px /* Safari */ 133.328125px
次回は、これらの仕組みを踏まえて、@property
の使い方や課題を取り上げます。
脚注
-
このときの
initial
値は「Guaranteed-Invalid Value」と呼ばれます。なお、カスタムプロパティの値にinitial
を指定することで明示的に無効な値を渡すこともできます。 ↩ -
継承されたプロパティの場合には
inherit
、そうでなければinitial
になります。 ↩ -
「CSS Object Model」は、現時点では草案(Working Draft)段階である点には注意が必要です。 ↩