1. はじめに
このセクションは規範的ではありません。
注: 現時点では、この仕様はカスタム関数のみを定義しており、 これはCSS値のレベルで動作します。 今後、スタイルルールレベルで動作する「ミックスイン」も定義される予定です。
カスタムプロパティは、著者が便利で時に複雑な値を 一箇所で定義し、 スタイルシート全体で再利用できる強力な機能です。 文書全体やメディアクエリ、その他の条件によって値を変更できるため、 柔軟かつレスポンシブな設計が可能です。
しかし、カスタムプロパティの値は定義された時点で固定されており、 その後変更するには定義を完全に上書きするしかありません。 例えば --shadow: 2px 2px var(--shadow-color) という宣言では --shadow-color の値は宣言された要素のものが使われ、 後で子孫要素で --shadow-color を変更しても その要素の --shadow の値は変わりません。 つまり --shadow が定義された時点の影の色を常に使い続けます。 この仕組みは、複合変数を多用する著者にとって混乱の元となりがちです。
カスタム関数は カスタムプロパティと同じ強力さを持ちつつ、 パラメータ化されています。 カスタムプロパティ定義と同様の柔軟性と条件分岐が可能ですが、 他のカスタムプロパティの値や (または明示的な引数として)使用時点で値を受け取ります。 例えば、--shadow カスタムプロパティの代わりに --shadow() カスタム関数を定義し、 次のようにできます:
@function --shadow ( --shadow-color <color> : inherit) { /* --shadow-color 引数が渡されていない、 または <color> として正常にパースできない場合、 代わりに要素の --shadow-color *プロパティ* を使用する */ /* var(--shadow-color) は --shadow-color パラメータを参照するが、 カスタムプロパティではなく、通常通りフォールバック値も使える */ result:2 px 2 px var ( --shadow-color, black); } .foo{ --shadow-color : blue; box-shadow : --shadow (); /* 青い影が生成される */ /* あるいは単に */ box-shadow:--shadow ( blue); }
2. カスタム関数の定義
カスタム関数は、 高度なカスタムプロパティ と考えることができ、 一つの固定値で置換されるのではなく、 関数パラメータや 呼び出し時点でのカスタムプロパティの値に基づいて 置換値を計算します。 カスタムプロパティが値の置換に使うvar()構文ではなく、 カスタム関数は<dashed-function>構文で呼び出し、 引数として追加の値も渡すことができます。
@function --negative ( --value) { result : calc ( -1 *var ( --value)); }
この関数は、宣言内で --negative() として参照できます:
html{ --gap : 1 em ; padding : --negative ( var ( --gap)); /* または値を直接渡す場合: */ padding:--negative ( 1 em ); }
<dashed-function>は任意置換関数であり、 var()と同様です。 プロパティ値に含まれるとパース時に有効とみなされ、 算出値の時点でのみ評価・パースされます。 任意置換が行われた後に評価されます。
2.1. @function規則
@function規則はカスタム関数を定義し、 名前、 パラメータのリスト、 関数本体、 オプションとして戻り値型(構文定義で記述)を持ちます。
各関数パラメータは、 名前(<custom-property-name>)、 オプションとしてパラメータ型(構文定義で記述)、 オプションとしてデフォルト値で構成されます。
<@function> = @function <function-token> <function-parameter>#? ) [ returns <css-type> ]? { <declaration-rule-list> } <function-parameter> = <custom-property-name> <css-type>? [ : <declaration-value> ]? <css-type> = <syntax-component> | <type()> <type()> = type( <syntax> )
2.1.1. 関数の前文
<function-token>生成規則は <dashed-ident>と同様、 2つのハイフン(U+002D HYPHEN-MINUS)で始まらなければならず、 そうでなければ定義は無効です。
生成されるカスタム関数の名前は<function-token>の名前で決まり、 オプションの関数パラメータは <function-parameter> の値(デフォルトは空集合)、 オプションの戻り値型は returnsキーワードの後の<css-type> (デフォルトはtype(*))で決まります。
@function --foo ( --a <length>) { /* ... */ } @function --foo ( --a <color>) { /* ... */ } @function --foo ( --a <length>+) { /* ... */ }
ただし、 <syntax>が<syntax-combinator>を必要とする場合は type()関数で包む必要があります:
@function --foo ( --atype ( <number> | <percentage>)) { /* ... */ }
@function規則の名前はツリースコープ名です。 同じ名前の@functionが複数存在する場合、 強いカスケードレイヤーのルールが優先され、 同じレイヤー内では後に定義されたものが勝ちます。
関数パラメータ内に 同じ<custom-property-name>が複数ある場合、 @function規則は無効です。
2.1.2. 関数本体
@function規則の本体には 条件付きグループ規則(例えば@media)を記述できます。 さらに、以下の記述子も受け付けます:
未知の記述子は無効として無視されますが、 @function規則自体は無効になりません。
2.2. result記述子
名称: | result |
---|---|
対象: | @function |
値: | <declaration-value>? |
初期値: | n/a(本文参照) |
result記述子は 関数評価時の カスタム関数の結果を定義します。 var()関数を使うことで 関数パラメータ、ローカル変数 や他のカスタム関数も<dashed-function>経由で参照できます。
result記述子自体には型はありませんが、 その解決された値は 置換時に <dashed-function>の型チェックが行われます。
2.3. 引数とローカル変数
このセクションは非規範です。
カスタム関数 の関数本体内では、 var()関数でローカル変数(関数本体内で定義されたカスタムプロパティ)、 関数パラメータ (関数に渡された値やデフォルト値)、 呼び出し元(要素や他のカスタム関数)で定義された カスタムプロパティ にアクセスできます。
この順序で、同名の場合は前のものが「勝ち」ます。例えば ローカル変数に --foo があれば、var(--foo) はその ローカル変数で置換されます。 引数や外部のカスタムプロパティは参照しません。 ただし他の値も参照は可能です。 ローカル変数 --foo を initial にすると パラメータの --foo を参照し、 inherit にすると 呼び出し元の --foo カスタムプロパティを参照します。
@function --outer ( --outer-arg) { --outer-local : 2 ; result : --inner (); } @function --inner () returns <number>{ result : calc ( var ( --outer-arg) +var ( --outer-local)); } div{ z-index : --outer ( 1 ); /* 3 */ }
同様に、カスタムプロパティも暗黙的に利用できます:
@function --double-z () returns <number>{ result : calc ( var ( --z) *2 ); } div{ --z : 3 ; z-index : --double-z (); /* 6 */ }
ただし関数パラメータは カスタムプロパティ を「シャドウ」し、 ローカル変数は両方を「シャドウ」します:
@function --add-a-b-c ( --b, --c) { --c : 300 ; result : calc ( var ( --a) +var ( --b) +var ( --c)); /* 呼び出し元のカスタムプロパティ --a、 関数パラメータ --b、 ローカル変数 --c をそれぞれ使う */ } div{ --a : 1 ; --b : 2 ; --c : 3 ; z-index : --add-a-b-c ( 20 , 30 ); /* 321 */ }
3. カスタム関数の利用
カスタムプロパティの値を var()で 他のプロパティ値に代入できるように、 カスタム関数の評価結果も プロパティ値に <dashed-function>で代入できます。
<dashed-function>は、関数表記で、関数名が2つのハイフン(U+002D HYPHEN-MINUS)で始まります。 その引数文法は以下の通りです:
<dashed-function> = --*( <declaration-value>#? )
<dashed-function>は var() が許可されている場所でのみ使用できます。
あるプロパティに<dashed-function>が1つ以上含まれる場合、 そのプロパティの文法全体はパース時に有効とみなされます。 算出値時点で 全ての<dashed-function>を 置換し、 その後プロパティ文法と照合します。
注: カスタム関数の本体内では var() の解決結果が <dashed-function>が使われている要素上での挙動と異なる場合があります。 詳細は§ 3.1 カスタム関数の評価を参照してください。
<dashed-function>は何らかのコンテキストで評価されます。 例えば要素のプロパティ値 (または最終的に要素のプロパティとして扱われる記述子、 @keyframesなど)、 または他のカスタム関数の 関数本体内記述子(仮想要素上)などです。 いずれの場合も 呼び出しコンテキストがあり、 その<dashed-function>を含むプロパティ/記述子名と、 そのプロパティ/記述子が適用される要素(または仮想要素)を持ちます。
呼び出しコンテキストは <dashed-function>の評価が カスタム関数内で ネストされるごとに積み重なり、 スタックの根本の要素が ルート要素です。
-
functionを dashed functionの名前でtree-scoped referenceとして参照し取得する。 その名前がなければ保証された無効値を返す。
-
各argについて 任意置換関数を arg内で置換し、 その結果でargを置き換える。
注: これにより(全てまたは一部の)引数が保証された無効値となる場合があり、 その場合はデフォルト値(あれば)が適用される。
-
dashed functionが要素のプロパティに置換される場合、 calling contextとしてその要素とプロパティを持つ呼び出しコンテキストを使う。
それ以外の場合は、仮想要素上の記述子に置換され、 他のカスタム関数を評価中である。 この場合は仮想要素と記述子を持つ呼び出しコンテキストを使う。
-
カスタム関数の評価を function、arguments、calling contextで行い、 その結果値の等価トークン列を返す。
{}
で包むことで単一の引数として渡せます:
@function --max-plus-x ( --list, --x) { result : calc ( max ( var ( --list)) +var ( --x)); } div{ width : --max-plus-x ({ 1 px , 7 px , 2 px }, 3 px ); /* 10px */ }
--foo ()
は自身と循環しています:
@function --foo ( --x) { result : --foo ( 10 ); }
同様に
も自身と循環していますが、
ローカル変数 --x
は result で参照されていません:
@function --bar () { --x : --bar (); result : 1 ; }
一方、下記の
は自身と循環していません。
result
宣言が
ルール内で評価されないためです:
@function --baz ( --x) { @media ( unknown-feature) { result : --baz ( 42 ); } result:1 ; }
--baz ()
は循環しません:
var ( --x)
や var ( --y)
が関数本体に現れても、
それぞれ関数パラメータと
ローカル変数を参照しています。
カスタムプロパティ --x
と --y
は両方 --baz ()
を参照しますが問題ありません。
これらカスタムプロパティは --baz ()
の中で参照されていません。
@function --baz ( --x) { --y : 10 px ; result : calc ( var ( --x) +var ( --y)); } div{ --x : --baz ( 1 px ); --y : --baz ( 2 px ); width : var ( --x); /* 11px */ height:var ( --y); /* 12px */ }
3.1. カスタム関数の評価
カスタム関数は、 基本的にはその関数本体を仮想要素へのスタイルルールとして 適用したかのように評価され、 通常通りスタイルを解決し、 その仮想要素上のresult記述子の値を返す。 仮想要素は呼び出しコンテキストの子であるかのように 全てのカスタムプロパティ値を「継承」し、 同名の場合は関数パラメータが 「継承」したカスタムプロパティより優先される。
-
substitution context を «"function", custom function» を含む 置換コンテキスト とする。
注: tree-scoping のため、 同じ関数名がスタック上で複数回現れることがあり、 異なる カスタム関数 を参照する場合がある。 そのため、カスタム関数自体を 置換コンテキストに含める(名前だけでなく)。
-
このアルゴリズムの残りの処理の間、substitution context を ガード する。 substitution context が 循環としてマークされている場合、 保証された無効値を返す。
-
もし arguments の項目数が custom function の 関数パラメータ の数より多い場合、 保証された無効値を返す。
-
registrations を空の カスタムプロパティ登録集合とする。
-
custom function の各 関数パラメータについて、 パラメータ名・パラメータ型・inheritフラグtrue・初期値なしで カスタムプロパティ登録を作成し、 registrations に追加する。
-
もし custom function に 戻り値型 があれば、 名前 "return"(通常の登録名ルール違反)、構文 return type、inheritフラグfalse・初期値なしで カスタムプロパティ登録を作成し、 registrations に追加する。
-
argument rule を空の スタイルルールとする。
-
custom function の各 関数パラメータについて:
-
resolve function styles を custom function・argument styles・registrations・calling context で呼び出し、 結果を argument styles とする。
-
registrations の各 カスタムプロパティ登録について、 初期値を argument styles の対応値に設定し、 構文を universal syntax definition に設定し、 body rule の先頭に カスタムプロパティ(プロパティ名と値は argument styles より)を追加する。
-
resolve function styles を custom function・body rule・registrations・calling context で呼び出し、 結果を body styles とする。
-
もし substitution context が 循環置換コンテキストとしてマークされていれば、 保証された無効値を返す。
注: ネストした 任意置換関数が、 ステップ2以降で substitution context を 循環としてマークすることがある(例えば result の解決時など)。
-
body styles の result プロパティの値を返す。
-
仮想要素 el を作成し、calling context の要素の子として振る舞わせる。el は featureless であり、 カスタムプロパティと result 記述子のみが適用される。
-
rule を el に 指定値段階で適用する。以下の変更あり:
-
registrations の カスタムプロパティ登録のみ可視。 他の カスタムプロパティは未登録扱い。
-
カスタムプロパティでは、CSS全域キーワード initial および inherit は通常通り動作。 その他の CSS全域キーワードは 保証された無効値となる。
注: initial は 関数パラメータから作られたカスタムプロパティ登録を参照し、 プロパティを渡した値に「リセット」できる。 inherit は 呼び出しコンテキストの要素から継承する。\
result では、すべての CSS全域キーワードは未解決のまま残る。
注: 例えば result: inherit は <dashed-function> を inherit キーワードとして評価させる(var(--unknown, inherit) に類似)。
-
カスタムプロパティ prop について、 そのプロパティの プロパティ置換時には 置換コンテキストにも custom function を含める。 つまり substitution context は «"property", prop の名前, custom function» となる。
注: 動的スコープのため、 同じプロパティ名がスタック上で複数回現れることがあり、 異なる カスタムプロパティ を参照する場合がある。 そのため カスタム関数自体も 置換コンテキストに含める(名前だけでなく)。
-
-
全ての カスタムプロパティと el 上の result "プロパティ" の 算出値を決定する。 CSS Properties and Values API 1 § 2.4 Computed Value-Time Behavior に従うが、前ステップの変更と以下を適用する:
-
カスタムプロパティへの参照(通常通り el 上の値を使う)と 数値・パーセンテージ(カスタムプロパティ内では通常通り未解決)の他は、 通常はスタイリング中の要素を参照する値も calling context の ルート要素を参照する。
注: 例えば、プロパティ内の attr() や、ルール内の @container クエリなど。
-
-
el のスタイルを返す。
4. カスタム関数の実行モデル
他のCSSと同様に、カスタム関数は宣言型モデルに従います。
ローカル変数記述子 および result記述子は 任意の順序で現れ、 複数回指定することもできます。 その場合、後に現れる宣言が前の宣言よりも優先されます。
@function --circle-area ( --r) { result : calc ( pi *var ( --r2)); --r2 : var ( --r) *var ( --r); }
ローカル変数記述子は 参照より前でも後でも現れてもかまいません。
4.1. 条件付きルール
条件付きグループ規則が @function 内に現れる場合、 入れ子グループ規則となります。 ただし、入れ子グループ規則内では @function で許可されている記述子のみが使用できます。
条件付きグループ規則は @function 内でも 通常通り処理されます。 条件が真の場合、その規則の内容がその場所にあるかのように動作し、 そうでない場合は何も存在しないかのように動作します。
@function --suitable-font-size () { result : 16 px ; @media ( width >1000 px ) { result : 20 px ; } }
result記述子の値は
メディアクエリの条件が真の場合
、
そうでない場合は
です。
@function --suitable-font-size () { @media ( width >1000 px ) { result : 20 px ; } result:16 px ; }
上記の例では、result記述子の値は常に
となります。
@function --suitable-font-size () { --size : 16 px ; @media ( width >1000 px ) { --size : 20 px ; } result:var ( --size); }
5. CSSOM
5.1. CSSFunctionRule
インターフェース
CSSFunctionRule
インターフェースは @function 規則を表します。
[Exposed =Window ]interface :
CSSFunctionRule CSSGroupingRule {readonly attribute CSSOMString name ;sequence <FunctionParameter >();
getParameters readonly attribute CSSOMString returnType ; };
name
, 型 CSSOMString、readonly- カスタム関数の名前。
returnType
, 型 CSSOMString、readonly- カスタム関数の 構文文字列として表される戻り値型。
カスタム関数に戻り値型がない場合は
を返します。"type(*)"
dictionary {
FunctionParameter required CSSOMString ;
name required CSSOMString ;
type CSSOMString ?; };
defaultValue
- name
- 関数パラメータの名前。
- type
- 関数パラメータの型。
構文文字列として表されるか、
パラメータに型がない場合は
。"type(*)" - defaultValue
- デフォルト値。 引数にデフォルト値がなければ `null`。
宣言は @function 規則内で直接指定できますが、
CSSOMではそのまま表現はされません。
代わりに、連続した宣言の区間は
CSSFunctionDeclarations
規則でラップされているかのように現れます。
注: これは @function 規則内の「先頭」の宣言(他の入れ子規則よりも前に現れるもの)にも適用されます。
@function --bar () { --x : 42 ; result : var ( --y); @media ( width >1000 px ) { /* ... */ } --y:var ( --x); }
上記はCSSOMでは以下のように現れます:
@function --bar () { /* CSSFunctionDeclarations { */ --x:42 ; result : var ( --y); /* } */ @media ( width >1000 px ) { /* ... */ } /* CSSFunctionDeclarations { */ --y:var ( --x); /* } */ }
-
文字列
と1つの半角スペース (U+0020)。"@function" -
serialize an identifier をカスタム関数名に対して行い、 左括弧 (U+0028) を続ける。
-
serialize a function parameter を カスタム関数の parameters全てに行い、
(コンマ+スペース)で結合する。", " -
右括弧 (U+0029) を1つ。
-
カスタム関数に 戻り値型があり、 その戻り値型が ユニバーサル構文定義 ("*") でない場合:
-
半角スペース (U+0020)、文字列
、 半角スペース (U+0020)。"returns" -
serialize a CSS type をその 型に行い、 半角スペース (U+0020) を続ける。
-
-
左波括弧 (U+007B)、半角スペース (U+0020)。
-
cssRules内の各ルールにserialize a CSS ruleを行い、 空文字列は除外し、 半角スペースで結合する。
注: serialize a CSS ruleは 空の
CSSFunctionDeclarations
ルールを直列化する際に空文字列を返すことがある。 -
半角スペース (U+0020)、右波括弧 (U+007D) を1つ。
-
serialize an identifier を 関数パラメータ名に対して行う。
-
関数パラメータに 型があり、 その型が ユニバーサル構文定義でない場合:
-
半角スペース (U+0020)、serialize a CSS type をその 型に行う。
-
-
-
コロン (U+003A)、半角スペース (U+0020)、 serialize a CSS value をその値に行う。
-
-
もし <css-type> が単一の <syntax-component> なら、 対応する構文文字列を返す。
-
それ以外の場合、以下を連結して返す:
-
文字列
("type"+左括弧)。"type(" -
対応する構文文字列。
-
文字列
(右括弧)。")"
-
5.2.
CSSFunctionDeclarations
インターフェース
CSSFunctionDeclarations
インターフェースは
宣言の連続区間を
@function 規則内で表します。
[Exposed =Window ]interface :
CSSFunctionDescriptors CSSStyleDeclaration {attribute [LegacyNullToEmptyString ]CSSOMString ; }; [
result Exposed =Window ]interface :
CSSFunctionDeclarations CSSRule { [SameObject ,PutForwards =cssText ]readonly attribute CSSFunctionDescriptors style ; };
style
属性は
その規則について CSSFunctionDescriptors
オブジェクトを返し、以下のプロパティを持つ:
- computed flag
-
未設定
- readonly flag
-
未設定
- declarations
- parent CSS rule
- owner node
-
null
CSSFunctionDeclarations
規則は CSSNestedDeclarations
と同様に、
serialize される際は
その 宣言ブロックが直接 serialize されたかのように扱われます。
6. プライバシーへの配慮
本仕様で定義される構造は、CSS内でのみ定義・利用されるものであり、新たな情報は公開しません。
7. セキュリティへの配慮
本仕様に対して提出された問題はありません。