@@ -247,15 +247,11 @@ and the optional [=custom function/return type=] is given by the <<css-type>> fo
247
247
</xmp>
248
248
</div>
249
249
250
-
251
250
The name of a ''@function'' rule is a [=tree-scoped name=] .
252
251
If more than one ''@function'' exists for a given name,
253
252
then the rule in the stronger cascade layer wins,
254
253
and rules defined later win within the same layer.
255
254
256
-
257
-
258
-
259
255
If the [=function parameters=]
260
256
contain the same <<custom-property-name>> more than once,
261
257
then the ''@function'' rule is invalid.
@@ -791,6 +787,368 @@ or acting as if nothing exists at that location otherwise.
791
787
</pre>
792
788
</div>
793
789
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
+
794
1152
<!-- Big Text: cssom
795
1153
796
1154
███▌ ███▌ ███▌ ███▌ █ █
0 commit comments