CSS値の計算過程(specified→computed→used→actual)
emやパーセントが最終的に何pxになるかをブラウザと同じ4段階で追え、継承の食い違いやcalc()の予想外を当て推量せず説明できる。宣言値から実際値までの変換と基準の決まり方を原理から解き明かします。
- 1.値は declared→cascaded→specified→computed→used→actual と段階変換される。computed は継承される正規化済みの値で、レイアウト前に確定する。used はレイアウト後に確定する実寸、actual はデバイス制約で丸めた最終値。
- 2.em/rem や `currentColor` などの相対値の多くは computed の段で絶対化されるが、パーセンテージは基準が確定する used まで残ることがある。継承されるのは computed であって、パーセント文字列がそのまま親から子へ渡るわけではない。
- 3.calc() は computed まで遅延評価され、混在単位は最終解決まで保持される。カスタムプロパティ(var())は computed-value time に置換され、置換後にプロパティの文法で再パースされる。
値は6つの段階を経て画面上の実寸になる
width: 50% や font-size: 1.2em と書いた宣言が、最終的に画面上の何ピクセルになるか。CSSはこの変換を明確に定義された段階のパイプラインとして処理します。各段で「何が解決され、何がまだ残るか」が仕様で決まっており、継承されるのも、calc() が評価されるのも、特定の段に固定されています。段階は次のとおりです。
declared value 宣言値:そのプロパティに当たった全宣言
↓ カスケード(オリジン/レイヤ/詳細度/出現順で1つ選ぶ)
cascaded value カスケード値:勝ち残った1つの宣言値
↓ 欠落を継承/初期値で補う(inherit/initial 等の解決)
specified value 指定値:そのプロパティに「指定された」最終的な値
↓ 相対値の絶対化・正規化
computed value 計算値:継承される、レイアウト非依存の正規形
↓ レイアウトを実行し、基準サイズを確定
used value 使用値:レイアウト後に決まる実寸(px)
↓ デバイス制約で丸め
actual value 実際値:描画に使う最終値
ここで決定的なのは、継承されるのは computed value だという点です。カスケードで勝者を選ぶアルゴリズムそのものは CSSカスケード・詳細度・継承 で扱いますが、その出口(cascaded→specified→computed)から先が本稿の主題です。
あるプロパティに当たる宣言が1つもなければ cascaded value は存在しません。その穴を埋めるのが specified への段で、継承プロパティなら親の computed value、非継承なら初期値が入ります。inherit/initial/unset/revert はこの埋め方をプロパティ側から明示制御するキーワードです。逆に宣言があった場合、specified は基本的にその宣言値(必要なら inherit などを解決した結果)になります。
computed value:レイアウト前に確定する継承の通貨
computed value は、specified value からレイアウトに依存しない正規化を施した値です。「レイアウト前に決まる」ことが要点で、だからこそ子要素はレイアウト計算を待たずに親の computed を継承できます。computed の段で絶対化される代表例を挙げます。
| 指定値 | computed で起きること | 結果 |
|---|---|---|
| font-size: 1.2em | 親の font-size(px)× 1.2 を計算 | 絶対pxに固定 |
| line-height: 1.5(単位なし) | 数値のまま保持し継承 | 子は自分の font-size×1.5 で再計算 |
| color: currentColor | color の computed を参照し解決 | 具体的な色値 |
| width: 50% | 正規化のみ、基準は未確定 | パーセントのまま残る |
| transform: translateX(2em) | em を絶対px化 | px化、ただし%は保持 |
em は computed の時点で親(または自要素)の font-size を基準にpx へ畳み込まれます。一方 line-height: 1.5 のような単位なし数値はあえて computed でも数値のまま継承され、各子が自分の font-size に掛けて使う——これが「単位なし line-height を親に置くと各子で適切な行間になる」理由です。px を継承させると親の行間がそのまま降りてしまいます。
width: 50% の computed value は 50% のままです。基準となる包含ブロックの幅はレイアウトが走るまで未確定だからです。プロパティによって扱いが分かれ、font-size: 150% は親 font-size を基準に computed で px 化されますが、width/height/margin などの%は computed では生のパーセントで保持され、used の段で初めて解決されます。「computed value を見たら px になっているはず」という思い込みは、ここで崩れます。
used value と actual value:レイアウト後とデバイス丸め
used value は、computed value にレイアウトの結果を流し込んで確定する実際の寸法です。パーセンテージや auto、フレックスの伸縮など、基準サイズが分からないと決められない値がここで初めて px になります。width: 50% は、包含ブロック幅が 800px と判明して初めて used value 400px になります。margin: auto の実際の余白量、フレックスアイテムの最終幅、min-height による下限の適用なども used の段の産物です。レイアウトの解決順序そのものは CSSレイアウトアルゴリズム が詳しく、used value はその出力に相当します。
actual value は used value にデバイス由来の制約を反映した最終値です。代表はピクセルへの丸めで、used が 400.6px でも、サブピクセルを許さない描画系では 401px のように整数化されます。border-width が計算上 0.4px になっても、最低 1 物理ピクセルを確保するために繰り上がる、といった調整もこの段です。actual はスクリプトから直接は取りにくく、getComputedStyle() が返すのは多くのプロパティでused value(一部は computed)である点に注意してください。
| 値の段 | 確定タイミング | px化 | getComputedStyle |
|---|---|---|---|
| computed value | レイアウト前 | em等は済/%は未 | 一部プロパティで返る |
| used value | レイアウト後 | 完了(%/autoも解決) | 多くのサイズ系で返る |
| actual value | 描画直前 | デバイス丸め後 | 原則返らない |
相対単位とパーセンテージの基準は段で異なる
相対値が「何を基準に絶対化されるか」は単位ごとに決まっており、解決される段も異なります。
| 単位/値 | 基準 | 解決される段 |
|---|---|---|
| em | 同要素または親の font-size | computed(font-size 自体は親基準) |
| rem | ルート要素の font-size | computed |
| vw / vh | ビューポートの幅・高さ | computed(ビューポートは既知) |
| %(font-size) | 親の font-size | computed で px 化 |
| %(width/height) | 包含ブロックの対応する寸法 | used |
| %(line-height) | 自要素の font-size | computed で px 化 |
em の基準が「font-size プロパティ自身では親、それ以外のプロパティでは自要素の font-size」である点はよく引っかかります。font-size: 1.2em は親基準ですが、同じ要素の padding: 1em はその要素の computed font-sizeが基準です。rem と vw/vh は基準(ルート font-size、ビューポート)がレイアウト前から既知なので computed で絶対化できます。対して width: 50% は包含ブロックというレイアウトの産物を待つため used まで残る——同じ「相対値」でも解決段が割れるのはこの「基準が既知か否か」の差です。相対単位を土台にした設計は レスポンシブデザイン でも要になります。
calc() とカスタムプロパティの置換タイミング
calc() はできるだけ computed value time まで簡約され、異なる単位が混在する式は最後まで保持されます。calc(100% - 20px) は、% の基準(包含ブロック幅)が未確定なので computed では簡約しきれず、100% を used で px 化したうえで - 20px を適用して初めて単一の px になります。一方 calc(2em + 4px) は computed で em が px 化され、計算済みpx + 4px に畳まれます。混在単位を保持できるのが calc() の本質で、% と px を直接足せるのはこのためです。
calc(100% - 20px)
computed: 100% は基準未確定 → 式のまま保持(emやpx部分のみ正規化)
used: 100% を包含ブロック幅で解決し、- 20px を適用 → 単一の px
カスタムプロパティ(--* と var())の置換は computed-value time に起こります。重要なのは置換の順序で、(1) まず var() がカスタムプロパティの値(トークン列)に文字列的に置換され、(2) その置換結果をそのプロパティの本来の文法で再パースします。だから無効な値を仕込むと、置換後に初めて不正と判明し、そのプロパティは**無効値時の継承(initial か親の値)**へフォールバックします。
:root { --gap: 16px; }
.box {
--pad: 1em; /* カスタムプロパティの値は「ほぼ自由なトークン列」 */
padding: var(--pad); /* computed-value time に 1em へ置換 → さらに em を解決 */
margin: var(--gap); /* 16px へ置換 */
width: var(--missing, 50%); /* 未定義なのでフォールバック 50% を採用 */
}
通常のカスタムプロパティは型を持たないトークン列で、継承されるのは「文字列としての値」です。@property で構文(syntax)・初期値・継承可否を登録すると、その変数は型付き computed value を持ち、アニメーション補間や早期の妥当性検査が効くようになります。未登録の --* は computed-value time の置換まで実体が定まらないため、transition で滑らかに動かせないのが既定の挙動です。
頻出は、(1) 段の順序 declared→cascaded→specified→computed→used→actual と、継承されるのは computed という対応、(2) em/rem/vw は computed で px 化されるが width 系の % は used まで残るという解決段の差、(3) 単位なし line-height は computed でも数値のまま継承され各子で再計算される点、(4) calc() は混在単位を保持し computed〜used に跨って解決、(5) var() は computed-value time に置換され置換後に再パースされる点、(6) getComputedStyle() が返すのは多くが used value で actual ではない点です。「computed value は必ず px」という断定は典型的な誤りです。
まとめ
CSSの値は declared→cascaded→specified→computed→used→actual の段階を経て画面上の実寸になります。computed value はレイアウト非依存の正規形で、継承される通貨はこれです。em/rem/vw や currentColor は computed で絶対化されますが、width/height/margin のパーセンテージは基準(包含ブロック)が確定する used value まで生のまま残り、auto やフレックスの伸縮もここで px 化されます。actual value は used をデバイス制約で丸めた最終値で、getComputedStyle() が返すのは多くが used です。calc() は混在単位を保持して computed〜used に跨り解決し、カスタムプロパティ(var()) は computed-value time に置換され置換後に再パースされます。土台のセレクタや単位は CSS、勝者を選ぶ手続きは CSSカスケード・詳細度・継承、used を生み出すサイズ解決は CSSレイアウトアルゴリズム で押さえると、宣言から描画までの値の流れが一本につながります。
Web/フロントエンド Article
CSS値の計算過程(specified→computed→used→actual)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
CSS
比較で見る軸
難易度: advanced / カテゴリ: Web/フロントエンド / タグ数: 5
導入後に効く点
em/rem や `currentColor` などの相対値の多くは computed の段で絶対化されるが、パーセンテージは基準が確定する used まで残ることがある。継承されるのは computed であって、パーセント文字列がそのまま親から子へ渡るわけではない。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- Web/フロントエンド
- タグ数
- 5
判断チェックリスト
- 自社の用途が「CSS / 値の計算」に近いか確認する。
- 強みである「値は declared→cascaded→specified→computed→used→actual と段階変換される。computed は継承される正規化済みの値で、レイアウト前に確定する。used はレイアウト後に確定する実寸、actual はデバイス制約で丸めた最終値。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。