CSSをより深く理解する、プロパティの値に無効な値を設定する(IACVT)とどのように処理されているのかを解説

CSSで無効な値、たとえばcolor: 20px;のようにcolorプロパティにカラー値以外を設定したり、background-colorにカラー値以外をカスタムプロパティで設定したりすると当然その値は反映されません。

CSSにおいて値の処理がどのように実行されているのかを紹介します。無効な値だけでなく、値の上書き、値の継承、キーワードから変換した値など、いろいろな処理がされています。

CSSで無効な値を設定すると、どのように処理されているのか

CSS Foundations: What is IACVT?
by Bramus!

下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。

はじめに

先日、SNS(X, Mastodon)で、「CSSの宣言がIACVTのときにデベロッパーツールがフラグを立てる必要があるか」についてアンケートを実施しました。そのアンケートではYes, Noの他に、IACVTとは何ですか?も加えました。

そのアンケートの結果は、多くの人が「IACVTとは何ですか?」を選びました。この記事ではIACVT(Invalid At Computed Value Time)についてを解説しようと思います。

CSSにおける無効な宣言(Invalid Declarations)とは

CSSでは、すべての(カスタムではない)プロパティは特定の型の値のみを受け入れます。たとえば、background-colorプロパティ(W3Cの仕様)は、<color>型(W3Cの仕様)の値のみを受け入れるように定義されています。

Name(名前):
background-color
Value(値):
<color>
Initial(初期値):
transparent
Applies to(適用対象)
all elements(すべての要素)
Inherited(継承)
no(されない)
Percentages(百分率)
N/A(受容しない)
Computed value(算出値)
computed color(算出色)
Canonical order(正準的順序)
per grammar(文法に従う)
Animation type(アニメーション型)
by computed value(算出値の型による)

定義では「初期値は何か」「このプロパティは継承されるのか」「アニメーションで使用した場合はどのように動作するのか」などが分かります。

たとえば、background-colorプロパティに<length>である20pxのような値を設定すると、その宣言は無効なプロパティ値が含まれているため破棄されます。

このような無効な宣言は、CSS値の処理プロセスの非常に早い段階で破棄されます。宣言された値を収集するときに、ユーザーエージェント(ブラウザの仕様用語)はすでに構文的に無効な宣言をフィルタで除外します。

以下は、CSS Cascading and Inheritance Level 5より。

宣言された値を見つけるために、実装はまず各要素に適用されるすべての宣言を識別する必要があります。次の場合、宣言は要素に適用されます。

  • 現在このドキュメントに適用されているスタイルシートに属している。
  • falseの条件を含む条件付きルールにより除外されていない。
  • セレクタが要素に一致するスタイルルールに属している(必要ならばスコープを考慮)。
  • 構文として有効である。宣言のプロパティが既知のプロパティ名であり、宣言の値がそのプロパティの構文と一致している。

補足:
<color>型自体はいくつかのサブタイプに分割されているため、多数の可能な値を受け入れます。16進数カラー、名前付きカラー、currentcolorキーワード、カラー関数(rgb(), oklab()など)、light-dark()関数などを受け付けるように定義されています。

CSSにおける値の処理

スタイルシートで値を宣言してから、要素が実際にどの値を使用するかを知るまでの間に、複数のステップによる計算が行われています。このプロセスは、値の処理(Value Processing)として知られています。

以下は、CSS Cascading and Inheritance Level 5より。

  1. 最初に、要素に適用されているすべての宣言された値が、各要素の各プロパティについて収集されます。要素に適用される宣言値が0個または多数である場合もあります。
  2. カスケード法により、カスケードされた値が生成されます。どの要素にもカスケード値は1つのプロパティごとに最大1つです。
  3. デフォルト法により、指定された値が得られます。すべての要素には、プロパティごとに指定値は1つだけです。
  4. 値の依存関係を解決すると、計算された値が得られます。すべての要素には、プロパティごとに1つの計算値が含まれます。
  5. ドキュメントをフォーマットすると、使用される値が得られます。要素は指定されたプロパティに対して、そのプロパティが要素に適用される場合にのみ使用値を持ちます。
  6. 最後に、使用値は表示環境による制約に基づいて、実際の値に変換されます。使用値と同様に、そのプロパティが要素に適用される場合に限られます。

例: 1.2emから14pxまでの6ステップ

たとえば、下記のCSSで見てましょう。

値の処理プロセスは次のように機能します。

Declared Value(宣言値)
font-sizeには、16px1.2emの2つの宣言値があり、互いに競合しています。
Cascaded Value(カスケード値)
カスケードが実行された結果、勝利した宣言はfont-size: 1.2em;になります。したがって、カスケード値は1.2emになります。
Specified Value(指定値)
font-sizeプロパティにはデフォルト値がないため、指定値は1.2emになります。
Computed Value(計算値)
計算値が計算されると、ドキュメントをレイアウトしたり、負荷の高い操作を実行したりすることなく、指定値を可能な限り使用します。一般的には、相対値を計算すると相対値が絶対化されるため、たとえば1.2em14.1pxに計算されます。
Used Value(使用値)
実行すべき計算がないため、使用値も14.1pxになります。
Actual Value(実際値)
ユーザーエージェントまたはハードウェアに応じて、たとえばフルピクセルしか描画できないデバイでは、14.1pxは実際値の14pxになる可能性があります。

W3Cの仕様には、特定の値がどのように処理されるかの例が掲載されています。

カスタムプロパティの場合

カスタムプロパティとは、言語に変数を持つことに対するCSSの答えです。CSSにおける変数は一度宣言したら決して変更できない静的なトークンではなく、カスケードの一部を担う実際のプロパティです。特定の要素で値を変更したり、メディアクエリに応答させたりすることができます。

CSSの宣言でカスタムプロパティを使用するには、var()関数を使用します。

var()関数は、計算値の時点で代入されます。

Declared Value(宣言値)
var(--color)
Cascaded Value(カスケード値)
var(--color)
Specified Value(指定値)
var(--color)
Computed Value(計算値)
greenrgb(0, 128, 0)
Used Value(使用値)
rgb(0, 128, 0)
Actual Value(実際値)
rgb(0, 128, 0)

このCSSはご想像通り、background-colorgreenにします。

補足:
greenは、CSS Color Module Level 4の仕様に従って、rgb(0, 128, 0)に解決されることに注意してください。

sRGBカラーが名前付きカラーとして明示的に設定された場合、計算されて使用される値は対応するsRGBカラーと指定されたアスファチャンネル([0, 1]にクランプされた後)とペアになり、指定されていない場合のデフォルトは不透明になります。

IACVT: 無効な値を含む有効な宣言

プロパティ: var(--varname)という形式の宣言はそれ自体は有効ですが、var()関数に代入されると意味のない宣言になってしまう可能性があります。

仕様から次の例を見てましょう。

値を処理すると、次のようになります。

Declared Value(宣言値)
var(--not-a-color)
Cascaded Value(カスケード値)
var(--not-a-color)
Specified Value(指定値)
var(--not-a-color)
Computed Value(計算値)
16px
Used Value(使用値)
??
Actual Value(実際値)
??

計算値の16pxには問題があります。なぜなら16px<color>値しか受け入れないbackground-colorの有効な値ではないからです。

従って、この宣言はInvalid at Computed-Value Time、略してIACVTとみなされます。

以下は、CSS Custom Properties for Cascading Variables Module Level 1より。

無効な値を保証されたカスタムプロパティを参照するvar()が宣言に含まれている場合、または有効なカスタムプロパティを使用しているがvar()を代入した後の値が無効である場合、宣言は計算値時点で無効になる可能性があります。

補足:
念のために言っておくと、ここで表示される無効保証値はinitialです。しかし、それはまた別の記事で解説しようと思います。

IACVTの結果

CSSの宣言がIACVTとみなされた場合、他の宣言はカスケード値の時点ですでに破棄されているため、他の宣言にフォールバックされることはありません。

代わりに、無効な値は別の値に置き換えられます。実際に何が起こるかは、プロパティの型によって異なります。

  • プロパティが未登録のカスタムプロパティまたはユニバーサル構文を持つ登録済みのカスタムプロパティの場合、無効が保証された値に置き換えられます。
  • それ以外の場合はすべて値はunsetになり、その結果はプロパティの継承が許可されているかどうかによって異なります。
    • プロパティの継承が許可されている場合は、inheritとして動作し、計算値から親を継承します。
    • プロパティの継承が許可されていない場合は、initialとして動作し、初期値に戻ります。

前述のCSSを見てましょう。

下記のように展開されます。

  1. カスケード値はvar(--not-a-color)です。background-color: red;宣言は役に立たないので、破棄されます。
  2. background-color: var(--not-a-color);は、計算値の時点でIACVTとしてマークされます。
  3. var(--not-a-color)はIACVTだったので、unsetに置き換えられます。
  4. background-colorは継承されないため、unsetは初期値として動作します。
  5. 計算値は、background-colorの初期値としてtransparentになります。

実際の動作は、デモページでご覧ください。
背景にはredではなく、transparentが適用されています。

See the Pen
CSS IACVT Example
by coliss (@coliss)
on CodePen.

補足:
もし、background-color: 20px;を直接(つまり、カスタムプロパティを使用せずに)記述した場合、その宣言は無効であるため、単に破棄され、背景にはredが適用されます。

終わりに

CSSには、要素に適用される実際の値を決定するための値処理(Value Processing)と呼ばれるプロセスがあります。このプロセスではcolor: 20px;のような無効な宣言は事前にフィルタリングされて除外されます。

color: var(--not-a-color);のようなカスタムプロパティを使用した宣言は、最初は通過することができますが、代入された値がプロパティが期待する型と一致しない場合は除外されます。

無効化は計算値の時点で発生するため、宣言には「計算値の時点で無効(IACVT)」というフラグが立てられます。

IACVTが発生すると、無効な値は対象となるプロパティに応じて、無効保証値またはunset値に置き換えられます。

sponsors

top of page

©2024 coliss