From 6b08d4af75749a86e0ee1fd3d760ca0fdb497e5c Mon Sep 17 00:00:00 2001
From: Rune Lillesveen
Date: Mon, 5 Aug 2024 12:47:39 +0200
Subject: [PATCH 1/6] [css-conditional-5] Draft spec for scroll-state() #6402
Per resolution in [1], add scroll-state() as a query function to query
sticky, snap, and overflow scroll states with a new container-type for
scroll-state queries.
[1] https://github.com/w3c/csswg-drafts/issues/6402#issuecomment-1812973013
---
css-conditional-5/Overview.bs | 231 +++++++++++++++++++++++++++++-----
1 file changed, 202 insertions(+), 29 deletions(-)
diff --git a/css-conditional-5/Overview.bs b/css-conditional-5/Overview.bs
index bc8e240f780..4c998a2b4fd 100644
--- a/css-conditional-5/Overview.bs
+++ b/css-conditional-5/Overview.bs
@@ -460,7 +460,7 @@ Creating Query Containers: the 'container-type' property
Name: container-type
- Value: normal | size | inline-size
+ Value: normal | [ [ size | inline-size ] || scroll-state ]
Initial: normal
Inherited: no
Applies to: all elements
@@ -468,20 +468,12 @@ Creating Query Containers: the 'container-type' property
Animation type: not animatable
- The 'container-type' property establishes the element
- as a query container
- for the purpose of [=container queries=] that require explicit containment
- (such as [=container size queries=]),
- allowing [=style rules=] styling its descendants
- to query various aspects of its sizing and layout,
- and respond accordingly.
-
- Unless otherwise noted,
- all elements are [=query containers=]
- for the purpose of [=container queries=]
- that do not require explicit [=containment=]
- (such as [=container style queries=]),
- regardless of the specified 'container-type'.
+ The 'container-type' property establishes the element as a
+ query container for certain types of queries. For size
+ [=container queries=], that require certain types of containment, elements
+ are explicitly made [=query containers=] through this property. For other
+ types of [=query containers=] any element can be a query container, such as
+ for [=container style queries=].
Values have the following meanings:
@@ -502,10 +494,13 @@ Creating Query Containers: the 'container-type' property
[=style containment=],
and [=inline-size containment=]
to the [=principal box=].
+ scroll-state
+
+ Establishes a [=query container=] for [=scroll-state queries=]
normal
The element is not a [=query container=]
- for any [=container size queries=],
+ for any [=container size queries=] or [=scroll-state queries=],
but remains a [=query container=] for [=container style queries=].
@@ -546,6 +541,23 @@ Creating Query Containers: the 'container-type' property
+
+ Containers can also expose state that depend on scroll offset. Here is an
+ example of how to style a descendant of a sticky positioned element when it
+ is stuck to the top edge:
+
+
+ #sticky {
+ container-type: scroll-state;
+ position: sticky;
+ }
+ @container scroll-state(stuck: top) {
+ #sticky-child {
+ background-color: lime;
+ }
+ }
+
+
Naming Query Containers: the 'container-name' property
@@ -657,19 +669,27 @@ Container Queries: the ''@container'' rule
<> = [ <> ]? <>
<> = <>
- <> = not <>
- | <> [ [ and <> ]* | [ or <> ]* ]
- <> = ( <> )
- | ( <> )
- | style( <> )
- | <>
-
- <> = not <>
- | <> [ [ and <> ]* | [ or <> ]* ]
- | <>
- <> = ( <> )
- | ( <> )
- | <>
+ <> = not <>
+ | <> [ [ and <> ]* | [ or <> ]* ]
+ <> = ( <> )
+ | ( <> )
+ | style( <> )
+ | scroll-state( <> )
+ | <>
+
+ <> = not <>
+ | <> [ [ and <> ]* | [ or <> ]* ]
+ | <>
+ <> = ( <> )
+ | ( <> )
+ | <>
+
+ <> = not <>
+ | <> [ [ and <> ]* | [ or <> ]* ]
+ | <>
+ <> = ( <> )
+ | ( <> )
+ | <>
The keywords ''container-name/none'', ''and'', ''not'', and ''or''
@@ -1067,6 +1087,159 @@ Style Container Features
are [=computed value|computed=] with respect to the [=query container=],
the same as other values.
+
+
+ A container scroll-state query allows to query a container for various
+ state that depends on scroll position. The ''scroll-state'' [=query container=] can either
+ be the scroller itself, or an element that is affected by the scroll position of an ancestor
+ [=scroll container's=] [=scrollport=].
+
+
+
+ Note: This section is subject to change as a result of resolving
+
issue #10796
+
+
+ Scroll state may cause layout cycles since queried scroll state may cause style changes,
+ which may lead to scroll state changes as a result of layout. The same issue exists for
+ [=scroll progress timelines=], and scroll state is handled in a similar manner.
+
+ To avoid such layout cycles, ''scroll-state'' [=query containers=] update their
+ current state once as the last step of [=run the scroll steps=]. Then, after the
+ resizeObserver loop in the
+ HTML event loop processing model,
+ the scroll state of every ''scroll-state'' [=query container=] is updated.
+ If that state has changed since the scroll state update in [=run the scroll steps=],
+ re-run the style and layout update if necessary.
+
+
+Sticky positioning: the '@container/stuck' feature
+
+
+ Name: stuck
+ For: @container
+ Value: top | right | bottom | left | block-start | inline-start | block-end | inline-end
+ Type: discrete
+
+
+ The '@container/stuck' [=container feature=] queries whether a
+ ''position/sticky'' positioned container is visually shifted to stay inside
+ the [=sticky view rectangle=] for the given edge. The logical edges map to
+ physical based on the direction and writing-mode of the [=query container=].
+
+ In the boolean context, the query matches if visual shift is applied in any
+ direction.
+
+
+ - top
+
-
+ The ''position/sticky'' container is shifted to stay inside the top edge.
+
- right
+
-
+ The ''position/sticky'' container is shifted to stay inside the right edge.
+
- bottom
+
-
+ The ''position/sticky'' container is shifted to stay inside the bottom edge.
+
- left
+
-
+ The ''position/sticky'' container is shifted to stay inside the left edge.
+
- block-start
+
-
+ The ''position/sticky'' container is shifted to stay inside the block-start edge.
+
- inline-start
+
-
+ The ''position/sticky'' container is shifted to stay inside the inline-start edge.
+
- block-end
+
-
+ The ''position/sticky'' container is shifted to stay inside the block-end edge.
+
- inline-end
+
-
+ The ''position/sticky'' container is shifted to stay inside the inline-end edge.
+
+
+
+Scroll snapping: the '@container/snapped' feature
+
+
+ Name: snapped
+ For: @container
+ Value: x | y | block | inline
+ Type: discrete
+
+
+ The '@container/snapped' [=container feature=] queries whether a [=snap target=]
+ is snapped to its [=snap container=] in the given axis. It matches in the boolean
+ context if it is snapped in at least one of the directions.
+
+
+ - x
+
-
+ '@container/snapped' [=container feature=] matches ''x''
+ if the container is a horizontal [=snap target=] for its [=scroll container=]
+
- y
+
-
+ '@container/snapped' [=container feature=] matches ''y''
+ if the container is a vertical [=snap target=] for its [=scroll container=]
+
- block
+
-
+ '@container/snapped' [=container feature=] matches ''block''
+ if the container is a [=snap target=] for its [=scroll container=]
+ in the block direction of the [=snap container=].
+
- inline
+
-
+ '@container/snapped' [=container feature=] matches ''inline''
+ if the container is a [=snap target=] for its [=scroll container=]
+ in the inline direction of the [=snap container=].
+
+
+
+Sticky positioning: the '@container/overflowing' feature
+
+
+ Name: overflowing
+ For: @container
+ Value: top | right | bottom | left | block-start | inline-start | block-end | inline-end
+ Type: discrete
+
+
+ The '@container/overflowing' [=container feature=] queries whether a
+ [=scroll container=] has [=scrollable overflow=] in the given direction for the
+ current scroll progress. The logical values map to physical based on the direction
+ and writing-mode of the [=query container=].
+
+ In the boolean context, the query matches if there is scrollable overflow in any
+ direction.
+
+
+ - top
+
-
+ The [=scroll container=] has [=scrollable overflow=] past the top edge.
+
- right
+
-
+ The [=scroll container=] has [=scrollable overflow=] past the right edge.
+
- bottom
+
-
+ The [=scroll container=] has [=scrollable overflow=] past the bottom edge.
+
- left
+
-
+ The [=scroll container=] has [=scrollable overflow=] past the left edge.
+
- block-start
+
-
+ The [=scroll container=] has [=scrollable overflow=] past the block-start edge.
+
- inline-start
+
-
+ The [=scroll container=] has [=scrollable overflow=] past the inline-start edge.
+
- block-end
+
-
+ The [=scroll container=] has [=scrollable overflow=] past the block-end edge.
+
- inline-end
+
-
+ The [=scroll container=] has [=scrollable overflow=] past the inline-end edge.
+
+
+
Container Relative Lengths: the ''cqw'', ''cqh'', ''cqi'', ''cqb'', ''cqmin'', ''cqmax'' units
From 78f5cc881947faf26a0db28ea1166fcee7721e8b Mon Sep 17 00:00:00 2001
From: Rune Lillesveen
Date: Mon, 2 Sep 2024 14:44:36 +0200
Subject: [PATCH 2/6] Fixed some review issues
---
css-conditional-5/Overview.bs | 87 ++++++++++++++++++++++-------------
1 file changed, 56 insertions(+), 31 deletions(-)
diff --git a/css-conditional-5/Overview.bs b/css-conditional-5/Overview.bs
index 4c998a2b4fd..9685c832a65 100644
--- a/css-conditional-5/Overview.bs
+++ b/css-conditional-5/Overview.bs
@@ -470,7 +470,7 @@ Creating Query Containers: the 'container-type' property
The 'container-type' property establishes the element as a
query container for certain types of queries. For size
- [=container queries=], that require certain types of containment, elements
+ [=container queries=], which require certain types of containment, elements
are explicitly made [=query containers=] through this property. For other
types of [=query containers=] any element can be a query container, such as
for [=container style queries=].
@@ -542,18 +542,18 @@ Creating Query Containers: the 'container-type' property
- Containers can also expose state that depend on scroll offset. Here is an
- example of how to style a descendant of a sticky positioned element when it
- is stuck to the top edge:
+ Containers can also expose state that depends on scroll offset. This example
+ styles a descendant of a sticky positioned element when it is stuck to the
+ top edge:
#sticky {
- container-type: scroll-state;
- position: sticky;
+ container-type: scroll-state;
+ position: sticky;
}
@container scroll-state(stuck: top) {
#sticky-child {
- background-color: lime;
+ background-color: lime;
}
}
@@ -1090,17 +1090,22 @@ Style Container Features
- A
container scroll-state query allows to query a container for various
- state that depends on scroll position. The ''scroll-state'' [=query container=] can either
- be the scroller itself, or an element that is affected by the scroll position of an ancestor
+ A
container scroll-state query allows querying a container for
+ state that depends on scroll position. It is a boolean combination of
+ individual
scroll-state features (<
>)
+ that each query a single feature of the [=query container=]. The syntax of a
+ <> is the same as for a [=media feature=]:
+ a feature name, a comparator, and a value.
+
+ The ''scroll-state'' [=query container=] can either be the scroller itself,
+ or an element that is affected by the scroll position of an ancestor
[=scroll container's=] [=scrollport=].
-
- Note: This section is subject to change as a result of resolving
-
issue #10796
-
+
+ Issue(10796): This section is subject to change as a result of resolving
+ the issue of unifying scroll-snapshotting layout state across several specifications.
Scroll state may cause layout cycles since queried scroll state may cause style changes,
which may lead to scroll state changes as a result of layout. The same issue exists for
@@ -1128,6 +1133,22 @@ Sticky positioning: the '@container/stuck' feature
''position/sticky'' positioned container is visually shifted to stay inside
the [=sticky view rectangle=] for the given edge. The logical edges map to
physical based on the direction and writing-mode of the [=query container=].
+ None of the values match if the [=query container=] is not [=sticky positioned=].
+
+ It is possible for two values from opposite axes to match at the same time,
+ but not for opposite edges along the same axis.
+
+
+ May match:
+
+ @container scroll-state((stuck: top) and (stuck: left)) { ... }
+
+
+ Will never match:
+
+ @container scroll-state((stuck: left) and (stuck: right)) { ... }
+
+
In the boolean context, the query matches if visual shift is applied in any
direction.
@@ -1147,16 +1168,16 @@ Sticky positioning: the '@container/stuck' feature
The ''position/sticky'' container is shifted to stay inside the left edge.
block-start
- The ''position/sticky'' container is shifted to stay inside the block-start edge.
+ The ''position/sticky'' container is shifted to stay inside the [=block-start=] edge.
inline-start
- The ''position/sticky'' container is shifted to stay inside the inline-start edge.
+ The ''position/sticky'' container is shifted to stay inside the [=inline-start=] edge.
block-end
- The ''position/sticky'' container is shifted to stay inside the block-end edge.
+ The ''position/sticky'' container is shifted to stay inside the [=block-end=] edge.
inline-end
- The ''position/sticky'' container is shifted to stay inside the inline-end edge.
+ The ''position/sticky'' container is shifted to stay inside the [=inline-end=] edge.
@@ -1177,25 +1198,25 @@ Scroll snapping: the '@container/snapped' feature
x
'@container/snapped' [=container feature=] matches ''x''
- if the container is a horizontal [=snap target=] for its [=scroll container=]
+ if the [=query container=] is a horizontal [=snap target=] for its [=scroll container=]
y
'@container/snapped' [=container feature=] matches ''y''
- if the container is a vertical [=snap target=] for its [=scroll container=]
+ if the [=query container=] is a vertical [=snap target=] for its [=scroll container=]
block
'@container/snapped' [=container feature=] matches ''block''
- if the container is a [=snap target=] for its [=scroll container=]
+ if the [=query container=] is a [=snap target=] for its [=scroll container=]
in the block direction of the [=snap container=].
inline
'@container/snapped' [=container feature=] matches ''inline''
- if the container is a [=snap target=] for its [=scroll container=]
+ if the [=query container=] is a [=snap target=] for its [=scroll container=]
in the inline direction of the [=snap container=].
-Sticky positioning: the '@container/overflowing' feature
+Overflowing: the '@container/overflowing' feature
Name: overflowing
@@ -1206,11 +1227,15 @@ Sticky positioning: the '@container/overflowing' feature
The '@container/overflowing' [=container feature=] queries whether a
[=scroll container=] has [=scrollable overflow=] in the given direction for the
- current scroll progress. The logical values map to physical based on the direction
- and writing-mode of the [=query container=].
+ current scroll progress. Content not reachable through user scrolling, like
+ content overflowing to the left of an ltr container, or a ''overflow/hidden''
+ container, does not make a query match.
- In the boolean context, the query matches if there is scrollable overflow in any
- direction.
+ The logical values map to physical based on the direction and writing-mode of
+ the [=query container=]. None of the values match if the container is not a
+ [=scroll container=].
+
+ In the boolean context, the query matches if any of the values match.
- top
@@ -1227,16 +1252,16 @@ Sticky positioning: the '@container/overflowing' feature
The [=scroll container=] has [=scrollable overflow=] past the left edge.
- block-start
-
- The [=scroll container=] has [=scrollable overflow=] past the block-start edge.
+ The [=scroll container=] has [=scrollable overflow=] past the [=block-start=] edge.
- inline-start
-
- The [=scroll container=] has [=scrollable overflow=] past the inline-start edge.
+ The [=scroll container=] has [=scrollable overflow=] past the [=inline-start=] edge.
- block-end
-
- The [=scroll container=] has [=scrollable overflow=] past the block-end edge.
+ The [=scroll container=] has [=scrollable overflow=] past the [=block-end=] edge.
- inline-end
-
- The [=scroll container=] has [=scrollable overflow=] past the inline-end edge.
+ The [=scroll container=] has [=scrollable overflow=] past the [=inline-end=] edge.
From c7bda8f4c49793404ba58660b88bc067f8a29616 Mon Sep 17 00:00:00 2001
From: Rune Lillesveen
Date: Tue, 3 Sep 2024 11:52:57 +0200
Subject: [PATCH 3/6] Fixed issues in "Updating Scroll State"
---
css-conditional-5/Overview.bs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/css-conditional-5/Overview.bs b/css-conditional-5/Overview.bs
index 9685c832a65..05f93fe9856 100644
--- a/css-conditional-5/Overview.bs
+++ b/css-conditional-5/Overview.bs
@@ -1115,9 +1115,9 @@ Updating Scroll State
current state once as the last step of [=run the scroll steps=]. Then, after the
resizeObserver loop in the
HTML event loop processing model,
- the scroll state of every ''scroll-state'' [=query container=] is updated.
+ update the current state of every ''scroll-state'' [=query container=].
If that state has changed since the scroll state update in [=run the scroll steps=],
- re-run the style and layout update if necessary.
+ re-run the style and layout update a single time if necessary.
Sticky positioning: the '@container/stuck' feature
From cb73856ad221351e9b79b8cfe2293fe5196a1d68 Mon Sep 17 00:00:00 2001
From: Rune Lillesveen
Date: Tue, 3 Sep 2024 12:33:11 +0200
Subject: [PATCH 4/6] Move definition of "query container"
---
css-conditional-5/Overview.bs | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/css-conditional-5/Overview.bs b/css-conditional-5/Overview.bs
index 05f93fe9856..1159d74c1a1 100644
--- a/css-conditional-5/Overview.bs
+++ b/css-conditional-5/Overview.bs
@@ -347,10 +347,10 @@ Container Queries
[=container queries=] allow testing aspects of elements within the document
(such as box dimensions or computed styles).
- By default, all elements are [=query containers=]
+ By default, all elements are query containers
for the purpose of [=container style queries=],
and can be established as [=query containers=]
- for [=container size queries=] by specifying
+ for [=container size queries=] and [=container scroll-state queries=] by specifying
the additional query types using the 'container-type' property
(or the 'container' [=shorthand=]).
Style rules applying to a [=query container=]’s [=flat tree=] descendants
@@ -384,9 +384,9 @@ Container Queries
For the ''::part()'' and ''::slotted()'' pseudo-element selectors,
- which represent real elements in the DOM tree, query containers can be
+ which represent real elements in the DOM tree, [=query containers=] can be
established by [=flat tree=] ancestors of those elements.
- For other pseudo-elements, query containers can be established by
+ For other pseudo-elements, [=query containers=] can be established by
inclusive [=flat tree=] ancestors of their originating element.
@@ -469,11 +469,11 @@ Creating Query Containers: the 'container-type' property
The 'container-type' property establishes the element as a
- query container for certain types of queries. For size
+ [=query container=] for certain types of queries. For size
[=container queries=], which require certain types of containment, elements
are explicitly made [=query containers=] through this property. For other
- types of [=query containers=] any element can be a query container, such as
- for [=container style queries=].
+ types of [=query containers=] any element can be a [=query container=], such
+ as for [=container style queries=].
Values have the following meanings:
From 9a66863cbfb26ebc7e5ac282082d04c004d1ee19 Mon Sep 17 00:00:00 2001
From: Rune Lillesveen
Date: Tue, 3 Sep 2024 12:53:08 +0200
Subject: [PATCH 5/6] Talk about scroll-state features instead of scroll-state
containers
---
css-conditional-5/Overview.bs | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/css-conditional-5/Overview.bs b/css-conditional-5/Overview.bs
index 1159d74c1a1..b35766f956d 100644
--- a/css-conditional-5/Overview.bs
+++ b/css-conditional-5/Overview.bs
@@ -1092,14 +1092,15 @@ Scroll State Container Features
A container scroll-state query allows querying a container for
state that depends on scroll position. It is a boolean combination of
- individual scroll-state features (<>)
- that each query a single feature of the [=query container=]. The syntax of a
- <> is the same as for a [=media feature=]:
- a feature name, a comparator, and a value.
+ individual scroll-state features
+ (<>) that each query a single feature of the
+ [=query container=]. The syntax of a <> is the
+ same as for a [=media feature=]: a feature name, a comparator, and a value.
- The ''scroll-state'' [=query container=] can either be the scroller itself,
+ [=Scroll-state features=] can either match state of the scroller itself,
or an element that is affected by the scroll position of an ancestor
- [=scroll container's=] [=scrollport=].
+ [=scroll container's=] [=scrollport=]. An example of the former is the
+ ''overflowing'' feature, ''snapped'' the latter.
From 1a924140ce9bee5ec0a38d62b276a5a49af0c26b Mon Sep 17 00:00:00 2001
From: Rune Lillesveen
Date: Wed, 4 Sep 2024 19:30:35 +0200
Subject: [PATCH 6/6] Re-worded 'overflowing'
---
css-conditional-5/Overview.bs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/css-conditional-5/Overview.bs b/css-conditional-5/Overview.bs
index b35766f956d..0fe2d42a85d 100644
--- a/css-conditional-5/Overview.bs
+++ b/css-conditional-5/Overview.bs
@@ -1227,10 +1227,10 @@ Overflowing: the '@container/overflowing' feature
The '@container/overflowing' [=container feature=] queries whether a
- [=scroll container=] has [=scrollable overflow=] in the given direction for the
- current scroll progress. Content not reachable through user scrolling, like
- content overflowing to the left of an ltr container, or a ''overflow/hidden''
- container, does not make a query match.
+ [=scroll container=] has clipped [=scrollable overflow rectangle=] content
+ in the given direction which is reachable through user initiated scrolling.
+ That is, '@container/overflowing' does not match for a ''overflow/hidden''
+ container, nor for a [=negative scrollable overflow region=].
The logical values map to physical based on the direction and writing-mode of
the [=query container=]. None of the values match if the container is not a