> referencing a [=custom function=]
which is part of a cycle
makes the containing [=declaration=] [=invalid at computed-value time=].
Note: Cycles are disallowed even through branches that are not taken
during execution.
In the following,
--foo()
is in a cycle with itself,
even though the media query never evaluates to "true":
@function --foo(--x) {
@media (unknown-feature) {
result: --foo(42);
}
result: 1;
}
Similarly,
--bar()
is in a cycle with itself,
even though the local variable
--x
is never referenced:
@function --bar() {
--x: --bar();
result: 1;
}
The function
--baz()
is not in a cycle in the example below:
even though
var(--x)
and
var(--y)
appear in the function body,
they refer to a [=function parameter=] and [=local variable=], respectively.
The [=custom properties=]
--x
and
--y
both reference
--baz()
, but that's fine:
those [=custom properties=] are not referenced within
--baz()
.
@function --baz(--x) {
--y: 10px;
result: calc(var(--x) + var(--y));
}
div {
--x: --baz(1px);
--y: --baz(2px);
width: var(--x); /* 11px */
height: var(--y); /* 12px */
}
Execution Model of Custom Functions {#execution-model}
======================================================
Like the rest of CSS,
[=custom functions=] adhere to a declarative model.
The [=local variable=] descriptors
and '@function/result' descriptor
can appear in any order,
and may be provided multiple times.
If this happens, then declarations appearing later win over earlier ones.
@function --mypi() {
result: 3;
result: 3.14;
}
The value of the '@function/result' descriptor of
--mypi
is
3.14
.
@function --circle-area(--r) {
result: calc(pi * var(--r2));
--r2: var(--r) * var(--r);
}
[=Local variable=] descriptors may appear before or after
they are referenced.
Conditional Rules {#conditional-rules}
--------------------------------------
A [=conditional group rule=] that appears within a ''@function''
becomes a [=nested group rule=],
with the additional restriction
that only descriptors allowed within ''@function''
are allowed within the [=nested group rule=].
[=Conditional group rules=] within ''@function''
are processed as normal,
acting as if the contents of the rule were present
at the [=conditional group rule=]'s location
when the condition is true,
or acting as if nothing exists at that location otherwise.
@function --suitable-font-size() {
result: 16px;
@media (width > 1000px) {
result: 20px;
}
}
The value of the '@function/result' descriptor
is
20px
if the media query's condition is true,
and
16px
otherwise.
Note that due to the execution model,
"early return" is not possible within a ''@function'':
@function --suitable-font-size() {
@media (width > 1000px) {
result: 20px;
}
result: 16px;
}
The value of the '@function/result' descriptor
is always
16px
in the above example.
[=Local variables=] are also valid within conditional rules:
@function --suitable-font-size() {
--size: 16px;
@media (width > 1000px) {
--size: 20px;
}
result: var(--size);
}
CSSOM {#cssom}
==============
The {{CSSFunctionRule}} Interface {#the-function-interface}
-----------------------------------------------------------
The {{CSSFunctionRule}} interface represents a ''@function'' rule.
[Exposed=Window]
interface CSSFunctionRule : CSSGroupingRule {
readonly attribute CSSOMString name;
sequence<FunctionParameter> getParameters();
readonly attribute CSSOMString returnType;
};
- name
-
The name of the [=custom function=].
- returnType
-
The [=custom function/return type=] of the [=custom function=],
represented as a [[css-properties-values-api-1#syntax-strings|syntax string]].
If the [=custom function=] has no return type,
returns
"type(*)"
.
dictionary FunctionParameter {
required CSSOMString name;
required CSSOMString type;
CSSOMString? defaultValue;
};
- name
-
The name of the [=function parameter=].
- type
-
The [=parameter type|type=] of the [=function parameter=],
represented as a [[css-properties-values-api-1#syntax-strings|syntax string]],
or
"type(*)"
if the [=function parameter|parameter=] has no type.
- defaultValue
-
The [=default value=] of the [=function parameter=],
or `null` if the argument does not have a default.
While declarations may be specified directly within a ''@function'' rule,
they are not represented as such in the CSSOM.
Instead, consecutive segments of declarations
appear as if wrapped in {{CSSFunctionDeclarations}} rules.
Note: This also applies to the "leading" declarations in the ''@function'' rule,
i.e those that do not follow another nested rule.
@function --bar() {
--x: 42;
result: var(--y);
@media (width > 1000px) {
/* ... */
}
--y: var(--x);
}
The above will appear in the CSSOM as:
@function --bar() {
/* CSSFunctionDeclarations { */
--x: 42;
result: var(--y);
/* } */
@media (width > 1000px) {
/* ... */
}
/* CSSFunctionDeclarations { */
--y: var(--x);
/* } */
}
To
serialize a CSSFunctionRule,
return the concatenation of the following:
1. The string
"@function"
followed by a single SPACE (U+0020).
2. The result of performing
serialize an identifier
on the name of the [=custom function=],
followed by a single LEFT PARENTHESIS (U+0028).
4. The result of [=serialize a function parameter=]
on each of the [=custom function's=] [=function parameter|parameters=],
all joined by
", "
(COMMA U+002C, followed by a single SPACE U+0020).
5. A single RIGHT PARENTHESIS (U+0029).
6. If the [=custom function=] has [=custom function/return type=],
and that [=custom function/return type=]
is not the [=universal syntax definition=] ("*"):
* A single SPACE (U+0020),
followed by the string
"returns"
,
followed by a single SPACE (U+0020).
* The result of performing [=serialize a CSS type=]
on that [=custom function/return type|type=],
followed by a single SPACE (U+0020).
7. A single LEFT CURLY BRACKET (U+007B),
followed by a SPACE (U+0020).
8. The result of performing [=serialize a CSS rule=]
on each rule in cssRules,
filtering out empty strings,
all joined by a single SPACE (U+0020).
Note: [=Serialize a CSS rule=] can return an empty string
when serializing an empty {{CSSFunctionDeclarations}} rule.
9. A single SPACE (U+0020),
followed by a single RIGHT CURLY BRACKET (U+007D).
To
serialize a function parameter,
return the concatenation of the following:
1. The result of performing
serialize an identifier
on the name of the [=function parameter=].
2. If the [=function parameter=] has a [=parameter type|type=],
and that [=parameter type|type=]
is not the [=universal syntax definition=]:
* A single SPACE (U+0020),
followed by the result of performing [=serialize a CSS type=]
on that [=parameter type|type=].
3. If the [=function parameter=] has a [=default value=]:
* A single COLON (U+003A),
followed by a single SPACE (U+0020),
followed by the result of performing [=serialize a CSS value=]
on that value.
To serialize a CSS type,
return the concatenation of the following:
1. If the <> consists of a single <>,
return the corresponding [[css-properties-values-api-1#syntax-strings|syntax string]].
2. Otherwise,
return the concatenation of the following:
* The string "type("
,
i.e. "type"
followed by a single LEFT PARENTHESIS (U+0028).
* The corresponding [[css-properties-values-api-1#syntax-strings|syntax string]].
* The string ")"
,
i.e. a single RIGHT PARENTHESIS (U+0029).
The {{CSSFunctionDeclarations}} Interface {#the-function-declarations-interface}
--------------------------------------------------------------------------------
The {{CSSFunctionDeclarations}} interface represents a run
of consecutive [=declarations=] within a ''@function'' rule.
[Exposed=Window]
interface CSSFunctionDescriptors : CSSStyleDeclaration {
attribute [LegacyNullToEmptyString] CSSOMString result;
};
[Exposed=Window]
interface CSSFunctionDeclarations : CSSRule {
[SameObject, PutForwards=cssText] readonly attribute CSSFunctionDescriptors style;
};
The style attribute
must return a {{CSSFunctionDescriptors}} object for the rule,
with the following properties:
: [=CSSStyleDeclaration/computed flag=]
:: Unset
: [=CSSStyleDeclaration/readonly flag=]
:: Unset
: [=CSSStyleDeclaration/declarations=]
:: The declared declarations in the rule, in [=specified order=].
This includes any [=local variables=].
: [=CSSStyleDeclaration/parent CSS rule=]
:: [=this=]
: [=CSSStyleDeclaration/owner node=]
:: Null
The {{CSSFunctionDeclarations}} rule, like {{CSSNestedDeclarations}},
[=serialize a CSS rule|serializes=] as if its [=CSS declaration block|declaration block=]
had been [=serialize a CSS declaration block|serialized=] directly.
Privacy Considerations {#privacy}
===============================================
The constructs defined by this specification
are defined and used entirely within CSS;
they expose no new information.
Security Considerations {#security}
===============================================
No issues have been opened against this specification.