@@ -348,10 +348,10 @@ Container Queries</h2>
348348 [=container queries=] allow testing aspects of elements within the document
349349 (such as box dimensions or computed styles).
350350
351- By default, all elements are [= query containers=]
351+ By default, all elements are <dfn export lt=" query container">query containers</dfn>
352352 for the purpose of [=container style queries=] ,
353353 and can be established as [=query containers=]
354- for [=container size queries=] by specifying
354+ for [=container size queries=] and [=container scroll-state queries=] by specifying
355355 the additional query types using the 'container-type' property
356356 (or the 'container' [=shorthand=] ).
357357 Style rules applying to a [=query container=] ’s [=flat tree=] descendants
@@ -385,9 +385,9 @@ Container Queries</h2>
385385 </div>
386386
387387 For the ''::part()'' and ''::slotted()'' <a>pseudo-element</a> selectors,
388- which represent real elements in the DOM tree, query containers can be
388+ which represent real elements in the DOM tree, [= query containers=] can be
389389 established by [=flat tree=] ancestors of those elements.
390- For other <a>pseudo-element</a> s, query containers can be established by
390+ For other <a>pseudo-element</a> s, [= query containers=] can be established by
391391 inclusive [=flat tree=] ancestors of their <a>originating element</a> .
392392
393393 <div class=note>
@@ -461,28 +461,20 @@ Creating Query Containers: the 'container-type' property</h3>
461461
462462 <pre class='propdef'>
463463 Name : container-type
464- Value : normal | size | inline-size
464+ Value : normal | [ [ size | inline-size ] || scroll-state ]
465465 Initial : normal
466466 Inherited : no
467467 Applies to : all elements
468468 Computed value : specified keyword
469469 Animation type : not animatable
470470 </pre>
471471
472- The 'container-type' property establishes the element
473- as a <dfn export>query container</dfn>
474- for the purpose of [=container queries=] that require explicit containment
475- (such as [=container size queries=] ),
476- allowing [=style rules=] styling its descendants
477- to query various aspects of its sizing and layout,
478- and respond accordingly.
479-
480- Unless otherwise noted,
481- all elements are [=query containers=]
482- for the purpose of [=container queries=]
483- that do not require explicit [=containment=]
484- (such as [=container style queries=] ),
485- regardless of the specified 'container-type' .
472+ The 'container-type' property establishes the element as a
473+ [=query container=] for certain types of queries. For size
474+ [=container queries=] , which require certain types of containment, elements
475+ are explicitly made [=query containers=] through this property. For other
476+ types of [=query containers=] any element can be a [=query container=] , such
477+ as for [=container style queries=] .
486478
487479 Values have the following meanings:
488480
@@ -503,10 +495,13 @@ Creating Query Containers: the 'container-type' property</h3>
503495 [=style containment=] ,
504496 and [=inline-size containment=]
505497 to the [=principal box=] .
498+ <dt> <dfn>scroll-state</dfn>
499+ <dd>
500+ Establishes a [=query container=] for [=scroll-state queries=]
506501 <dt> <dfn>normal</dfn>
507502 <dd>
508503 The element is not a [=query container=]
509- for any [=container size queries=] ,
504+ for any [=container size queries=] or [=scroll-state queries=] ,
510505 but remains a [=query container=] for [=container style queries=] .
511506 </dl>
512507
@@ -547,6 +542,23 @@ Creating Query Containers: the 'container-type' property</h3>
547542 </pre>
548543 </div>
549544
545+ <div class=example>
546+ Containers can also expose state that depends on scroll offset. This example
547+ styles a descendant of a sticky positioned element when it is stuck to the
548+ top edge:
549+
550+ <pre class=lang-css>
551+ #sticky {
552+ container-type: scroll-state;
553+ position: sticky;
554+ }
555+ @container scroll-state(stuck: top) {
556+ #sticky-child {
557+ background-color: lime;
558+ }
559+ }
560+ </pre>
561+ </div>
550562
551563<h3 id="container-name">
552564Naming Query Containers: the 'container-name' property</h3>
@@ -658,19 +670,27 @@ Container Queries: the ''@container'' rule</h3>
658670 <pre class="prod def">
659671 <dfn><<container-condition>></dfn> = [ <<container-name>> ]? <<container-query>>
660672 <dfn><<container-name>></dfn> = <<custom-ident>>
661- <dfn><<container-query>></dfn> = not <<query-in-parens>>
662- | <<query-in-parens>> [ [ and <<query-in-parens>> ]* | [ or <<query-in-parens>> ]* ]
663- <dfn><<query-in-parens>></dfn> = ( <<container-query>> )
664- | ( <<size-feature>> )
665- | style( <<style-query>> )
666- | <<general-enclosed>>
667-
668- <dfn><<style-query>></dfn> = not <<style-in-parens>>
669- | <<style-in-parens>> [ [ and <<style-in-parens>> ]* | [ or <<style-in-parens>> ]* ]
670- | <<style-feature>>
671- <dfn><<style-in-parens>></dfn> = ( <<style-query>> )
672- | ( <<style-feature>> )
673- | <<general-enclosed>>
673+ <dfn><<container-query>></dfn> = not <<query-in-parens>>
674+ | <<query-in-parens>> [ [ and <<query-in-parens>> ]* | [ or <<query-in-parens>> ]* ]
675+ <dfn><<query-in-parens>></dfn> = ( <<container-query>> )
676+ | ( <<size-feature>> )
677+ | style( <<style-query>> )
678+ | scroll-state( <<scroll-state-query>> )
679+ | <<general-enclosed>>
680+
681+ <dfn><<style-query>></dfn> = not <<style-in-parens>>
682+ | <<style-in-parens>> [ [ and <<style-in-parens>> ]* | [ or <<style-in-parens>> ]* ]
683+ | <<style-feature>>
684+ <dfn><<style-in-parens>></dfn> = ( <<style-query>> )
685+ | ( <<style-feature>> )
686+ | <<general-enclosed>>
687+
688+ <dfn><<scroll-state-query>></dfn> = not <<scroll-state-in-parens>>
689+ | <<scroll-state-in-parens>> [ [ and <<scroll-state-in-parens>> ]* | [ or <<scroll-state-in-parens>> ]* ]
690+ | <<scroll-state-feature>>
691+ <dfn><<scroll-state-in-parens>></dfn> = ( <<scroll-state-query>> )
692+ | ( <<scroll-state-feature>> )
693+ | <<general-enclosed>>
674694 </pre>
675695
676696 The keywords ''container-name/none'' , ''and'' , ''not'' , and ''or''
@@ -1068,6 +1088,185 @@ Style Container Features</h3>
10681088 are [=computed value|computed=] with respect to the [=query container=] ,
10691089 the same as other values.
10701090
1091+ <h3 id="scroll-state-container">
1092+ Scroll State Container Features</h3>
1093+
1094+ A <dfn export>container scroll-state query</dfn> allows querying a container for
1095+ state that depends on scroll position. It is a boolean combination of
1096+ individual <dfn lt="scroll-state feature">scroll-state features</dfn>
1097+ (<<scroll-state-feature>> ) that each query a single feature of the
1098+ [=query container=] . The syntax of a <dfn><<scroll-state-feature>></dfn> is the
1099+ same as for a [=media feature=] : a feature name, a comparator, and a value.
1100+
1101+ [=Scroll-state features=] can either match state of the scroller itself,
1102+ or an element that is affected by the scroll position of an ancestor
1103+ [=scroll container's=] [=scrollport=] . An example of the former is the
1104+ ''overflowing'' feature, ''snapped'' the latter.
1105+
1106+ <h4 id="updating-scroll-state">
1107+ Updating Scroll State</h4>
1108+
1109+ Issue(10796): This section is subject to change as a result of resolving
1110+ the issue of unifying scroll-snapshotting layout state across several specifications.
1111+
1112+ Scroll state may cause layout cycles since queried scroll state may cause style changes,
1113+ which may lead to scroll state changes as a result of layout. The same issue exists for
1114+ [=scroll progress timelines=] , and scroll state is handled in a similar manner.
1115+
1116+ To avoid such layout cycles, ''scroll-state'' [=query containers=] update their
1117+ current state once as the last step of [=run the scroll steps=] . Then, after the
1118+ resizeObserver loop in the
1119+ <a href="https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model">HTML event loop processing model</a> ,
1120+ update the current state of every ''scroll-state'' [=query container=] .
1121+ If that state has changed since the scroll state update in [=run the scroll steps=] ,
1122+ re-run the style and layout update a single time if necessary.
1123+
1124+ <h4 id="stuck">
1125+ Sticky positioning: the '@container/stuck' feature</h4>
1126+
1127+ <pre class="descdef mq">
1128+ Name : stuck
1129+ For : @container
1130+ Value : top | right | bottom | left | block-start | inline-start | block-end | inline-end
1131+ Type : discrete
1132+ </pre>
1133+
1134+ The '@container/stuck' [=container feature=] queries whether a
1135+ ''position/sticky'' positioned container is visually shifted to stay inside
1136+ the [=sticky view rectangle=] for the given edge. The logical edges map to
1137+ physical based on the direction and writing-mode of the [=query container=] .
1138+ None of the values match if the [=query container=] is not [=sticky positioned=] .
1139+
1140+ It is possible for two values from opposite axes to match at the same time,
1141+ but not for opposite edges along the same axis.
1142+
1143+ <div class=example>
1144+ May match:
1145+ <pre class="lang-css">
1146+ @container scroll-state((stuck: top) and (stuck: left)) { ... }
1147+ </pre>
1148+
1149+ Will never match:
1150+ <pre class="lang-css">
1151+ @container scroll-state((stuck: left) and (stuck: right)) { ... }
1152+ </pre>
1153+ </div>
1154+
1155+ In the boolean context, the query matches if visual shift is applied in any
1156+ direction.
1157+
1158+ <dl dfn-type=value dfn-for="@container/stuck">
1159+ <dt> <dfn>top</dfn>
1160+ <dd>
1161+ The ''position/sticky'' container is shifted to stay inside the top edge.
1162+ <dt> <dfn>right</dfn>
1163+ <dd>
1164+ The ''position/sticky'' container is shifted to stay inside the right edge.
1165+ <dt> <dfn>bottom</dfn>
1166+ <dd>
1167+ The ''position/sticky'' container is shifted to stay inside the bottom edge.
1168+ <dt> <dfn>left</dfn>
1169+ <dd>
1170+ The ''position/sticky'' container is shifted to stay inside the left edge.
1171+ <dt> <dfn>block-start</dfn>
1172+ <dd>
1173+ The ''position/sticky'' container is shifted to stay inside the [=block-start=] edge.
1174+ <dt> <dfn>inline-start</dfn>
1175+ <dd>
1176+ The ''position/sticky'' container is shifted to stay inside the [=inline-start=] edge.
1177+ <dt> <dfn>block-end</dfn>
1178+ <dd>
1179+ The ''position/sticky'' container is shifted to stay inside the [=block-end=] edge.
1180+ <dt> <dfn>inline-end</dfn>
1181+ <dd>
1182+ The ''position/sticky'' container is shifted to stay inside the [=inline-end=] edge.
1183+ </dl>
1184+
1185+ <h4 id="snapped">
1186+ Scroll snapping: the '@container/snapped' feature</h4>
1187+
1188+ <pre class="descdef mq">
1189+ Name : snapped
1190+ For : @container
1191+ Value : x | y | block | inline
1192+ Type : discrete
1193+ </pre>
1194+
1195+ The '@container/snapped' [=container feature=] queries whether a [=snap target=]
1196+ is snapped to its [=snap container=] in the given axis. It matches in the boolean
1197+ context if it is snapped in at least one of the directions.
1198+
1199+ <dl dfn-type=value dfn-for="@container/snapped">
1200+ <dt> <dfn>x</dfn>
1201+ <dd>
1202+ '@container/snapped' [=container feature=] matches ''x''
1203+ if the [=query container=] is a horizontal [=snap target=] for its [=scroll container=]
1204+ <dt> <dfn>y</dfn>
1205+ <dd>
1206+ '@container/snapped' [=container feature=] matches ''y''
1207+ if the [=query container=] is a vertical [=snap target=] for its [=scroll container=]
1208+ <dt> <dfn>block</dfn>
1209+ <dd>
1210+ '@container/snapped' [=container feature=] matches ''block''
1211+ if the [=query container=] is a [=snap target=] for its [=scroll container=]
1212+ in the block direction of the [=snap container=] .
1213+ <dt> <dfn>inline</dfn>
1214+ <dd>
1215+ '@container/snapped' [=container feature=] matches ''inline''
1216+ if the [=query container=] is a [=snap target=] for its [=scroll container=]
1217+ in the inline direction of the [=snap container=] .
1218+ </dl>
1219+
1220+ <h4 id="overflowing">
1221+ Overflowing: the '@container/overflowing' feature</h4>
1222+
1223+ <pre class="descdef mq">
1224+ Name : overflowing
1225+ For : @container
1226+ Value : top | right | bottom | left | block-start | inline-start | block-end | inline-end
1227+ Type : discrete
1228+ </pre>
1229+
1230+ The '@container/overflowing' [=container feature=] queries whether a
1231+ [=scroll container=] has clipped [=scrollable overflow rectangle=] content
1232+ in the given direction which is reachable through user initiated scrolling.
1233+ That is, '@container/overflowing' does not match for a ''overflow/hidden''
1234+ container, nor for a [=negative scrollable overflow region=] .
1235+
1236+ The logical values map to physical based on the direction and writing-mode of
1237+ the [=query container=] . None of the values match if the container is not a
1238+ [=scroll container=] .
1239+
1240+ In the boolean context, the query matches if any of the values match.
1241+
1242+ <dl dfn-type=value dfn-for="@container/overflowing">
1243+ <dt> <dfn>top</dfn>
1244+ <dd>
1245+ The [=scroll container=] has [=scrollable overflow=] past the top edge.
1246+ <dt> <dfn>right</dfn>
1247+ <dd>
1248+ The [=scroll container=] has [=scrollable overflow=] past the right edge.
1249+ <dt> <dfn>bottom</dfn>
1250+ <dd>
1251+ The [=scroll container=] has [=scrollable overflow=] past the bottom edge.
1252+ <dt> <dfn>left</dfn>
1253+ <dd>
1254+ The [=scroll container=] has [=scrollable overflow=] past the left edge.
1255+ <dt> <dfn>block-start</dfn>
1256+ <dd>
1257+ The [=scroll container=] has [=scrollable overflow=] past the [=block-start=] edge.
1258+ <dt> <dfn>inline-start</dfn>
1259+ <dd>
1260+ The [=scroll container=] has [=scrollable overflow=] past the [=inline-start=] edge.
1261+ <dt> <dfn>block-end</dfn>
1262+ <dd>
1263+ The [=scroll container=] has [=scrollable overflow=] past the [=block-end=] edge.
1264+ <dt> <dfn>inline-end</dfn>
1265+ <dd>
1266+ The [=scroll container=] has [=scrollable overflow=] past the [=inline-end=] edge.
1267+ </dl>
1268+
1269+
10711270<h2 id="container-lengths">
10721271Container Relative Lengths: the ''cqw'', ''cqh'', ''cqi'', ''cqb'', ''cqmin'', ''cqmax'' units</h2>
10731272
0 commit comments