<pre class='metadata'>
Title: CSS Custom Functions and Mixins Module Level 1
Shortname: css-mixins
Level: 1
Status: ED
Prepare for TR: no
Work Status: Exploring
Group: CSSWG
ED: https://drafts.csswg.org/css-mixins/
TR: https://www.w3.org/TR/css-mixins-1/
Editor: Miriam E. Suzanne, Invited Expert, http://miriamsuzanne.com/contact, w3cid 117151
Editor: Tab Atkins-Bittner, Google, http://xanthir.com/contact/, w3cid 42199
Abstract: This module defines the ability for authors to define custom functions, acting similar to <em>parametrized</em> custom properties. They can use the full power of CSS's values and conditional rules. It also defines an early form of a similar idea for CSS rule mixins, allowing parametrized substitution of entire blocks of properties into other rules.
Default Highlight: css
Ignored Terms: cssText
WPT Path Prefix: css/css-mixins/
WPT Display: open
</pre>

<pre class=link-defaults>
spec:infra; type:dfn; text:list
spec:infra; type:dfn; for:list; text:append
spec:css-borders-4; type:property;
	text:border-width;
spec:css-cascade-5; type:dfn;
	text:inherit
	text:computed value
	text:specified value
spec:css-properties-values-api; type:dfn;
	text:supported syntax component name
	text:syntax component
spec:css-cascade-6; type:dfn;
	text:scoping limit
spec:css-syntax-3; type:dfn;
	text:declaration; for:CSS
	text:descriptor;
spec:css-values-4; type:dfn;
	text:keyword;
	text:identifier;
spec:css-values-5;
	type:dfn;
		text:invalid at computed-value time
	type:function;
		text:if()
spec:cssom-1; type:dfn; 
	text:specified order;
spec:css-conditional-5; type:at-rule;
	text:@container
</pre>

<style>
/* Put nice boxes around each algorithm. */
[data-algorithm]:not(.heading) {
	padding: .5em;
	border: thin solid #ddd; border-radius: .5em;
	margin: .5em calc(-0.5em - 1px);
}
[data-algorithm]:not(.heading) > :first-child {
	margin-top: 0;
}
[data-algorithm]:not(.heading) > :last-child {
	margin-bottom: 0;
}
[data-algorithm] [data-algorithm] {
	margin: 1em 0;
}
</style>

<!-- Big Text: intro

████ █    █▌ █████▌ ████▌   ███▌ 
 ▐▌  █▌   █▌   █▌   █▌  █▌ █▌  █▌
 ▐▌  ██▌  █▌   █▌   █▌  █▌ █▌  █▌
 ▐▌  █▌▐█ █▌   █▌   ████▌  █▌  █▌
 ▐▌  █▌  ██▌   █▌   █▌▐█   █▌  █▌
 ▐▌  █▌   █▌   █▌   █▌ ▐█  █▌  █▌
████ █▌   ▐▌   █▌   █▌  █▌  ███▌ 
-->

Introduction {#intro}
=====================

	<em>This section is not normative.</em>

	Note: At this time, this specification only defines [=custom functions=],
	which operate at the level of CSS values.
	It is expected that it will define "mixins" later,
	which are functions that operate at the style rule level.

	[=Custom properties=] give authors a lot of power
	to define useful, sometimes complex values
	in one place,
	and then re-use them across their stylesheet.
	They can vary across the document,
	or based on Media Queries or other conditionals,
	making them very flexible and responsive.

	However, their values are <em>fixed</em> at the point they're defined,
	unable to be changed except by fully overriding their previous definition:
	a ''--shadow: 2px 2px var(--shadow-color)'' declaration
	takes its ''--shadow-color'' value from the element it's declared on,
	and later changes to ''--shadow-color'' on descendant elements
	don't alter the value of ''--shadow'' for them;
	they continue to use the shadow color defined where ''--shadow'' was defined.
	This is a common source of confusion for authors
	making heavy use of composite variables like this.

	[=Custom functions=] allow authors the same power as [=custom properties=],
	but <em>parameterized</em>:
	they have the same flexibility and conditionality as a [=custom property=] definition,
	but take values from other custom properties
	(or explicitly as arguments)
	<em>at the point of use</em>.
	For example, instead of a ''--shadow'' [=custom property=],
	a ''--shadow()'' [=custom function=] could be defined instead,
	like:

	<xmp highlight=css>
	@function --shadow(--shadow-color <color> : inherit) {
		/* If --shadow-color argument isn't passed,
		   or doesn't successfully parse as a <color>,
		   try to use the --shadow-color *property*
		   from the element instead */

		/* var(--shadow-color) refers to the --shadow-color parameter,
		   rather than a custom property,
		   but can still use a fallback value as normal */
		result: 2px 2px var(--shadow-color, black);
	}

	.foo {
		--shadow-color: blue;
		box-shadow: --shadow(); /* produces a blue shadow */
		/* or just */
		box-shadow: --shadow(blue);
	}
	</xmp>

	<wpt>
		functions/function-in-media.html
		functions/local-inherit-substitution.html
		functions/local-var-substitution.html
	</wpt>

<!-- Big Text: @function

 ████▌  █████▌ █▌  █▌ █    █▌  ███▌  █████▌ ████  ███▌  █    █▌
█▌   █▌ █▌     █▌  █▌ █▌   █▌ █▌  █▌   █▌    ▐▌  █▌  █▌ █▌   █▌
█▌▐█ █▌ █▌     █▌  █▌ ██▌  █▌ █▌       █▌    ▐▌  █▌  █▌ ██▌  █▌
█▌▐█ █▌ ████   █▌  █▌ █▌▐█ █▌ █▌       █▌    ▐▌  █▌  █▌ █▌▐█ █▌
█▌ ██▌  █▌     █▌  █▌ █▌  ██▌ █▌       █▌    ▐▌  █▌  █▌ █▌  ██▌
█▌      █▌     █▌  █▌ █▌   █▌ █▌  █▌   █▌    ▐▌  █▌  █▌ █▌   █▌
 ████▌  █▌      ███▌  █▌   ▐▌  ███▌    █▌   ████  ███▌  █▌   ▐▌
-->

Defining Custom Functions {#defining-custom-functions}
======================================================

	A [=custom function=] can be thought of as an advanced [=custom property=],
	which instead of being substituted by a single fixed value,
	computes its substitution value based on [=function parameters=]
	and the value of [=custom properties=] at the point it's invoked.
	Rather than the ''var()'' syntax that [=custom properties=] use for substitution,
	[=custom functions=] are invoked by <<dashed-function>> syntax,
	allowing additional values to be passed as arguments.

	<div class='example'>
		A simple [=custom function=] to negate a value can be defined as follows:

		<pre class='lang-css'>
		@function --negative(--value) {
		  result: calc(-1 * var(--value));
		}
		</pre>

		Then, that function can be referenced with ''--negative()''
		in some declaration:

		<pre class='lang-css'>
		html {
			--gap: 1em;
			padding: --negative(var(--gap));
			/* or by passing the value explicitly, like: */
			padding: --negative(1em);
		}
		</pre>
	</div>

	<<dashed-function>>s are [=arbitrary substitution functions=],
	like ''var()''.
	Their presence in a property's value
	causes it to be assumed valid at parse time,
	and only evaluated and parsed at computed-value time,
	after [=arbitrary substitution=] has occurred.



The <dfn>@function</dfn> Rule {#function-rule}
----------------------------------------------

The ''@function'' rule defines a <dfn>custom function</dfn>,
and consists of a name,
a list of [=function parameter|parameters=],
a <dfn for="custom function">function body</dfn>,
and optionally a <dfn for="custom function">return type</dfn> described by a [=syntax definition=].

Each <dfn>function parameter</dfn> consists of a name (<<custom-property-name>>);
optionally a <dfn>parameter type</dfn>, described by a [=syntax definition=];
and optionally a <dfn>default value</dfn>.

<pre class="prod def" nohighlight>
&lt;@function> = @function <<function-token>> <<function-parameter>>#? )
	[ returns <<css-type>> ]?
{
	<<declaration-rule-list>>
}

<dfn><<function-parameter>></dfn> = <<custom-property-name>> <<css-type>>? [ : <<default-value>> ]?
<dfn><<css-type>></dfn> = <<syntax-component>> | <<@function/type()>>
<dfn><<default-value>></dfn> = <<declaration-value>>
<dfn function lt="type()" for="@function">&lt;type()></dfn> = type( <<syntax>> )
</pre>

<wpt>
	functions/at-function-parsing.html
	functions/dashed-function-named-arg.tentative.html
	functions/dashed-function-parsing.html
</wpt>

If a [=default value=] and a [=parameter type=] are both provided,
then the [=default value=] must [=CSS/parse=] successfully
according to that [=parameter type=]'s syntax.
Otherwise, the ''@function'' rule is invalid.

<h4 id=function-prelude>
The Function Prelude</h4>

The <<function-token>> production
must start with two dashes (U+002D HYPHEN-MINUS),
similar to <<dashed-ident>>,
or else the definition is invalid.

The name of the resulting [=custom function=] is given by the name of the <<function-token>>.
The optional [=function parameters=]
are given by the <<function-parameter>> values
(defaulting to an empty set),
and the optional [=custom function/return type=]
is given by the <<css-type>> following the <css>returns</css> keyword
(defaulting to ''type(*)'').

<div class='example'>
	If the <<css-type>> of a [=function parameter=] or [=custom function/return type=]
	can be described by a single <<syntax-component>>,
	then the ''type()'' function can be omitted:

	<xmp class='lang-css'>
	@function --foo(--a <length>) { /* ... */ }
	@function --foo(--a <color>) { /* ... */ }
	@function --foo(--a <length>+) { /* ... */ }
	</xmp>

	However,
	any <<syntax>> that requires a <<syntax-combinator>>
	needs to be wrapped in the ''type()'' function:

	<xmp class='lang-css'>
	@function --foo(--a type(<number> | <percentage>)) { /* ... */ }
	</xmp>
</div>

The name of a ''@function'' rule is a [=tree-scoped name=].
If more than one ''@function'' exists for a given name,
then the rule in the stronger cascade layer wins,
and rules defined later win within the same layer.

If the [=function parameters=]
contain the same <<custom-property-name>> more than once,
then the ''@function'' rule is invalid.

<h4 id=function-body>
The Function Body</h4>

The body of a ''@function'' rule accepts [=conditional group rules=],
such as ''@media''.
Additionally, it accepts the following descriptors:

	* The '@function/result' descriptor,
		which determines the result of [=evaluating a custom function|evaluating the function=].
		If no '@function/result' descriptor exists,
		the function is valid,
		but always returns the [=guaranteed-invalid value=].
	* [=Custom properties=],
		providing <dfn>local variables</dfn>.

Unknown descriptors are invalid and ignored,
but do not make the ''@function'' rule itself invalid.

The '@function/result' Descriptor {#the-result-descriptor}
----------------------------------------------------------

<pre class='descdef'>
Name: result
Value: <<declaration-value>>?
For: @function
Initial: n/a (see prose)
</pre>

The '@function/result' descriptor
defines the result of [=evaluate a custom function|evaluating=]
the [=custom function=] defined by its ''@function'' rule.
Using ''var()'' functions,
it can reference [=function parameters=], [=local variables=],
as well as other [=custom functions=] via <<dashed-function>>s.

The '@function/result' descriptor itself does not have a type,
but its [=resolve function styles|resolved=] value is type-checked
during the [=replace a dashed function|substitution=] of a <<dashed-function>>.

Arguments & Local Variables {#args}
-----------------------------------

<em>This section is non-normative.</em>

Within a [=custom function's=] [=function body=],
the ''var()'' function can access
[=local variables=]
(the [=custom properties=] defined in the [=function body=]),
[=function parameters=]
(the values passed to the function, or set to default values),
and [=custom properties=] defined at the <em>call site</em>
(an element, or another [=custom function=]).

In that list, earlier things "win" over later things of the same name--
if you have a [=local variable=] named '--foo',
''var(--foo)'' will be substituted by that [=local variable=],
not by an argument or a custom property defined outside.
The other values can still be <em>accessed</em>, however:
setting the '--foo' local variable to ''initial''
will resolve it to the '--foo' parameter,
while ''inherit'' will resolve it
to the '--foo' custom property from the call site.

<div class='example'>
	A [=custom function=] can access [=local variables=]
	and [=function parameters=]
	from functions higher up in the call stack:

	<xmp class='lang-css'>
	@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 */
	}
	</xmp>

	Similarly, [=custom properties=] are implicitly available:

	<xmp class='lang-css'>
	@function --double-z() returns <number> {
	  result: calc(var(--z) * 2);
	}
	div {
	  --z: 3;
	  z-index: --double-z(); /* 6 */
	}
	</xmp>

	But [=function parameters=] "shadow" [=custom properties=],
	and [=local variables=] "shadow" both:

	<xmp class='lang-css'>
	@function --add-a-b-c(--b, --c) {
		--c: 300;
		result: calc(var(--a) + var(--b) + var(--c));
		/* uses the --a from the call site's custom property,
		   the --b from the function parameter,
		   and the --c from the local variable */
	}
	div {
		--a: 1;
		--b: 2;
		--c: 3;
		z-index: --add-a-b-c(20, 30); /* 321 */
	}
	</xmp>

</div>


<!-- Big Text: using

█▌  █▌  ███▌  ████ █    █▌  ███▌ 
█▌  █▌ █▌  █▌  ▐▌  █▌   █▌ █▌  █▌
█▌  █▌ █▌      ▐▌  ██▌  █▌ █▌    
█▌  █▌  ███▌   ▐▌  █▌▐█ █▌ █▌ ██▌
█▌  █▌     █▌  ▐▌  █▌  ██▌ █▌  █▌
█▌  █▌ █▌  █▌  ▐▌  █▌   █▌ █▌  █▌
 ███▌   ███▌  ████ █▌   ▐▌  ███▌ 
-->

Using Custom Functions {#using-custom-functions}
================================================

Similar to how the value of a [=custom property=] can be substituted
into the value of another property with ''var()'',
the result of a [=custom function=] evaluation can be substituted
into the value of a property
with a <<dashed-function>>.

A <dfn><<dashed-function>></dfn> is a [=functional notation=]
whose function name starts with two dashes (U+002D HYPHEN-MINUS).
Its [=argument grammar=] is:

<pre class="prod informative" nohighlight>
	&lt;dashed-function> = --*( <<declaration-value>>#? )
</pre>

A <<dashed-function>> can only be used where ''var()'' is allowed.

If a property contains one or more <<dashed-function>>s,
the entire property’s grammar must be assumed to be valid at parse time.
At computed-value time,
every <<dashed-function>> must be [=replace a dashed function|replaced=]
before finally being checked against the property's grammar.

Note: Within the body of a [=custom function=],
''var()'' functions might resolve differently
than on the element the <<dashed-function>> is used on.
See [[#evaluating-custom-functions]].

A <<dashed-function>> is evaluated in some context:
either in a property value on an element
(or in a descriptor that is eventually treated like a property on an element,
such as in ''@keyframes''),
or in a descriptor in the [=function body=] of another [=custom function=]
that is being applied to a "hypothetical" element.
Either way, this provides a <dfn>calling context</dfn>,
which contains the property or descriptor name containing the <<dashed-function>>,
and the element (or "hypothetical" element) that property/descriptor is being applied to.

As [=calling contexts=] are nested by <<dashed-function>> evaluations
<em>inside of</em> [=custom functions=],
a [=calling context's=] <dfn for="calling context">root element</dfn>
is the real element at the root of the [=calling context=] stack.

<div algorithm>
	To <dfn>replace a dashed function</dfn> |dashed function|,
		with a list of |arguments|:

		1. Let |function| be the result of dereferencing
			the |dashed function|'s name as a [=tree-scoped reference=].
			If no such name exists, return the [=guaranteed-invalid value=].
		2. For each |arg| in |arguments|, 
			[=substitute arbitrary substitution functions=] in |arg|,
			and replace |arg| with the result.

			Note: This may leave some (or all) arguments as the [=guaranteed-invalid value=],
				triggering [=default values=] (if any).
		3. If |dashed function| is being substituted into a property on an element,
			let |calling context| be a [=calling context=]
			with that element and that property

			Otherwise, it's being substituted into a descriptor
			on a "hypothetical element",
			while evaluating another [=custom function=].
			Let |calling context| be a [=calling context=]
			with that "hypothetical element" and that descriptor.

		4. [=Evaluate a custom function=],
			using |function|, |arguments|, and |calling context|,
			and return the [=equivalent token sequence=]
			of the value resulting from the evaluation.
</div>

<wpt>
	functions/dashed-function-eval.html
	functions/dashed-function-standard-property.html
	functions/function-attr.html
	functions/function-shadow-animations.html
	functions/function-shadow-cache.html
	functions/function-shadow-container.html
	functions/function-shadow.html
</wpt>

<div class='example'>
	A [=free-form production|comma-containing value=]
	can be passed as a single argument
	by wrapping the value in curly braces, <code>{}</code>:

	<pre class='lang-css'>
	@function --max-plus-x(--list, --x) {
	  result: calc(max(var(--list)) + var(--x));
	}
	div {
	  width: --max-plus-x({ 1px, 7px, 2px }, 3px); /* 10px */
	}
	</pre>
</div>

<div class='example'>
	In the following,
	<code>--foo()</code> is in a cycle with itself:

	<pre class='lang-css'>
	@function --foo(--x) {
	  result: --foo(10);
	}
	</pre>

	Similarly,
	<code>--bar()</code> is in a cycle with itself,
	even though the local variable <code>--x</code> is never referenced
	by '@function/result':

	<pre class='lang-css'>
	@function --bar() {
	  --x: --bar();
	  result: 1;
	}
	</pre>

	However, <code>--baz()</code> is not in a cycle with itself here,
	since we never evaluate the <code>result</code> declaration within
	the <code>@media</code> rule:

	<pre class='lang-css'>
	@function --baz(--x) {
	  @media (unknown-feature) {
	    result: --baz(42);
	  }
	  result: 1;
	}

	</pre>
</div>

<div class='example'>
	The function <code>--baz()</code> is not in a cycle in the example below:
	even though <code>var(--x)</code> and <code>var(--y)</code> appear in the function body,
	they refer to a [=function parameter=] and [=local variable=], respectively.
	The [=custom properties=] <code>--x</code> and <code>--y</code>
	both reference <code>--baz()</code>, but that's fine:
	those [=custom properties=] are not referenced within <code>--baz()</code>.

	<pre class='lang-css'>
	@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 */
	}
	</pre>
</div>

Evaluating Custom Functions {#evaluating-custom-functions}
----------------------------------------------------------

[=Custom functions=] are evaluated by, essentially,
pretending their function body is a [=style rule=]
being applied to a hypothetical element,
resolving styles as normal,
and then returning the value of the '@function/result' descriptor on that hypothetical element.
The hypothetical element "inherits" the values of all custom properties
as if it were a child of its [=calling context=],
with its [=function parameters=] overriding "inherited" custom properties of the same name.

<div algorithm>
	To <dfn>evaluate a custom function</dfn> |custom function|,
	given a [=calling context=] |calling context|
	and a list of CSS values |arguments|,
	returning a CSS value:

	1. Let |substitution context| be a [=substitution context=]
		containing &bs<<;"function", |custom function|&bs>>;.

		Note: Due to [=tree-scoped names|tree-scoping=],
		the same function name may appear multiple times on the stack
		while referring to different [=custom functions=].
		For this reason, the [=custom function=] itself is included
		in the [=substitution context=], not just its name.
	2. [=guarded|Guard=] |substitution context| for the remainder of this algorithm.
		If |substitution context| is marked as [=cyclic substitution context|cyclic=],
		return the [=guaranteed-invalid value=].
	3. If the number of items in |arguments|
		is greater than the number of [=function parameters=] in |custom function|,
		return the [=guaranteed-invalid value=].
	4. Let |registrations| be an initially empty set of [=custom property registrations=].
	5. For each [=function parameter=] of |custom function|,
		create a [=custom property registration=]
		with the parameter's name,
		a syntax of the [=parameter type=],
		an inherit flag of "true",
		and no initial value.
		Add the registration to |registrations|.
	6. If |custom function| has a [=custom function/return type=],
		create a [=custom property registration=]
		with the name "result"
		(violating the usual rules for what a registration's name can be),
		a syntax of the [=custom function/return type=],
		an inherit flag of "false",
		and no initial value.
		Add the registration to |registrations|.
	7. Let |argument rule| be an initially empty [=style rule=].
	8. For each [=function parameter=] of |custom function|:
		1. Let |arg value| be the value of the corresponding argument in |arguments|,
			or the [=guaranteed-invalid value=] if there is no corresponding argument.
		2. Let |default value| be the parameter's [=default value=].
		3. Add a [=custom property=] to |argument rule|
			with a name of the parameter's name,
			and a value of ''first-valid(|arg value|, |default value|)''.
	9. [=Resolve function styles=] using |custom function|, |argument rule|, |registrations|, and |calling context|.
		Let |argument styles| be the result.
	10. Let |body rule| be the [=function body=] of |custom function|,
		as a [=style rule=].
	11. For each [=custom property registration=] of |registrations|
		except the registration with the name "result",
		set its initial value
		to the corresponding value in |argument styles|,
		set its syntax
		to the [=universal syntax definition=],
		and prepend a [=custom property=] to |body rule|
		with the property name and value in |argument styles|.
	12. [=Resolve function styles=] using |custom function|, |body rule|, |registrations|, and |calling context|.
		Let |body styles| be the result.
	13. If |substitution context| is marked as a [=cyclic substitution context=],
		return the [=guaranteed-invalid value=].

		Note: Nested [=arbitrary substitution functions=]
			may have marked |substitution context| as [=cyclic substitution context|cyclic=]
			at some point after step 2,
			for example when resolving '@function/result'.
	14. Return the value of the '@function/result' property in |body styles|.
</div>

<wpt>
	functions/dashed-function-cycles.html
	functions/local-attr-substitution.html
	functions/local-if-substitution.html
</wpt>

<div algorithm>
	To <dfn>resolve function styles</dfn>,
	given a [=custom function=] |custom function|,
	a style rule |rule|,
	a set of [=custom property registrations=] |registrations|,
	and a [=calling context=] |calling context|,
	returning a set of [=computed value|computed=] styles:

	1. Create a "hypothetical element" |el|
		that acts as a child of |calling context|'s element.
		|el| is [=featureless=],
		and only [=custom properties=]
		and the '@function/result' descriptor apply to it.
	2. Apply |rule| to |el| to the [=specified value=] stage,
		with the following changes:

		* Only the [=custom property registrations=] in |registrations| are visible;
			all other [=custom properties=] are treated as unregistered.

		* The [=inherited value=] of |calling context|'s property
			is the [=guaranteed-invalid value=].

		* On custom properties,
			the [=CSS-wide keywords=] have the following effects:

			<dl>
				<dt>''initial''</dt>
				<dd>
					Resolves to the initial value of the custom property
					within |registrations|.
				</dd>

				<dt>''inherit''</dt>
				<dd>
					Resolves like an ''inherit()'' function
					with the custom property name as its one and only argument.

					Note: This ensures that a [=function parameter=] defaulted to ''inherit''
						is reinterpreted using the local [=parameter type=].
				</dd>

				<dt>any other [=CSS-wide keyword=]</dt>
				<dd>
					Resolves to the [=guaranteed-invalid value=].
				</dd>
			</dl>

			Note: ''initial'' references the [=custom property registration=]
			created from the [=function parameters=],
			letting you "reset" a property to the passed value.
			''inherit'' inherits from the [=calling context=]'s element.\

			On '@function/result',
			all [=CSS-wide keywords=] are left unresolved.

			Note: ''result: inherit'', for example,
			will cause the <<dashed-function>> to <em>evaluate to</em> the ''inherit'' keyword,
			similar to ''var(--unknown, inherit)''.
		* For a given [=custom property=] |prop|,
			during [=property replacement=] for that property,
			the [=substitution context=] also includes |custom function|.
			In other words, the [=substitution context=] is
			&bs<<;"property", |prop|'s name, |custom function|&bs>>;

			Note: Due to dynamic scoping,
			the same property name may appear multiple times on the stack
			while referring to different [=custom properties=].
			For this reason, the [=custom function=] itself is included
			in the [=substitution context=], not just its name.

	3. Determine the [=computed value=] of all [=custom properties=]
		and the '@function/result' "property" on |el|,
		as defined in [[css-properties-values-api#calculation-of-computed-values]],
		with changes from the previous step,
		and the following:

		* Aside from references to [=custom properties=]
			(which use the values on |el| as normal)
			and numbers/percentages
			(which are left unresolved in custom properties, as normal),
			all values which would normally refer to the element being styled
			instead refer to |calling context|'s [=calling context/root element=].

			Note: For example, ''attr()'' in a property,
			or ''@container'' queries in the rule.

	4. Return |el|'s styles.

		Note: Only [=custom properties=] and the '@function/result' descriptor
		will be used from these styles.
</div>

<!-- Big Text: execution

█████▌ █     █ █████▌  ███▌  █▌  █▌ █████▌ ████  ███▌  █    █▌
█▌      █   █  █▌     █▌  █▌ █▌  █▌   █▌    ▐▌  █▌  █▌ █▌   █▌
█▌       █ █   █▌     █▌     █▌  █▌   █▌    ▐▌  █▌  █▌ ██▌  █▌
████      █    ████   █▌     █▌  █▌   █▌    ▐▌  █▌  █▌ █▌▐█ █▌
█▌       █ █   █▌     █▌     █▌  █▌   █▌    ▐▌  █▌  █▌ █▌  ██▌
█▌      █   █  █▌     █▌  █▌ █▌  █▌   █▌    ▐▌  █▌  █▌ █▌   █▌
█████▌ █     █ █████▌  ███▌   ███▌    █▌   ████  ███▌  █▌   ▐▌
-->

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.

<div class='example'>
	<pre class='lang-css'>
	@function --mypi() {
	  result: 3;
	  result: 3.14;
	}
	</pre>
	The value of the '@function/result' descriptor of <code>--mypi</code>
	is <code>3.14</code>.
</div>

<div class='example'>
	<pre class='lang-css'>
	@function --circle-area(--r) {
	  result: calc(pi * var(--r2));
	  --r2: var(--r) * var(--r);
	}
	</pre>
	[=Local variable=] descriptors may appear before or after
	they are referenced.
</div>

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 <a href="https://drafts.csswg.org/css-conditional-3/#processing">processed</a> 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.

<wpt>
	functions/function-conditionals.html
	functions/function-container-dynamic.html
	functions/function-container-self.html
	functions/function-container-style.html
	functions/function-layer.html
	functions/function-media-dynamic.html
</wpt>

<div class='example'>
	<pre class='lang-css'>
	@function --suitable-font-size() {
		result: 16px;
		@media (width > 1000px) {
			result: 20px;
		}
	}
	</pre>

	The value of the '@function/result' descriptor
	is <code>20px</code> if the media query's condition is true,
	and <code>16px</code> otherwise.
</div>

<div class='example'>
	Note that due to the execution model,
	"early return" is not possible within a ''@function'':
	<pre class='lang-css'>
	@function --suitable-font-size() {
		@media (width > 1000px) {
			result: 20px;
		}
		result: 16px;
	}
	</pre>

	The value of the '@function/result' descriptor
	is always <code>16px</code> in the above example.
</div>

<div class='example'>
	[=Local variables=] are also valid within conditional rules:
	<pre class='lang-css'>
	@function --suitable-font-size() {
		--size: 16px;
		@media (width > 1000px) {
			--size: 20px;
		}
		result: var(--size);
	}
	</pre>
</div>


<!-- Big Text: @mixin

 ████▌  █     █ ████ █     █ ████ █    █▌
█▌   █▌ ██   ██  ▐▌   █   █   ▐▌  █▌   █▌
█▌▐█ █▌ █▌█ █▐█  ▐▌    █ █    ▐▌  ██▌  █▌
█▌▐█ █▌ █▌ █ ▐█  ▐▌     █     ▐▌  █▌▐█ █▌
█▌ ██▌  █▌   ▐█  ▐▌    █ █    ▐▌  █▌  ██▌
█▌      █▌   ▐█  ▐▌   █   █   ▐▌  █▌   █▌
 ████▌  █▌   ▐█ ████ █     █ ████ █▌   ▐▌
-->

<h2 id=defining-mixins>
Defining Mixins</h2>

A [=mixin=] is in many ways similar to a [=custom function=],
but rather than extending/upgrading [=custom properties=],
[=mixins=] extend/upgrade [=nested style rules=],
making them reusable and customizable with arguments.

<wpt>
	mixins/mixin-basic.html
	mixins/mixin-declarations.html
	mixins/mixin-parsing.html
	mixins/mixin-shadow-dom.html
</wpt>

<div class=example>
	For example, the following code sets up a mixin
	applying all the properties you need for a "gradient text" effect,
	including guarding it with [=supports queries=]:

	<pre highlight=css>
		@mixin --gradient-text(
			--from <<color>>: mediumvioletred,
			--to <<color>>: teal,
			--angle: to bottom right,
		) {
			--gradient: linear-gradient(var(--angle), var(--from), var(--to));
			@result {
				color: var(--from, var(--to));

				@supports (background-clip: text) or (-webkit-background-clip: text) {
					background: var(--gradient, var(--from));
					color: transparent;
					-webkit-background-clip: text;
					background-clip: text;
				}
			}
		}

		h1 {
			@apply --gradient-text(pink, powderblue);
		}
	</pre>

	Note that this example also uses a [=local variable=] ''--gradient'',
	which is accessible inside the mixin
	to aid in readability,
	but won't pollute the element's actual styles.

	This is roughly equivalent to writing a [=nested style rule=] literally into the `h1` styles:

	<pre highlight=css>
		h1 {
			--from: pink;
			--to: powderblue;
			--angle: to bottom right;
			color: var(--from, var(--to));

			@supports (background-clip: text) or (-webkit-background-clip: text) {
				--gradient: linear-gradient(var(--angle), var(--from), var(--to));
				background: var(--gradient, var(--from));
				color: transparent;
				-webkit-background-clip: text;
				background-clip: text;
			}
		}
	</pre>

	(except that none of those custom properties actually show up in the element's styles)
</div>

Issue: The entire ''@mixin'' feature is experimental and under active development,
and is much less stable than ''@function''.
Expect things to change frequently for now.


<h3 id=mixin-rule>
The <dfn>@mixin</dfn> rule</h3>

The ''@mixin'' rule defines a <dfn>mixin</dfn>,
and consists of a name,
a list of [=mixin parameters=],
and a [=mixin body=].
(Identical to ''@function'',
save that it lacks a [=custom function/return type=],
and that the parameter list and enclosing parentheses are optional.)

<pre class="prod def">
	<<@mixin>> = @mixin [<<function-token>> <<function-parameter>>#? ) | <<ident-token>> ]
	{
		<<declaration-rule-list>>
	}
</pre>

<wpt>
	mixins/mixin-media-query-invalidation-2.html
	mixins/mixin-media-query-invalidation.html
	mixins/mixin-parameters.html
</wpt>

If a [=default value=] and a [=parameter type=] are both provided,
then the default value must parse successfully according to that parameter type’s syntax.
Otherwise, the ''@mixin'' rule is invalid.

A ''@mixin'' rule cannot be a [=nested group rule=];
it is invalid within the body of a [=style rule=].

<h4 id=mixin-prelude>
The Mixin Prelude</h4>

The <<function-token>> or <<ident-token>> production
must start with two dashes (U+002D HYPHEN-MINUS),
similar to <<dashed-ident>>,
or else the definition is invalid.

The name of the resulting [=mixin=] is given by the name of the <<function-token>> or <<ident-token>>.
The optional [=mixin parameters=]
are given by the <<function-parameter>> values
(defaulting to an empty set).

If an <<ident-token>> is used,
it is equivalent to a <<function-token>> followed by an empty parameter list.

The name of a ''@mixin'' rule is a [=tree-scoped name=].
If more than one ''@mixin'' exists for a given name,
then the rule in the stronger cascade layer wins,
and rules defined later win within the same layer.

If the [=mixin parameters=]
contain the same <<custom-property-name>> more than once,
then the ''@mixin'' rule is invalid.

<h4 id=mixin-body dfn lt="mixin body" export>
The Mixin Body</h4>

The body of a [=mixin=] accepts [=conditional group rules=],
such as ''@media'',
and [=custom properties=],
providing [=local variables=].

Note: This is identical to a [=function body=],
except for the lack of a 'result!!descriptor' descriptor.

Additionally, the [=mixin body=] must contain a ''@result'' rule,
giving the [=mixin's=] substitution result.
A ''@mixin'' without a ''@result'' is invalid.

Unknown properties and rules are invalid and ignored,
but do not make the ''@mixin'' rule itself invalid.

<wpt>
	mixins/mixin-conditionals.html
	mixins/mixin-layers.html
	mixins/mixin-locals.html
</wpt>

<h3 id=result-rule at-rule lt="@result" export>
The ''@result'' Rule</h3>

Within a ''@mixin'' rule,
the ''@result'' rule specifies the <dfn export>mixin result</dfn>,
a [=nested declarations rule=]
similar to the 'result!!descriptor' descriptor in [=custom functions=].
It's what the ''@apply'' rule will be substituted with.

<pre class="prod def">
	<<@result>> = @result {
		<<declaration-rule-list>>
	}
</pre>

The body of a ''@result'' rule acts as a [=nested declarations rule=],
and accepts the same properties and rules
that a normal [=nested declarations rule=] would.
In particular, further [=mixins=] can be invoked
(via the ''@apply'' rule)
within a ''@result''.

Note: [=Custom properties=] inside of a ''@result''
actually define properties that will be emitted by the [=mixin=];
they are <em>not</em> [=local variables=].
They <em>can</em> still be accessed by ''var()'',
but as element styles,
which are a lower priority than [=local variables=] or [=mixin parameters=];
see [[#mixin-args]] for details.

The ''@result'' body can also contain the ''@contents'' rule,
allowing a [=contents block=] passed to the [=mixin=] to be substituted in.

A [=mixin=] can contain multiple ''@result'' rules,
and all of them are concatenated, in order,
to form the [=mixin result=].
''@result'' rules inside of false [=conditional group rules=]
are not included in the [=mixin result=].

Note: It's possible for a [=mixin=] to end up with an empty [=mixin result=],
because all of its ''@result'' rules
are inside of false conditionals.
This will simply mean the [=mixin=] substitutes with nothing,
making it a no-op;
weird, but not invalid.

The [=mixin result=] is a [=scoped style rule=],
with the [=scoping root=] being the element the [=mixin's=] styles are being applied to.
(Unlike a traditional ''@scope'' rule,
the [=scoping root=] here can be a [=pseudo-element=],
if the [=mixin=] is being applied to one.)
There are no [=scoping limits=].

<!-- Big Text: params

████▌   ███▌  ████▌   ███▌  █     █  ███▌ 
█▌  █▌ ▐█ ▐█  █▌  █▌ ▐█ ▐█  ██   ██ █▌  █▌
█▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌ █▌█ █▐█ █▌    
████▌  █▌  █▌ ████▌  █▌  █▌ █▌ █ ▐█  ███▌ 
█▌     █████▌ █▌▐█   █████▌ █▌   ▐█     █▌
█▌     █▌  █▌ █▌ ▐█  █▌  █▌ █▌   ▐█ █▌  █▌
█▌     █▌  █▌ █▌  █▌ █▌  █▌ █▌   ▐█  ███▌ 
-->

<h3 id=mixin-args dfn lt="mixin parameter" export>
Arguments and Local Variables</h3>

Identical to [=function bodies=],
within a [=mixin body=]
the ''var()'' function can access [=local variables=]
(the [=custom properties=] defined in the [=mixin body=],
outside the ''@result'' rule),
[=mixin parameters=]
(the values passed to the [=mixin=],
	or set to default values),
and custom properties defined at the call site
(the element recieving the mixin styles,
or another [=mixin=] calling this [=mixin=]).

Just like in [=custom functions=],
earlier things in that list "win" over later things;
a [=local variable=] named ''--foo''
will be seen by ''var(--foo)''
instead of a [=mixin parameter=] or [=custom property=] on the element
of the same name.
See [[#evaluating-mixins]] for details on this behavior.

<div class=example>
	For example, the following mixin use:

	<xmp highlight=css>
	@mixin --shadowed-values(--color2: green, --color3: green) {
		--color3: blue;
		@result {
			background: linear-gradient(var(--color1), var(--color2), var(--color3));
		}
	}
	p {
		--color1: red;
		--color2: red;
		--color3: red;
		@apply --shadowed-values();
	}
	</xmp>

	will produce a ''linear-gradient(red, green, blue)'' value,
	taking ''--color-1'' from the outside
	(since nothing overrides it),
	''--color2'' from the [=mixin parameter=]
	(overriding the value from the element),
	and ''--color3'' from the [=local variable=] in the [=mixin body=]
	(overriding both the value from the element and the [=mixin parameter=] of that name).
</div>

<h4 id=var-hygiene>
Variable "Hygiene"</h4>

Because [=mixins=] can apply styles to multiple elements at once,
care must be taken to ensure that [=local variables=] and [=mixin parameters=]
work "as expected" across the mixin's styles,
even if [=custom properties=] on the element define clashing names.
Similarly, care must be taken to ensure that variables passed into a mixin,
such as by ''@apply --mix(var(--foo))'',
resolve "as expected" to the custom property on the element,
even if the [=mixin=] defines a [=local variable=] or [=mixin parameter=]
with the same name.

To achieve this,
[=local variables=] and [=mixin parameters=] in a [=mixin=]
(both in the [=mixin body=] and the [=mixin result=])
are <dfn export lt="hygienic rename|hygienically rename">hygienically renamed</dfn>,
to ensure that references to them work correctly across elements and inheritance.

[=Hygienic renaming=] changes the names
of [=local variables=] and [=mixin parameters=]
to an unobservable, guaranteed non-clashing name,
its <dfn noexport>hygienic name</dfn>.
(They remember their <dfn noexport>original name</dfn>, however.)

If a ''var()'' in the [=mixin body=]
would reference a [=local variable=] or [=mixin parameter=]
with its [=original name=],
the reference is rewritten to use the [=hygienic name=] instead.
The same applies to [=variable unit references=]
and ''style()'' references in an ''if()'' test.

Note: This list is not necessarily exhaustive.
If future features allow referencing the value of a custom property on an element,
they will also be interpreted as referencing the [=hygienic name=]
when used inside a [=mixin=].

[=Hygienic renaming=] extends to nested [=mixins=] and to invoked [=custom functions=],
if they contain "unbound" variable references
that would match a [=hygienically renamed=] [=local variable=] or [=mixin parameter=].
(This preserves the ability of mixins to "override" custom properties
implicitly used by nested mixins or functions,
the same way that nested function calls can.)

Otherwise, such "unbound" references are left undisturbed,
so they'll still match the appropriate [=custom property=] in the element context.

Note: For example, the ''inherit()'' function intrinsically reaches outside of the current context,
referencing the value one "level" up.
Even if a [=local variable=] with the same name exists in the current [=mixin=],
it won't cause the ''inherit()''&apos;s reference to be rewritten.
(But if it ends up referencing a [=local variable=] higher in the "call stack",
it'll be rewritten to coordinate with that one.)

<div class=example>
	For example, given the following styles and mixin:

	<xmp highlight=css>
	@mixin --triple-border(--size <length>) {
		@result {
			&, & > *, & > * > * {
				border-width: var(--size);
			}
		}
	}
	section {
		@apply --triple-border(5px);
	}
	section > h1 {
		--size: 10px;
	}
	section > h1 > small {
		--size: 20px;
	}
	</xmp>

	The [=mixin parameter=] ''--size'' is [=hygienically renamed=],
	resulting in the applied styles being equivalent to something like:

	<xmp highlight=css>
	section {
		--f7bd60b7: 5px;
		border-width: var(--f7bd60b7);
	}
	section > h1 {
		--size: 10px;
		border-width: var(--f7bd60b7);
	}
	section > h1 > small {
		--size: 20px;
		border-width: var(--f7bd60b7);
	}
	</xmp>

	Even though the child and grandchild elements set the same [=custom property=] as the [=mixin result=],
	they don't influence the result.
	Instead, the [=mixin result=] is changed to reference an un-clashable variable name,
	allowing inheritance to safely transmit the original value to the descendants,
	ensuring that all three borders are the same size,
	as the author intended.
</div>

Note: While [=hygienic renaming=] ensures that descendants won't accidentally pick up the wrong variable value,
and [[#evaluating-mixins]] ensures that element-dependent arguments passed to the mixin
(like ''@apply --foo(1em);'')
will resolve against the applying element too,
using <em>any other</em> element-dependent reference in the [=mixin result=]
will evaluate as normal for their placement in the styles.

<div class=example>
	For example, in the following variant of the previous example:

	<xmp highlight=css>
	@mixin --triple-border() {
		@result {
			&, & > *, & > * > * {
				border-width: .2em;
			}
		}
	}
	section {
		font-size: 10px;
		@apply --triple-border;
	}
	section > h1 {
		font-size: 20px;
	}
	section > h1 > small {
		font-size: 15px;
	}
	</xmp>

	The applied mixin will be equivalent to:

	<xmp highlight=css>
	section {
		font-size: 10px;
		border-width: .2em;
	}
	section > h1 {
		font-size: 20px
		border-width: .2em;
	}
	section > h1 > small {
		font-size: 15px;
		border-width: .2em;
	}
	</xmp>

	Which will give three different 'border-width' values: ''2px'', ''4px'', and ''3px''.
</div>

<div class=issue>

	This is likely often a desirable behavior,
	but if it's not,
	we should have a workaround.
	The following *doesn't* work,
	due to the mixin body becoming the function body of an anonymous function,
	which is evaluated on each element
	and thus inherits that element's ''em'' length.

	<xmp highlight=css>
	@function --as-length(--x <length>) returns <length> { result: var(--x); }
	@mixin --triple-border() {
		--em: --as-length(1em);
		@result {
			&, & > *, & > * > * {
				border-width: calc(0.2 * var(--em));
			}
		}
	}
	</xmp>

	I think the only way that works is to have an extra argument
	that you don't expect the user to pass,
	since arguments get lifted onto the applying element
	and hygienically renamed:

	<xmp highlight=css>
	@mixin --triple-border(--em <length>: 1em) {
		@result {
			&, & > *, & > * > * {
				border-width: calc(0.2 * var(--em));
			}
		}
	}
	</xmp>

	But this is clumsy. :(
</div>


<!-- Big Text: @contents

 ████▌   ███▌   ███▌  █    █▌ █████▌ █████▌ █    █▌ █████▌  ███▌ 
█▌   █▌ █▌  █▌ █▌  █▌ █▌   █▌   █▌   █▌     █▌   █▌   █▌   █▌  █▌
█▌▐█ █▌ █▌     █▌  █▌ ██▌  █▌   █▌   █▌     ██▌  █▌   █▌   █▌    
█▌▐█ █▌ █▌     █▌  █▌ █▌▐█ █▌   █▌   ████   █▌▐█ █▌   █▌    ███▌ 
█▌ ██▌  █▌     █▌  █▌ █▌  ██▌   █▌   █▌     █▌  ██▌   █▌       █▌
█▌      █▌  █▌ █▌  █▌ █▌   █▌   █▌   █▌     █▌   █▌   █▌   █▌  █▌
 ████▌   ███▌   ███▌  █▌   ▐▌   █▌   █████▌ █▌   ▐▌   █▌    ███▌ 
-->

<h3 id='contents-rule'>
The <dfn>@contents</dfn> Rule</h3>

In addition to accepting arguments passed by the <<dashed-function>> in the ''@apply'' rule,
a [=mixin=] can accept a <dfn>contents block</dfn>.
Any mixin can be passed a [=contents block=],
by giving the ''@apply'' rule invoking the mixin
a block.

This allows the invoker of the [=mixin=] to pass an entire style block,
which the [=mixin=] can then substitute into itself.
This is useful, for example,
if the [=mixin=] handles some common conditions for the author,
and substitutes the [=contents block=] into a predefined ''@media'' or ''@container'' rule.

The syntax of a ''@contents'' at-rule is:

<pre class="prod def">
	<<@contents>> = @contents [ { <<declaration-list>> } ]?
</pre>

<wpt>
	mixins/contents-nested-declarations-fallback.html
	mixins/contents-nested-declarations.html
	mixins/contents-rule.html
</wpt>

That is, it is either an <em>empty</em> statement ended immediately by a semicolon,
or a <dfn>fallback block</dfn> treated as a [=nested declarations rule=].
The empty statement form behaves identically to passing an empty block.

* If the ''@apply'' rule invoking the [=mixin=] passed a [=contents block=],
	the ''@contents'' is replaced with the [=contents block=],
	treating it as a [=nested declarations rule=].
* Otherwise (if the ''@apply'' rule did not pass a [=contents block=]),
	the ''@contents'' rule is replaced with its [=fallback block=],
	treating it as a [=nested declarations rule=].

Outside of an ''@result'' rule,
the ''@contents'' rule is invalid and ignored.

Note: It's valid for an ''@apply'' rule to pass a [=contents block=],
but the mixin not use it.

<div class=example>
	For example, the following mixins
	abstracts the cases that the page would consider to be appropriate
	for a "single column" layout,
	allowing the rest of the page to handle the case without worrying about the details,
	so the conditions can be adjusted in the future if necessary:

	<pre highlight=css>
	@mixin --one-column() {
		@result {
			@media (width <= 800px) {
				@contents;
			}
		}
	}
	@mixin --two-column() {
		@result {
			@media (width > 800px) {
				@contents;
			}
		}
	}
	body {
		@apply --one-column {
			display: flex;
			flex-flow: column;
		}
		@apply --two-column {
			display: grid;
			grid-template-columns: 60px 60px;
		}
	}
	</pre>
</div>


<!-- Big Text: @macro 

 ████▌  █     █  ███▌   ███▌  ████▌   ███▌ 
█▌   █▌ ██   ██ ▐█ ▐█  █▌  █▌ █▌  █▌ █▌  █▌
█▌▐█ █▌ █▌█ █▐█ █▌  █▌ █▌     █▌  █▌ █▌  █▌
█▌▐█ █▌ █▌ █ ▐█ █▌  █▌ █▌     ████▌  █▌  █▌
█▌ ██▌  █▌   ▐█ █████▌ █▌     █▌▐█   █▌  █▌
█▌      █▌   ▐█ █▌  █▌ █▌  █▌ █▌ ▐█  █▌  █▌
 ████▌  █▌   ▐█ █▌  █▌  ███▌  █▌  █▌  ███▌ 
-->

Defining Macros {#macros}
===============

A <dfn for=css>macro</dfn> is a simplified variant of a [=mixin=],
that very directly substitutes its body into its ''@apply''-ing rule.

It does not take any arguments
(besides possibly a ''@contents'' block)
or define local variables
(and thus doesn't use a ''@result'' rule to separate its result from its (nonexistent) body)
and does not impose a "scoping" semantic on its result rules.
Otherwise, it is identical to a [=mixin=].

<div class=example>
	For simple mixins that are just meant
	to make it easier to include a commonly-repeated block of styles,
	[=macros=] can be slightly shorter/easier to use:

	<xmp highlight=css>
	@macro --reset-list {
		margin: 0;
		padding: 0;
		list-style: none;
	}
	.foo {
		@apply --reset-list;
	}
	</xmp>

	In cases like this, the *result* of defining this as a [=mixin=] or [=macro=] are identical.
	That is, one could equally write this slightly more verbose definition:

	<xmp highlight=css>
	@mixin --reset-list() {
		@result {
			margin: 0;
			padding: 0;
			list-style: none;
		}
	}
	</xmp>

	In more complex cases, though, their behaviors can differ;
	see [[#mixin-macro-diff]].
</div>


<h3 id=macro-rule at-rule lt="@macro" export>
The ''@macro'' rule</h3>

The ''@macro'' rule defines a [=macro=],
and consists of a name
and a [=macro body=].
(Similar to a [=mixin result=] block.)

<pre class="prod def">
	<<@macro>> = @macro <<dashed-ident>>
	{
		<<declaration-rule-list>>
	}
</pre>

A ''@macro'' rule cannot be a [=nested group rule=];
it is invalid within the body of a [=style rule=].

<h4 id=macro-prelude>
The Macro Prelude</h4>

The name of the resulting [=macro=] is given by the <<dashed-ident>> in its prelude.

The name of a ''@macro'' rule is a [=tree-scoped name=],
and functions identically to a ''@mixin'' name.
[=Macros=] and [=mixins=] share the same namespace;
if two are defined with the same name,
the last one wins
(just like having two [=mixins=] with the same name).


<h4 id=macro-body dfn lt="macro body" export>
The Macro Body</h4>

The body of a ''@macro'' rule
acts as a [=nested declarations rule=],
and accepts the same properties and rules that a normal [=nested declarations rule=] would.
In particular, further [=mixins=] and [=macros=] can be invoked
(via the ''@apply'' rule)
within a ''@macro''.

Note: This is identical to the body of a [=mixin's=] ''@result'' rule.
As [=macros=] don't <em>have</em> any arguments or local variables,
they don't need to mark their result separately
to distinguish [=local variables=] from [=custom properties=]
that will get added to the element's style.

Unknown properties and rules are invalid and ignored,
but do not make the ''@macro'' rule itself invalid.

Identically to [=mixins=],
the body of a ''@macro'' rule
can contain a ''@contents'' rule,
which will substitute itself with a passed [=contents block=],
or potentially a fallback block.

<div class=example>
	The ''@contents'' example provided in [[#contents-rule]]
	used ''@mixin'',
	but it could equally be written with ''@macro'',
	as it does not use any arguments:

	<pre highlight=css>
	@macro --one-column {
		@media (width <= 800px) {
			@contents;
		}
	}
	@macro --two-column {
		@media (width > 800px) {
			@contents;
		}
	}
	body {
		@apply --one-column {
			display: flex;
			flex-flow: column;
		}
		@apply --two-column {
			display: grid;
			grid-template-columns: 60px 60px;
		}
	}
	</pre>
</div>




Using Mixins and Macros {#using-mixins}
=======================

The result of a [=mixin=] or [=macro=] application
is substituted into the body of another [=style rule=]
as a [=nested declarations rule=]
via the ''@apply'' rule.

<wpt>
	mixins/apply-nested-declarations.html
	mixins/mixin-cross-stylesheet.html
	mixins/mixin-from-import-with-media-queries.html
	mixins/mixin-from-import.html
</wpt>

<!-- Big Text: @apply

 ████▌   ███▌  ████▌  ████▌  █▌    █   ▐▌
█▌   █▌ ▐█ ▐█  █▌  █▌ █▌  █▌ █▌    ▐▌  █ 
█▌▐█ █▌ █▌  █▌ █▌  █▌ █▌  █▌ █▌     █ ▐▌ 
█▌▐█ █▌ █▌  █▌ ████▌  ████▌  █▌     ▐▌█  
█▌ ██▌  █████▌ █▌     █▌     █▌      █▌  
█▌      █▌  █▌ █▌     █▌     █▌      █▌  
 ████▌  █▌  █▌ █▌     █▌     █████   █▌  
-->

<h3 id=apply-rule>
The <dfn>@apply</dfn> Rule</h3>

The ''@apply'' rule applies a [=mixin=] or [=macro=],
causing it to substitute into the rule
in place of the ''@apply'' rule itself.

Its grammar is:

<pre class="prod">
<<@apply>> = @apply [ <<dashed-ident>> | <<dashed-function>> ] [ { <<declaration-list>> } ]?;
</pre>

<wpt>
	mixins/apply-top-level.html
	mixins/apply-within-mixin.html
</wpt>

<div class=example>
	For example, a [=mixin=] can be applied in any of these ways:

	<pre highlight=css>
	.foo {
		@apply --one;
		/* Invokes the --one mixin, with no arguments or contents. */

		@apply --two(blue);
		/* Invokes --two with one argument, and no contents. */

		@apply --three {color: red;}
		/* Invokes --three with no arguments, but with contents. */

		@apply --four(blue) {color: red;}
		/* Invokes --four with both an argument and contents. */
	}
	</pre>
</div>

The ''@apply'' rule is only valid
in the body of a [=style rule=]
or [=nested group rule=];
using it in any other context causes it to be invalid and ignored.

''@apply'' rules are processed <em>before</em> any styles are applied,
as they effectively modify the stylesheet itself.
(Similar, in effect, to how [=conditional group rules=]
adjust which properties and rules are active in a stylesheet
before styles are applied.)

The ''@apply'' rule applies the [=mixin=] or [=macro=]
named by the <<dashed-ident>> or the <<dashed-function>>'s name.
If no such [=mixin=] or [=macro=] exists,
the ''@apply'' does nothing.

If passed a <<dashed-function>>,
the arguments passed to the <<dashed-function>>
are mapped to the [=mixin's=] arguments;
if more arguments are passed than the length of the [=mixin's=] argument list,
the ''@apply'' application does nothing.
(Passing too few arguments is fine;
the missing arguments take their default values instead.)
A <<dashed-ident>> passes no arguments.
(That is, ''@apply --foo;'' is identical to ''@apply --foo();''.)
For these purposes, a [=macro=] is treated as having a zero-length argument list;
''@apply --my-macro();'' is valid.

If the ''@apply'' rule has a <<declaration-list>> block,
that block is passed as the [=mixin=] or [=macro=]'s [=contents block=].

<div class=example>
	Applying a mixin without arguments, or with an empty argument list,
	is identical.
	That is, these two invocations do exactly the same thing:

	<pre highlight=css>
	.foo {
		@apply --no-args;
	}
	.bar {
		@apply --no-args();
	}
	</pre>

	Passing a [=contents block=] is <em>not</em> the same;
	omitting the block entirely triggers ''@contents'' fallback,
	while passing an empty block will substitute the empty block:

	<pre highlight=css>
	@mixin --just-contents() {
		@result {
			@contents { color: red; }
			/* `color: red` is the fallback content */
		}
	}

	.foo {
		@apply --just-contents;
		/* fallback, substitutes with `color: red;` */
	}
	.bar {
		@apply --just-contents {};
		/* substitutes with nothing at all */
	}
	</pre>
</div>


<!-- Big Text: Eval

█████▌ █▌   █▌  ███▌  █▌   
█▌     █▌   █▌ ▐█ ▐█  █▌   
█▌     █▌   █▌ █▌  █▌ █▌   
████   ▐▌   █  █▌  █▌ █▌   
█▌      █  ▐▌  █████▌ █▌   
█▌      ▐▌ █   █▌  █▌ █▌   
█████▌   ▐█    █▌  █▌ █████
-->

Evaluating Mixins {#evaluating-mixins}
-----------------

At a high level, [=mixins=] are applied
by substituting their contents
at the location they're ''@apply''&apos;d.

Unfortunately, the exact mechanics of mixin substitution
are somewhat more complicated,
to ensure that local references, variables, and other concepts
work in a "natural" way.

When a [=mixin=] is applied,
the ''@apply'' rule referencing it
is replaced with the [=mixin result=],
with each property value in the [=mixin result=]
having its value replaced by an anonymous [=custom function=]
with the following properties:

* The [=function parameters=] are identical to the [=mixin parameters=].
	(The function's invocation has some adjustments; see below.)
* The [=function body=] is identical to the [=mixin body=],
	minus any ''@result'' rules,
	plus a 'result!!descriptor' descriptor
	containing the original value of the property this anonymous function is replacing.

Additionally, the arguments passed to the mixin
are evaluated and stored on the ''@apply''&apos;d element,
to ensure they obtain the "expected" value from that element,
rather than unexpectedly evaluating in a descendant element's context:

* For every [=mixin parameter=],
	a custom property is added to the top level of the [=mixin result=],
	with a [=hygienic rename|hygienic name=]
	and a value of the corresponding ''@apply()'' argument.
	This custom property is <em>unobservable</em> to the page;
	it only exists for UA purposes.

	Also, a [=custom property registration=]
	with that name,
	a syntax of the [=parameter type=],
	an inherit flag of "true",
	and no initial value,
	is added to the tree of that element.
* Each anonymous function invocation
	has its arguments set to ''var()'' functions
	referring to the corresponding custom property name
	created in the previous bullet point.

<div class=example>
	For example, given the following mixin:

	<xmp highlight=css>
	@mixin --same-size(--size <length>) {
		@result {
			&, & > * {
				width: calc(10 * var(--size));
			}
		}
	}
	.parent {
		font-size: 10px;
		@apply --same-size(1em);
	}
	.parent > .child {
		font-size: 20px;
	}
	</xmp>

	This will desugar into approximately:

	<xmp highight=css>
	@property --magic-arg1 {
		syntax: "<length>";
		inherits: true;
		/* initial-value: don't worry about it; */
	}
	@function --anonfunc1(--arg1) {
		result: calc(10 * var(--arg1));
	}
	@function --anonfunc2(--arg1) {
		result: calc(10 * var(--arg1));
	}
	.parent {
		font-size: 10px;
		--magic-arg1: 1em; /* resolves based on font-size here */
		width: --anonfunc1(var(--magic-arg1));
	}
	.parent > .child {
		font-size: 20px;
		width: --anonfunc2(var(--magic-arg1));
		/* --magic-arg1 is 10px, since it was resolved on the parent */
	}
	</xmp>
</div>

Note: In practice, this anonymous [=custom function=]
can usually be completely hypothetical,
and a direct substitution used instead.
It's required only to make variables
and other element-relative values resolve correctly.

<div class=example>
	When [=mixins=] are nested
	(one invoked via ''@apply'' inside the ''@result'' of another),
	the desugaring nests as well,
	in the obvious way.
	For example:

	<xmp highlight=css>
	div {
		@apply --colorized-squish(tomato);
	}

	/* "wraps" an element in colored arrows */
	@mixin --squish(--left-color <color>,
	                --right-color <color>: var(--left-color)) {
		@result {
			&::before {
				content: "🡆";
				background-color: var(--left-color);
			}
			&::after {
				content: "🡄";
				background-color: var(--right-color);
			}
		}
	}

	/* colors the element, and auto-generates a border color
	   and the "squish" colors from it */
	@mixin --colorized-squish(--color <color>) {
		@result {
			background-color: var(--color);
			border: 2px solid oklch(from var(--color) calc(l - 0.1) c h);
			@apply --squish(oklch(from var(--color) calc(l - 0.3) c h),
			                oklch(from var(--color) calc(l - 0.2) c h));
		}
	}
	</xmp>

	This desugars in two steps, inside-out.
	First, the ''--squish()'' is unfolded
	into the ''--colorized-squish()'' mixin:

	<xmp highlight=css>
	div {
		@apply --colorized-squish(tomato);
	}

	@mixin --colorized-squish(--color <color>) {
		/* Lift the `@apply squish();` arguments out into local vars */
		--s-arg1: oklch(from var(--color) calc(l - 0.3) c h);
		--s-arg2: oklch(from var(--color) calc(l - 0.2) c h);
		@result {
			background-color: var(--color);
			border: 2px solid oklch(from var(--color) calc(l - 0.1) c h);
			/* Replace the `@apply --squish();` with its @result,
			   transformed to wrap the property values in
			   anonymous functions. */
			&::before {
				content: --s1(var(--s-arg1), var(--s-arg2));
				background-color: --s2(var(--s-arg1), var(--s-arg2));
			}
			&::after {
				content: --s3(var(--s-arg1), var(--s-arg2));
				background-color: --s4(var(--s-arg1), var(--s-arg2));
			}
		}
	}
	@function --s1(--left-color <color>,
	               --right-color <color>: var(--left-color)) {
		result: "🡆";
	}
	@function --s2(--left-color <color>,
	               --right-color <color>: var(--left-color)) {
		result: var(--left-color);
	}
	@function --s3(--left-color <color>,
	               --right-color <color>: var(--left-color)) {
		result: "🡄";
	}
	@function --s4(--left-color <color>,
	               --right-color <color>: var(--left-color)) {
		result: var(--right-color);
	}
	</xmp>

	Then the ''--colorized-squish()'' mixin is unfolded into the ''div'' rule:

	<xmp highlight=css>
	div {
		/* Lift the `@apply --colorized-squish();` argument out into a var */
		--cs-arg1: tomato;
		/* Replace the `@apply --colorized-squish();` with (part of)
		   its @result, again with values wrapped in anonymous functions. */
		background-color: --cs1(var(--cs-arg1));
		border: --cs2(var(--cs-arg1));
		&::before {
			/* Note that --cs-arg1 is inherited here from div */
			content: --cs3(var(--cs-arg1));
			background-color: --cs4(var(--cs-arg1));
		}
		&::after {
			content: --cs5(var(--cs-arg1));
			background-color: --cs6(var(--cs-arg1));
		}
	}
	@function --cs1(--color <color>) {
	  result: var(--color);
	}
	@function --cs2(--color <color>) {
	  result: 2px solid oklch(from var(--color) calc(l - 0.1) c h);
	}

	/* These four generated functions all look identical, they
	   just call into the correct generated function from
	   --squish()'s unfolding. */
	@function --cs3(--color <color>) {
		/* The --colorized-squish() local vars (created by the
			first desugaring) are turned into function local vars. */
		--s-arg1: oklch(from var(--color) calc(l - 0.3) c h);
		--s-arg2: oklch(from var(--color) calc(l - 0.2) c h);
		result: --s1(var(--s-arg1), var(--s-arg2));
	}
	@function --cs4(--color <color>) {
		--s-arg1: oklch(from var(--color) calc(l - 0.3) c h);
		--s-arg2: oklch(from var(--color) calc(l - 0.2) c h);
		result: --s2(var(--s-arg1), var(--s-arg2));
	}
	@function --cs5(--color <color>) {
		--s-arg1: oklch(from var(--color) calc(l - 0.3) c h);
		--s-arg2: oklch(from var(--color) calc(l - 0.2) c h);
		result: --s3(var(--s-arg1), var(--s-arg2));
	}
	@function --cs6(--color <color>) {
		--s-arg1: oklch(from var(--color) calc(l - 0.3) c h);
		--s-arg2: oklch(from var(--color) calc(l - 0.2) c h);
		result: --s4(var(--s-arg1), var(--s-arg2));
	}

	/* These are copied from the previous desugaring */
	@function --s1(--left-color <color>,
	               --right-color <color>: var(--left-color)) {
		result: "🡆";
	}
	@function --s2(--left-color <color>,
	               --right-color <color>: var(--left-color)) {
		result: var(--left-color);
	}
	@function --s3(--left-color <color>,
	               --right-color <color>: var(--left-color)) {
		result: "🡄";
	}
	@function --s4(--left-color <color>,
	               --right-color <color>: var(--left-color)) {
		result: var(--right-color);
	}
	</xmp>

	Note that all the custom property and function names
	are given short, somewhat meaningful names here, for readability,
	but actually are [=hygienically renamed=]
	and guaranteed to be unreferencable by author code.
	Only the user agent ever sees or can use them,
	to do this desugaring.

	<details>
		<summary>Desugaring outside-in</summary>

		Equivalently, the mixins can be desugared outside-in,
		for the same result:

		<xmp highlight=css>
		/* Initial Code, same as main example */
		div {
			@apply --colorized-squish(tomato);
		}

		/* "wraps" an element in colored arrows */
		@mixin --squish(--left-color <color>,
		                --right-color <color>: var(--left-color)) {
			@result {
				&::before {
					content: "🡆";
					background-color: var(--left-color);
				}
				&::after {
					content: "🡄";
					background-color: var(--right-color);
				}
			}
		}

		/* colors the element, and auto-generates a border color
		   and the "squish" colors from it */
		@mixin --colorized-squish(--color <color>) {
			@result {
				background-color: var(--color);
				border: 2px solid oklch(from var(--color) calc(l - 0.1) c h);
				@apply --squish(oklch(from var(--color) calc(l - 0.3) c h),
				                oklch(from var(--color) calc(l - 0.2) c h));
			}
		}


		/* First desugar, unfolding --colorized-squish()*/

		div {
			/* Pull out the --colorized-squish() argument */
			--cs-arg1: tomato;
			/* Swap the @apply with the --colorized-squish() @result,
			   with values wrapped in anonymous functions. */
			background-color: --cs1(var(--cs-arg1));
			border: --cs2(var(--cs-arg1));
			/* The equivalent transform here is wrapping the
			   @apply args in anonymous functions. */
			@apply --squish(--cs3(--cs-arg1),
				            --cs4(--cs-arg1));
		}
		@function --cs1(--color <color>) {
			result: var(--color);
		}
		@function --cs2(--color <color>) {
			result: 2px solid oklch(from var(--color) calc(l - 0.1) c h);
		}
		@function --cs3(--color <color>) {
			result: oklch(from var(--color) calc(l - 0.3) c h);
		}
		@function --cs4(--color <color>) {
			result: oklch(from var(--color) calc(l - 0.2) c h);
		}
		@mixin --squish(--left-color <color>,
		                --right-color <color>: var(--left-color)) {
			@result {
				&::before {
					content: "🡆";
					background-color: var(--left-color);
				}
				&::after {
					content: "🡄";
					background-color: var(--right-color);
				}
			}
		}


		/* Second desugar, unfolding --squish() */
		div {
			--cs-arg1: tomato;
			background-color: --cs1(var(--cs-arg1));
			border: --cs1(var(--cs-arg1));
			/* Pull out the --squish() args now. */
			--s-arg1: --cs3(--cs-arg1);
			--s-arg2: --cs4(--cs-arg1);
			/* And swap the @apply with the --squish() @result,
			   with values wrapped in anonymous functions. */
			&::before {
				content: --s1(var(--s-arg1), var(--s-arg2));
				background-color: --s2(var(--s-arg1), var(--s-arg2));
			}
			&::after {
				content: --s3(var(--s-arg1), var(--s-arg2));
				background-color: --s4(var(--s-arg1), var(--s-arg2));
			}
		}
		@function --cs1(--color <color>) {
			result: var(--color);
		}
		@function --cs2(--color <color>) {
			result: 2px solid oklch(from var(--color) calc(l - 0.1) c h);
		}
		@function --cs3(--color <color>) {
			result: oklch(from var(--color) calc(l - 0.3) c h);
		}
		@function --cs4(--color <color>) {
			result: oklch(from var(--color) calc(l - 0.2) c h);
		}
		@function --s1(--left-color <color>,
		               --right-color <color>: var(--left-color)) {
			result: "🡆";
		}
		@function --s2(--left-color <color>,
		               --right-color <color>: var(--left-color)) {
			result: var(--left-color);
		}
		@function --s3(--left-color <color>,
		               --right-color <color>: var(--left-color)) {
			result: "🡄";
		}
		@function --s4(--left-color <color>,
		               --right-color <color>: var(--left-color)) {
			result: var(--right-color);
		}
		</xmp>

		The desugaring is slightly different in details,
		like the --s-arg1/2 custom properties are stored on ''div''
		rather than inside of the functions,
		but because they're unobservable and [=hygienically renamed=],
		the behavior is identical.
	</details>
</div>

Evaluating Macros {#eval-macro}
-----------------

[=Macros=] work similarly to [=mixins=],
in that they substitute their [=macro body=]
at the location they're ''@apply''&apos;d.
Contrary to [=mixins=],
[=macros=] are substituted simply and literally,
with no transforms performed on their content.


Mixin/Macro Differences {#mixin-macro-diff}
-----------------------

The basic differences between [=mixins=] and [=macros=] are obvious:

* [=Mixins=] can take arguments; [=macros=] can't.
* [=Mixins=] can have local variables, and wrap their result in ''@result'';
	[=macros=] don't, and just use their contents directly as their result.

The subtler difference is that,
<em>because</em> [=mixins=] have arguments and local variables
which they don't want to "leak" into the page's general styles,
and which they want to resolve on the applying element
(so ''var()'' functions, ''em'' values, etc passed as arguments or set as locals
all work "as expected"),
they treat their results as [=scoped style rules=].
[=Macros=] don't impose this restriction,
which makes them useful in some cases where [=mixins=] can't be used,
but which also limits their abilities in some other cases.

<div class=example>
	For example, the following mixin and macro are identical:

	<xmp highlight=css>
	@mixin --mix1() {
		@result {
			width: 20em;
			> .bar {
				width: 10em;
			}
		}
	}
	@macro --mac1() {
		width: 20em;
		> .bar {
			width: 10em;
		}
	}
	.foo {
		@apply --mix1; /* or --mac1 */
		font-size: 20px;
		/* width is 20em, so 400px */

		> .bar {
			font-size: 10px;
			/* width is 10em, so 100px;
		}
	}
	</xmp>

	Despite the mixin/macro *appearing* to set the ''.bar'' child
	to half the ''.foo'' parent's width,
	because they use ''em'' units and the elements have different 'font-size' values,
	the child ends up 1/4 the width of the parent instead.

	The mixin could be rewritten like this:

	<xmp highlight=css>
	@function --as-length(--x <length>) { result: var(--x); }
	@mixin --mix2() {
		--em: --as-length(1em);
		@result {
			width: 20--em; /* using custom units */
			> .bar {
				width: 10--em;
			}
		}
	}
	.foo {
		@apply --mix2;
		font-size: 20px;
		/* width is 20--em and --em is 20px, so 400px */

		> .bar {
			font-size: 10px;
			/* width is 10--em and --em is still 20px, so 200px;
		}
	}
	</xmp>

	...which resolves the ''--em'' local variable on ''.foo''
	(to a length of ''20px''),
	and then uses that in both places.
	A [=macro=] cannot reproduce this,
	unless you actually emit a ''--em'' [=custom property=] onto the element,
	where styles <em>outside of</em> the macro could see it.

	On the other hand, the following can be done with a [=macro=]:

	<xmp highlight=css>
	@macro --mac2() {
		width: 20em;
		+ .bar { /* sibling, not child! */
			width: 10em;
		}
	}
	.foo {
		@apply --mac2;
		font-size: 20px;
		/* width is 20em, so 400px */
		+ .bar { /* again, sibling! */
			font-size: 10px;
			/* width is 10em, so 100px;
		}
	}
	</xmp>

	A [=mixin=] can't reproduce this,
	unless you lift it up to applying on a parent element,
	with the mixin styling its two children.
</div>


<!-- Big Text: cssom

 ███▌   ███▌   ███▌   ███▌  █     █
█▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌ ██   ██
█▌     █▌     █▌     █▌  █▌ █▌█ █▐█
█▌      ███▌   ███▌  █▌  █▌ █▌ █ ▐█
█▌         █▌     █▌ █▌  █▌ █▌   ▐█
█▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌ █▌   ▐█
 ███▌   ███▌   ███▌   ███▌  █▌   ▐█
-->

CSSOM {#cssom}
==============

Issue: TODO Supply the OM for ''@mixin''/etc.

<wpt>
	functions/at-function-cssom.html
	functions/function-invalidation.html
</wpt>

The {{CSSFunctionRule}} Interface {#the-function-interface}
-----------------------------------------------------------

The {{CSSFunctionRule}} interface represents a ''@function'' rule.

<pre class='idl' export>
[Exposed=Window]
interface CSSFunctionRule : CSSGroupingRule {
	readonly attribute CSSOMString name;
	sequence&lt;FunctionParameter&gt; getParameters();
	readonly attribute CSSOMString returnType;
};
</pre>

<dl dfn-for=CSSFunctionRule dfn-type=attribute>
	<dt><dfn>name</dfn>
	<dd>
		The name of the [=custom function=].

	<dt><dfn>returnType</dfn>
	<dd>
		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 <code>"*"</code>.
</dl>


<pre class='idl' export>
dictionary FunctionParameter {
	required CSSOMString name;
	required CSSOMString type;
	CSSOMString defaultValue;
};
</pre>

<dl dfn-for=FunctionParameter>
	<dt>name
	<dd>
		The name of the [=function parameter=].

	<dt>type
	<dd>
		The [=parameter type|type=] of the [=function parameter=],
		represented as a [[css-properties-values-api-1#syntax-strings|syntax string]],
		or <code>"*"</code> if the [=function parameter|parameter=] has no type.

	<dt>defaultValue
	<dd>
		The [=default value=] of the [=function parameter=],
		or `null` if the argument does not have a default.
</dl>


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.

<div class='example' id=function-declarations-example>
	<pre class='lang-css'>
	@function --bar() {
	  --x: 42;
	  result: var(--y);
	  @media (width > 1000px) {
	    /* ... */
	  }
	  --y: var(--x);
	}
	</pre>

	The above will appear in the CSSOM as:

	<pre class='lang-css'>
	@function --bar() {
	  /* CSSFunctionDeclarations { */
	    --x: 42;
	    result: var(--y);
	  /* } */
	  @media (width > 1000px) {
	    /* ... */
	  }
	  /* CSSFunctionDeclarations { */
	    --y: var(--x);
	  /* } */
	}
	</pre>
</div>

<div algorithm>
To <dfn export>serialize a CSSFunctionRule</dfn>,
return the concatenation of the following:

	1. The string <code>"@function"</code> followed by a single SPACE (U+0020).
	2. The result of performing <a>serialize an identifier</a>
		on the name of the [=custom function=],
		followed by a single LEFT PARENTHESIS (U+0028).
	3. The result of [=serialize a function parameter=]
		on each of the [=custom function's=] [=function parameter|parameters=],
		all joined by <code>", "</code>
		(COMMA U+002C, followed by a single SPACE U+0020).
	4. A single RIGHT PARENTHESIS (U+0029).
	5. 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 <code>"returns"</code>,
			followed by a single SPACE (U+0020).
		* The result of performing [=serialize a CSS type=]
			on that [=custom function/return type|type=].

	6. A single SPACE (U+0020),
		followed by a LEFT CURLY BRACKET (U+007B).

	7. The result of performing [=serialize a CSS rule=]
		on each rule in cssRules,
		filtering out empty strings,
		each preceded by a single SPACE (U+0020).

		Note: [=Serialize a CSS rule=] can return an empty string
			when serializing an empty {{CSSFunctionDeclarations}} rule.

	8. A single SPACE (U+0020),
		followed by a single RIGHT CURLY BRACKET (U+007D).
</div>

<div algorithm>
To <dfn export>serialize a function parameter</dfn>,
return the concatenation of the following:

	1. The result of performing <a>serialize an identifier</a>
		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.
</div>

<div algorithm>
To <dfn export>serialize a CSS type</dfn>,
return the concatenation of the following:
	1. If the <<css-type>> consists of a single <<syntax-component>>,
		return the corresponding [[css-properties-values-api-1#syntax-strings|syntax string]].
	2. Otherwise,
		return the concatenation of the following:
			* The string <code>"type("</code>,
				i.e. <code>"type"</code>
				followed by a single LEFT PARENTHESIS (U+0028).
			* The corresponding [[css-properties-values-api-1#syntax-strings|syntax string]].
			* The string <code>")"</code>,
				i.e. a single RIGHT PARENTHESIS (U+0029).
</div>

The {{CSSFunctionDeclarations}} Interface {#the-function-declarations-interface}
--------------------------------------------------------------------------------

The {{CSSFunctionDeclarations}} interface represents a run
of consecutive [=declarations=] within a ''@function'' rule.

<xmp class=idl>
[Exposed=Window]
interface CSSFunctionDescriptors : CSSStyleDeclaration {
	attribute [LegacyNullToEmptyString] CSSOMString result;
};

[Exposed=Window]
interface CSSFunctionDeclarations : CSSRule {
	[SameObject, PutForwards=cssText] readonly attribute CSSFunctionDescriptors style;
};
</xmp>

<div algorithm>
	The <dfn attribute for=CSSFunctionDeclarations>style</dfn> 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=].
		<span class=note>This includes any [=local variables=].</span>
	: [=CSSStyleDeclaration/parent CSS rule=]
	:: [=this=]
	: [=CSSStyleDeclaration/owner node=]
	:: Null
</div>

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.

The {{CSSMixinRule}} Interface {#the-mixin-interface}
-----------------------------------------------------

The {{CSSMixinRule}} interface represents a ''@mixin'' rule.

<pre class='idl' export>
[Exposed=Window]
interface CSSMixinRule : CSSGroupingRule {
	readonly attribute CSSOMString name;
	sequence&lt;FunctionParameter&gt; getParameters();
	readonly attribute boolean contents;
};
</pre>

<dl dfn-for=CSSMixinRule>
	<dt><dfn dfn-type=attribute>name</dfn>
	<dd>
		The result of [=serialize an identifier=]
		on the [=mixin=]'s name.
	<dt><dfn dfn-type=method>getParameters()</dfn>
	<dd>
		Returns [=function parameters=] associated with the [=mixin=],
		excluding any '@contents' parameter.
	</dd>
	<dt><dfn dfn-type=attribute>contents</dfn>
	<dd>
		True if the [=mixin=] accepts a [=contents block=],
		and false otherwise.
</dl>

While declarations may be specified directly within a ''@mixin'' rule,
they are not represented as such in the CSSOM.
Instead, consecutive segments of declarations
appear as if wrapped in {{CSSNestedDeclarations}} rules.
<div class=note>
This is similar to
<a href="#function-declarations-example">how segments of bare declarations
within '@function' are wrapped</a>,
except with {{CSSNestedDeclarations}} as the wrapper
rather than {{CSSFunctionDeclarations}}.
</div>

<div algorithm>
To <dfn export>serialize a CSSMixinRule</dfn>,
return the concatenation of the following:

	1. The string <code>"@mixin"</code> followed by a single SPACE (U+0020).
	2. The result of performing <a>serialize an identifier</a>
		on the name of the [=mixin=],
		followed by a single LEFT PARENTHESIS (U+0028).
	3. The result of [=serialize a function parameter=]
		on each of the [=mixin's=] [=function parameter|parameters=],
		all joined by <code>", "</code>
		(COMMA U+002C, followed by a single SPACE U+0020).
	4. A single RIGHT PARENTHESIS (U+0029).
	5. A single LEFT CURLY BRACKET (U+007B),
		followed by a SPACE (U+0020).
	6. 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).
	7. A single SPACE (U+0020),
		followed by a single RIGHT CURLY BRACKET (U+007D).
</div>

The {{CSSApplyBlockRule}} Interface {#the-apply-block-interface}
----------------------------------------------------------------

The {{CSSApplyBlockRule}} interface represents
an ''@apply'' rule with a [=contents block=].

<pre class='idl' export>
[Exposed=Window]
interface CSSApplyBlockRule : CSSGroupingRule {
	readonly attribute CSSOMString name;
	sequence&lt;CSSOMString&gt; getArguments();
};
</pre>

<dl dfn-for=CSSApplyBlockRule>
	<dt><dfn dfn-type=attribute>name</dfn>
	<dd>
		If the ''@apply'' rule has an associated <<dashed-ident>>,
		the result of [=serialize an identifier=] on that [=ident=].
		Otherwise,
		the result of [=serialize an identifier=] on the name
		of the associated <<dashed-function>>.
	</dd>
	<dt><dfn dfn-type=method>getArguments()</dfn>
	<dd>
		Returns a sequence of arguments as strings,
		each item [[css-variables-1#serializing-custom-props|serialized]]
		as if it had been the specified value of a [=custom property=].
	</dd>
</dl>

The [=CSSRule/child CSS rules=] of a {{CSSApplyBlockRule}}
represent the [=contents block=]
of the ''@apply'' rule.

As for {{CSSMixinRule}},
consecutive segments of declarations
specified directly within the [=contents block=] of an ''@apply'' rule
are represented as {{CSSNestedDeclarations}}.

<div algorithm>
To <dfn export>serialize a CSSApplyBlockRule</dfn>,
return the concatenation of the following:

	1. The string <code>"@apply"</code> followed by a single SPACE (U+0020).
	2. The result of performing [=serialize an @apply prelude=]
		on the ''@apply'' rule.
	3. A single SPACE (U+0020).
	4. A single LEFT CURLY BRACKET (U+007B),
		followed by a SPACE (U+0020).
	5. 	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).
	6. A single SPACE (U+0020),
				followed by a RIGHT CURLY BRACKET (U+007D).
</div>

<div algorithm>
To <dfn export>serialize an @apply prelude</dfn>,
given an ''@apply'' rule,
return the concatenation of the following:

	1. The {{CSSApplyBlockRule/name}} of the ''@apply'' rule.
	2. If the ''@apply'' rule has at least one argument,
		the concatenation of:
		* A single LEFT PARENTHESIS (U+0028).
		* The result of performing [=serialize a function argument=]
			on each argument,
			all joined by <code>", "</code>.
		* A single RIGHT PARENTHESIS (U+0029).
</div>

<div algorithm>
To <dfn export>serialize a function argument</dfn>,
given a <<declaration-value>> |argument|:

	1. [[css-variables-1#serializing-custom-props|Serialize]] |argument|
			as if it had been the specified value of a [=custom property=],
			and let |serialized argument| be the result.
			<div class=note>
			This means that an argument serializes exactly as written,
			except with leading and trailing whitespace removed.
			</div>
	2. If |serialized argument| does not contain any top-level <<comma-token>>s,
		nor any top-level <<{-token>>s,
		return |serialized argument|.
	3. Otherwise, return the concatenation of the following:
		* A single LEFT CURLY BRACKET (U+007B),
				followed by a SPACE (U+0020).
		* The value of |serialized argument|.
		* A single SPACE (U+0020),
				followed by a RIGHT CURLY BRACKET (U+007D).

		<div class=note>
		See [[css-values-5#component-function-commas]] for more information
		on [=free-form productions=].
		</div>
</div>

The {{CSSApplyStatementRule}} Interface {#the-apply-statement-interface}
------------------------------------------------------------------------

The {{CSSApplyStatementRule}} interface represents
an ''@apply'' rule without a [=contents block=].

<pre class='idl' export>
[Exposed=Window]
interface CSSApplyStatementRule : CSSRule { 
	readonly attribute CSSOMString name;
	sequence&lt;CSSOMString&gt; getArguments();
};
</pre>

<dl dfn-for=CSSApplyStatementRule dfn-type=attribute>
	<dt><dfn>name</dfn>
	<dd>
		The same as {{CSSApplyBlockRule/name|CSSApplyBlockRule.name}}.
	</dd>
	<dt><dfn dfn-type=method>getArguments()</dfn>
	<dd>
		The same as {{CSSApplyBlockRule/getArguments()|CSSApplyBlockRule.getArguments()}}.
	</dd>
</dl>

<div algorithm>
To <dfn export>serialize a CSSApplyStatementRule</dfn>,
return the concatenation of the following:

	1. The string <code>"@apply"</code> followed by a single SPACE (U+0020).
	2. The result of performing [=serialize an @apply prelude=]
		on the ''@apply'' rule.
	3. A single SEMICOLON (U+003B).
</div>

The {{CSSContentsBlockRule}} Interface {#the-contents-block-interface}
---------------------------------------------------------------------

The {{CSSContentsBlockRule}} interface represents
a ''@contents'' rule with a [=fallback block=].

<pre class='idl' export>
[Exposed=Window]
interface CSSContentsBlockRule : CSSGroupingRule { };
</pre>

The [=CSSRule/child CSS rules=] of a {{CSSContentsBlockRule}}
represent the [=fallback block=]
of the ''@contents'' rule.

As for {{CSSMixinRule}} and {{CSSApplyBlockRule}},
consecutive segments of declarations
specified directly within the [=fallback block=] of a ''@contents'' rule
are represented as {{CSSNestedDeclarations}}.

<div algorithm>
To <dfn export>serialize a CSSContentsBlockRule</dfn>,
return the concatenation of the following:

	1. The string <code>"@contents"</code> followed by a single SPACE (U+0020).
	2. A single LEFT CURLY BRACKET (U+007B),
		followed by a SPACE (U+0020).
	3. 	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).
	4. A single SPACE (U+0020),
				followed by a RIGHT CURLY BRACKET (U+007D).
</div>

The {{CSSContentsStatementRule}} Interface {#the-contents-statement-interface}
------------------------------------------------------------------------------

The {{CSSContentsStatementRule}} interface represents
a ''@contents'' rule without a [=fallback block=].

<pre class='idl' export>
[Exposed=Window]
interface CSSContentsStatementRule : CSSRule { };
</pre>

<div algorithm>
To <dfn export>serialize a CSSContentsStatementRule</dfn>,
return the string <code>"@contents"</code>,
followed by a single SEMICOLON (U+003B).
</div>

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.

Changes {#changes}
===============================================

Changes since the <a href="https://www.w3.org/TR/2025/WD-css-mixins-1-20250515/">First Public Working Draft of 15 May 2025</a>:

* Made parentheses optional for mixins without parameters.
	(<a href="https://github.com/w3c/csswg-drafts/issues/13015">Issue 13015</a>)
* Added Web Platform Tests coverage
