@@ -247,15 +247,11 @@ and the optional [=custom function/return type=] is given by the <<css-type>> fo
247247 </xmp>
248248</div>
249249
250-
251250The name of a ''@function'' rule is a [=tree-scoped name=] .
252251If more than one ''@function'' exists for a given name,
253252then the rule in the stronger cascade layer wins,
254253and rules defined later win within the same layer.
255254
256-
257-
258-
259255If the [=function parameters=]
260256contain the same <<custom-property-name>> more than once,
261257then the ''@function'' rule is invalid.
@@ -791,6 +787,368 @@ or acting as if nothing exists at that location otherwise.
791787 </pre>
792788</div>
793789
790+
791+ <!-- Big Text: @mixin
792+
793+ ████▌ █ █ ████ █ █ ████ █ █▌
794+ █▌ █▌ ██ ██ ▐▌ █ █ ▐▌ █▌ █▌
795+ █▌▐█ █▌ █▌█ █▐█ ▐▌ █ █ ▐▌ ██▌ █▌
796+ █▌▐█ █▌ █▌ █ ▐█ ▐▌ █ ▐▌ █▌▐█ █▌
797+ █▌ ██▌ █▌ ▐█ ▐▌ █ █ ▐▌ █▌ ██▌
798+ █▌ █▌ ▐█ ▐▌ █ █ ▐▌ █▌ █▌
799+ ████▌ █▌ ▐█ ████ █ █ ████ █▌ ▐▌
800+ -->
801+
802+ <h2 id=defining-mixins>
803+ Defining Mixins</h2>
804+
805+ A [=mixin=] is in many ways similar to a [=custom function=] ,
806+ but rather than extending/upgrading [=custom properties=] ,
807+ [=mixins=] extend/upgrade [=nested style rules=] ,
808+ making them reusable and customizable with arguments.
809+
810+ <div class=example>
811+ For example, the following code sets up a mixin
812+ applying all the properties you need for a "gradient text" effect,
813+ including guarding it with [=supports queries=] :
814+
815+ <pre highlight=css>
816+ @mixin --gradient-text(
817+ --from type(color): mediumvioletred,
818+ --to type(color): teal,
819+ --angle: to bottom right,
820+ ) {
821+ color: env(--from, env(--to));
822+
823+ @supports (background-clip: text) or (-webkit-background-clip: text) {
824+ @env --gradient: linear-gradient(env(--angle), env(--from), env(--to));
825+ background: env(--gradient, env(--from));
826+ color: transparent;
827+ -webkit-background-clip: text;
828+ background-clip: text;
829+ }
830+ }
831+
832+ h1 {
833+ @apply --gradient-text(pink, powderblue);
834+ }
835+ </pre>
836+
837+ Note that this example also uses a [=scoped environment variable=]
838+ (along with the arguments, which implicitly define [=scoped environment variables=] )
839+ which is scoped to <em> the rule itself</em>
840+ (rather than being applied to the element, like a [=custom property=] would be)
841+ to hold a temporary value to aid in readability of the [=mixin=] ,
842+ without polluting the element's styles with unwanted [=custom properties=] .
843+
844+ This is exactly equivalent to writing a [=nested style rule=] literally into the `h1` styles:
845+
846+ <pre highlight=css>
847+ h1 {
848+ & {
849+ @env --from: pink;
850+ @env --to: powderblue;
851+ @env --angle: to bottom right;
852+ color: env(--from, env(--to));
853+
854+ @supports (background-clip: text) or (-webkit-background-clip: text) {
855+ @env --gradient: linear-gradient(env(--angle), env(--from), env(--to));
856+ background: env(--gradient, env(--from));
857+ color: transparent;
858+ -webkit-background-clip: text;
859+ background-clip: text;
860+ }
861+ }
862+ }
863+ </pre>
864+ </div>
865+
866+ Issue: The entire ''@mixin'' feature is experimental and under active development,
867+ and is much less stable than ''@function'' .
868+ Expect things to change frequently for now.
869+
870+
871+ <h3 id=mixin-rule>
872+ The <dfn>@mixin</dfn> rule</h3>
873+
874+ The ''@mixin'' rule defines a <dfn>mixin</dfn> ,
875+ and consists of a name,
876+ a list of [=mixin parameters=] ,
877+ and a [=mixin body=] .
878+ (Identical to ''@function'' ,
879+ save that it lacks a [=custom function/return type=] .)
880+
881+ <pre class="prod def">
882+ <<@mixin>> = @mixin <<function-token>> <<function-parameter>> #? )
883+ {
884+ <<declaration-rule-list>>
885+ }
886+ </pre>
887+
888+ If a [=default value=] and a [=parameter type=] are both provided,
889+ then the default value must parse successfully according to that parameter type’s syntax.
890+ Otherwise, the ''@mixin'' rule is invalid.
891+
892+ <h4 id=mixin-preamble>
893+ The Mixin Preamble</h4>
894+
895+ The <<function-token>> production
896+ must start with two dashes (U+002D HYPHEN-MINUS),
897+ similar to <<dashed-ident>> ,
898+ or else the definition is invalid.
899+
900+ The name of the resulting [=mixin=] is given by the name of the <<function-token>> ,
901+ the optional [=mixin parameters=]
902+ are given by the <<function-parameter>> values
903+ (defaulting to an empty set).
904+
905+ The name of a ''@mixin'' rule is a [=tree-scoped name=] .
906+ If more than one ''@mixin'' exists for a given name,
907+ then the rule in the stronger cascade layer wins,
908+ and rules defined later win within the same layer.
909+
910+ If the [=mixin parameters=]
911+ contain the same <<custom-property-name>> more than once,
912+ then the ''@mixin'' rule is invalid.
913+
914+ <h4 id=mixin-body dfn lt="mixin body" export>
915+ The Mixin Body</h4>
916+
917+ The body of a ''@mixin'' rule acts as a [=nested style rule=] ,
918+ and accepts the same properties and rules
919+ that a normal [=nested style rule=] would.
920+
921+ In particular, further [=mixins=] can be invoked
922+ (via the ''@apply'' rule)
923+ within a [=mixin body=] .
924+
925+ Unknown properties and rules are invalid and ignored,
926+ but do not make the ''@mixin'' rule itself invalid.
927+
928+ <h3 id=mixin-args dfn lt="mixin parameter" export>
929+ Mixin Parameters</h3>
930+
931+ Within a [=mixin body=] ,
932+ the ''env()'' function can access [=scoped environment variables=]
933+ defined within the [=mixin body=] ,
934+ defined by the mixin's arguments,
935+ or those defined at the <em> call site</em>
936+ (a style rule, or another [=mixin=] ).
937+
938+ In that list, earlier things "win" over later things of the same name,
939+ exactly as if the [=mixin body=] was a [=nested style rule=]
940+ placed at its call site.
941+ Specifically, it desugars to <em> two</em> [=nested style rules=] ,
942+ to correctly reproduce the argument scope
943+
944+ <div class=example>
945+ For example, the following mixin use:
946+
947+ <xmp highlight=css>
948+ @mixin --nested(--color2: green) {
949+ @env --color3: blue;
950+ background: linear-gradient(env(--color1), env(--color2), env(--color3));
951+ }
952+ p.nested {
953+ @env --color1: red;
954+ @apply --nested();
955+ }
956+ </xmp>
957+
958+ is exactly equivalent to:
959+
960+ <xmp highlight=css>
961+ p.nested {
962+ @env --color1: red;
963+ & {
964+ @env --color2: green;
965+ & {
966+ @env --color3: blue;
967+ background: linear-gradient(env(--color1), env(--color2), env(--color3));
968+ }
969+ }
970+ }
971+ </xmp>
972+ </div>
973+
974+ <div class=example>
975+ [=Scoped environment variables=] defined in mixins can "shadow" ones defined higher up,
976+ just like they can in [=nested style rules=] normally
977+ (and like how variables can be shadowed in [=custom functions=] ):
978+
979+ <xmp class='lang-css'>
980+ @mixin --z-index-a-b-c(--b, --c) {
981+ @env --c: 300;
982+ z-index: calc(env(--a) + env(--b) + env(--c));
983+ /* uses the --a from the call site's envs,
984+ the --b from the mixin parameter,
985+ and the --c from the local env */
986+ }
987+ div {
988+ @env --a: 1;
989+ @env --b: 2;
990+ @env --c: 3;
991+ @apply --add-a-b-c(20, 30); /* 321 */
992+ }
993+ </xmp>
994+ </div>
995+
996+ <div class=example>
997+ Note that [=mixin parameters=] are [=scoped environment variables=]
998+ rather than [=custom properties=] ,
999+ which means they exist in a separate namespace
1000+ and don't interfere with [=custom properties=] .
1001+ They can even be used together.
1002+
1003+ For example, this code shows how to use a [=custom property=]
1004+ as the fallback for a [=mixin parameter=] :
1005+
1006+ <pre highlight=css>
1007+ @mixin --var-fallback(--arg: var(--arg)) {
1008+ /* TODO: come up with a believable example */
1009+ }
1010+ </pre>
1011+ </div>
1012+
1013+
1014+ Using Mixins {#using-mixins}
1015+ ============================
1016+
1017+ The result of a [=mixin=] application
1018+ is substituted into the body of another [=style rule=]
1019+ as a [=nested style rule=]
1020+ via the ''@apply'' rule.
1021+
1022+ <h3 id=apply-rule>
1023+ The <dfn>@apply</dfn> Rule</h3>
1024+
1025+ The ''@apply'' rule applies a [=mixin=] ,
1026+ causing it to substitute into the rule
1027+ in place of the ''@apply'' rule itself.
1028+
1029+ Its grammar is:
1030+
1031+ <pre class="prod">
1032+ <<@apply>> = @apply <<dashed-function>> ;
1033+ </pre>
1034+
1035+ The ''@apply'' rule is only valid
1036+ in the body of a [=style rule=]
1037+ or [=nested group rule=] ;
1038+ using it in any other context causes it to be invalid and ignored.
1039+
1040+ ''@apply'' rules are processed <em> before</em> any styles are applied,
1041+ as they effectively modify the stylesheet itself.
1042+ (Similar, in effect, to how [=conditional group rules=]
1043+ adjust which properties and rules are active in a stylesheet
1044+ before styles are applied.)
1045+
1046+ The ''@apply'' rule applies the [=mixin=]
1047+ named by the <<dashed-function>> 's name.
1048+ If no such [=mixin=] exists,
1049+ the ''@apply'' does nothing.
1050+
1051+ The arguments passed to the <<dashed-function>>
1052+ are mapped to the [=mixin's=] arguments;
1053+ if more arguments are passed than the length of the [=mixin's=] argument list,
1054+ the ''@apply'' application does nothing.
1055+ (Passing too few arguments is fine;
1056+ the missing arguments take their default values instead.)
1057+
1058+
1059+ <!-- Big Text: @env
1060+
1061+ ████▌ █████▌ █ █▌ █▌ █▌
1062+ █▌ █▌ █▌ █▌ █▌ █▌ █▌
1063+ █▌▐█ █▌ █▌ ██▌ █▌ █▌ █▌
1064+ █▌▐█ █▌ ████ █▌▐█ █▌ ▐▌ █
1065+ █▌ ██▌ █▌ █▌ ██▌ █ ▐▌
1066+ █▌ █▌ █▌ █▌ ▐▌ █
1067+ ████▌ █████▌ █▌ ▐▌ ▐█
1068+ -->
1069+
1070+ Scoped Environment Variables {#scoped-env}
1071+ ============================
1072+
1073+ Issue: This section should move to [[css-env-1]]
1074+ (or level 2, whatever).
1075+
1076+ The ''env()'' function,
1077+ defined in [[css-env-1]] ,
1078+ allows substituting the value of [=environment variables=]
1079+ into a stylesheet.
1080+ These are "global" variables,
1081+ defined by the <l spec=infra> [=user agent=] </l> ,
1082+ rather than [=custom properties=]
1083+ defined by the page author on individual elements (and their descendants).
1084+
1085+ The ''@env'' rule allows defining <dfn>scoped environment variables</dfn> ,
1086+ which are <em> lexically scoped</em> to a single rule in a stylesheet
1087+ (and any [=nested style rules=] within it).
1088+
1089+ Issue: A top-level ''@env'' probably needs to still be lexically scoped to just the stylesheet itself.
1090+ (After all, you can use `media=""` to link in a stylesheet
1091+ *effectively* auto-wrapped in an ''@media'' ,
1092+ and it would be weird to have that act differently
1093+ from actually using a wrapping ''@media'' .)
1094+ That means only JS-defined custom envs are available cross-stylesheet.
1095+
1096+
1097+ <h3 id=env-rule>
1098+ The <dfn>@env</dfn> Rule</h3>
1099+
1100+ The ''@env'' rule defines a [=scoped environment variable=] ,
1101+ scoped to its parent rule
1102+ (and any other nested rule within its parent rule).
1103+ It's only valid within a [=nested style rule=]
1104+ or [=nested group rule=] ,
1105+ or at the "top level" of a stylesheet not nested in anything;
1106+ in any other context it's invalid and ignored.
1107+ Its grammar is:
1108+
1109+ <pre class=prod>
1110+ <<@env>> = @env <<custom-property-name>> : <<declaration-value>> ? ;
1111+ </pre>
1112+
1113+ This defines a [=scoped environment variable=]
1114+ with a name given by the <<custom-property-name>> ,
1115+ and a value given by the <css> <<declaration-value>> ?</css> .
1116+ Its scope is the rule it's nested in,
1117+ or the stylesheet it's defined in
1118+ if it's not nested.
1119+
1120+ <h4 id=using-scoped-env>
1121+ Using Scoped Environment Variables</h4>
1122+
1123+ When an ''env()'' function is used
1124+ with a <<dashed-ident>> as the name of the environment variable,
1125+ it's potentially accessing a [=scoped environment variable=] .
1126+
1127+ First the parent rule
1128+ of the property or rule the ''env()'' is used in
1129+ is checked to see if a [=scoped environment variable=] of that name
1130+ exists scoped to that rule.
1131+ If not,
1132+ its parent rule is checked,
1133+ recursively,
1134+ until finally the stylesheet itself is checked.
1135+ If that fails,
1136+ the global [=environment variables=] are finally checked.
1137+
1138+ Note: Custom global [=environment variables=] can be defined by the <code> CSS.customEnv</code> API.
1139+ (To be defined.)
1140+
1141+ Issue: Need some analogue to ''inherit'' ,
1142+ but for the parent lexical scopes.
1143+ Probably can't use ''inherit'' itself,
1144+ as that's a meaningful value that an ''env()'' could resolve to,
1145+ I guess?
1146+
1147+
1148+
1149+
1150+
1151+
7941152<!-- Big Text: cssom
7951153
7961154 ███▌ ███▌ ███▌ ███▌ █ █
0 commit comments