在 scroll-state() 查詢中,你可以使用以下三個 @container 描述符:
scrollable:查詢容器是否可以透過使用者啟動的滾動(例如透過拖動捲軸或使用觸控板手勢)在給定方向上滾動。換句話說,給定方向上是否有任何溢位內容可以滾動到?這對於應用與滾動容器的滾動位置相關的樣式非常有用。例如,你可以在捲軸位於頂部時顯示一個提示,鼓勵人們向下滾動檢視更多內容,並在使用者實際開始滾動時將其隱藏。
snapped:查詢容器是否將沿給定軸吸附到滾動吸附容器祖先。這對於在元素吸附到滾動吸附容器時應用樣式非常有用。例如,你可能希望以某種方式突出顯示吸附的元素,或者顯示其以前隱藏的某些內容。
stuck:查詢具有 sticky position 值的容器是否粘滯到其滾動容器祖先的邊緣。這對於在 position: sticky 元素粘滯時對其進行不同的樣式設定非常有用——例如,你可以為它們提供不同的配色方案或佈局。
要將容器元素建立為滾動狀態查詢容器,請在其上設定 container-type 屬性,並將其值設定為 scroll-state。你也可以選擇為其指定一個 container-name,以便可以使用特定的容器查詢來定位它。
.container {
container-type: scroll-state;
container-name: my-container;
}
然後,你可以建立一個 @container 塊,該塊指定查詢、如果測試透過則應用於容器子元素的規則,以及可選的要查詢的容器的 container-name。如果你不指定 container-name,則容器查詢將應用於頁面上的所有滾動狀態查詢容器。
在這裡,我們只查詢名為 my-container 的容器,以確定容器是否可以向其頂部邊緣滾動。
@container my-container scroll-state(scrollable: top) {
/* CSS rules go here */
}
注意:為了將滾動狀態查詢與其他容器查詢分開,滾動狀態描述符和值放置在括號內,前面加上 scroll-state(scroll-state( ... ))。這些構造看起來像函式,但它們不是。
滾動狀態 scrollable 查詢,寫為 scroll-state(scrollable: value),測試容器的滾動祖先是否可以透過使用者啟動的滾動在給定方向上滾動。如果不能,查詢返回 false。
value 表示你正在測試滾動可用性的方向,例如:
top:測試容器是否可以向其頂部邊緣滾動。
inline-end:測試容器是否可以向其內聯結束邊緣滾動。
y:測試容器是否可以沿其 y 軸的任一或兩個方向滾動。
如果測試透過,則 @container 塊內的規則將應用於匹配滾動容器的後代。
讓我們看一個例子,其中我們有一個充滿內容的滾動容器,以及一個方便的小連結,如果需要可以滾動回頂部。我們將使用 scrollable 查詢,僅當用戶開始向下滾動內容時才顯示該連結。
在 HTML 中,我們有一個 <article> 元素,其中包含足夠的內容以使文件滾動,前面是一個返回頂部連結。
<a class="back-to-top" href="#" aria-label="Top of page">↑</a>
<article>
<h1>Reader with container query-controlled "back-to-top" link</h1>
<section>
<header>
<h2>This first section is interesting</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</header>
...
</section>
...
</article>
為了簡潔起見,我們隱藏了大部分 HTML。
<a class="back-to-top" href="#" aria-label="Scroll back to top">↑</a>
<article>
<h1>Reader with container query-controlled "back-to-top" link</h1>
<section>
<header>
<h2>This first section is interesting</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</header>
<p>
Mauris non malesuada est, sed vestibulum nibh. Duis vestibulum iaculis
lectus, eu sagittis dolor dignissim iaculis. Nunc et orci sed sapien
eleifend placerat. Curabitur dapibus risus eget odio sollicitudin, sit
amet luctus justo pellentesque.
</p>
<p>
<strong>Morbi non pharetra quam.</strong> Fusce vestibulum sem diam, ac
consequat augue consectetur ut. Donec at augue viverra, tempus urna sit
amet, porta augue.
<em>Phasellus fringilla tincidunt sem ullamcorper varius.</em> Aenean
gravida feugiat sem nec ultricies.
</p>
<img src="#" alt="Placeholder" />
<p>
Sed pellentesque placerat mi sed maximus. Sed vitae dui vitae mi pulvinar
gravida sed et libero.
<a href="#">Duis nec venenatis dolor, sed tristique felis.</a>
Integer dapibus facilisis leo elementum vulputate. Curabitur a urna quis
nulla vulputate tincidunt quis ac enim.
</p>
<p>
Cras non elit vel leo dignissim convallis. Duis eros urna, varius sit amet
lorem vel, feugiat euismod est.
<strong>Aliquam ornare eu elit ut iaculis.</strong>
Suspendisse vulputate tempor leo, non rhoncus risus aliquam vel.
</p>
</section>
<section>
<header>
<h2>This one, not so much</h2>
<p>Suspendisse varius est ac turpis mollis cursus.</p>
</header>
<p>
<strong
>Curabitur faucibus condimentum eros, ut auctor felis lacinia
sed.</strong
>
Praesent vitae scelerisque eros.
</p>
<p>
<em>Ut vitae suscipit augue.</em> Cras et orci condimentum ante dignissim
iaculis. Sed consectetur quis est sed dignissim. Nulla egestas orci erat,
et commodo arcu feugiat ut.
</p>
<img src="#" alt="Placeholder" />
<p>
Sed non tempor massa, at accumsan ante. Pellentesque habitant morbi
<a href="#">tristique senectus</a> et netus et malesuada fames ac turpis
egestas.
</p>
<p>
Pellentesque placerat luctus tempor. Nunc congue dapibus eros, at
vulputate nulla. Sed rutrum eleifend magna vel porta. Integer cursus orci
faucibus turpis scelerisque, nec pharetra arcu molestie.
</p>
</section>
<section>
<header>
<h2>Hopefully this section provides some clarity?</h2>
<p>Curabitur facilisis ornare lorem et eleifend.</p>
</header>
<p>
<strong>Aenean mollis non neque sed finibus.</strong> Lorem ipsum dolor
sit amet, consectetur adipiscing elit. Suspendisse sagittis viverra urna.
In hac habitasse platea dictumst. Vestibulum neque orci, mollis sagittis
augue et, pharetra vehicula diam.
</p>
<img src="#" alt="Placeholder" />
<p>
<a href="#">Pellentesque sollicitudin</a> nunc quis nisl condimentum, ac
iaculis libero feugiat.
<strong>Nullam ultrices purus a nulla dignissim hendrerit.</strong> In
molestie consectetur est quis pulvinar.
</p>
<p>
Vivamus ac erat eu est lobortis commodo. Orci varius natoque penatibus et
magnis dis parturient montes, nascetur ridiculus mus. In nulla turpis,
<strong>mollis et est tempor</strong>, dignissim aliquam metus. Proin eu
arcu quis erat mollis pulvinar. Vivamus at facilisis neque.
</p>
<p>
Integer bibendum laoreet erat, quis vulputate mauris bibendum nec. Class
aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
himenaeos. Nam ut est in arcu interdum hendrerit.
</p>
</section>
<section>
<header>
<h2>A summary of sorts</h2>
<p>Nunc facilisis augue quis ex porta aliquam.</p>
</header>
<img src="#" alt="Placeholder" />
<p>
<strong
>Fusce nisi enim, venenatis a est vel, varius placerat lacus.</strong
>
Nunc tempus rutrum nisl bibendum aliquet. Pellentesque vitae nunc sed nisl
tincidunt elementum a sit amet nisi. Morbi pretium at dolor in pulvinar.
Curabitur dapibus eleifend accumsan.
</p>
<p>
Donec rhoncus, leo vitae mollis maximus, tellus lorem interdum arcu, eu
<em>tempor lectus libero in risus</em>. Ut sit amet magna vitae mauris
tempor bibendum. <a href="#">Integer id mauris ut ex mattis finibus.</a>
</p>
<p>
Curabitur dui felis, elementum et tellus id, blandit facilisis lorem.
Aliquam sed posuere ligula, at auctor ipsum. Morbi dignissim accumsan
tellus pretium iaculis.
</p>
</section>
</article>
.back-to-top 連結被賦予 fixed 的 position 值,放置在視口的右下角,並使用 80px 0 的 translate 值移出視口。當任一值更改時,transition 值將動畫化 translate 和 background-color。
/* General styling */
* {
box-sizing: border-box;
}
html {
font-family: "Helvetica", "Arial", sans-serif;
height: 100%;
}
body {
height: inherit;
width: 100%;
max-width: 540px;
padding: 20px;
margin: 0 auto;
}
p {
line-height: 1.5;
}
img {
display: block;
width: 90%;
margin: 30px auto;
padding: 20px;
border: 2px solid gray;
aspect-ratio: 3/2;
}
.back-to-top {
width: 64px;
height: 64px;
color: white;
text-align: center;
position: fixed;
bottom: 10px;
right: 10px;
translate: 80px 0;
transition:
0.4s translate,
0.2s background-color;
}
.back-to-top {
text-decoration: none;
border-radius: 50%;
border: 1px solid #00000077;
background-color: #00000077;
color: white;
font-size: 3rem;
text-shadow: 0 0 2px black;
padding-bottom: 10px;
}
.back-to-top:hover,
.back-to-top:focus {
background: #00000099;
}
此示例中的滾動容器是 <html> 元素本身,它被指定為滾動狀態查詢容器,其 container-type 值為 scroll-state。container-name 並非嚴格必需,但在程式碼新增到具有多個透過不同查詢定位的滾動狀態查詢容器的程式碼庫中時非常有用。
html {
container-type: scroll-state;
container-name: scroller;
}
接下來,我們定義一個 @container 塊,該塊設定此查詢的目標容器名稱,以及查詢本身——scrollable: top。此查詢僅當 <html> 元素可以向其頂部邊緣滾動時才應用塊內包含的規則——換句話說,如果容器之前已向下滾動。如果是這種情況,則將 translate: 0 0 應用於 .back-to-top 連結,這將使其平滑地回到螢幕上。
@container scroller scroll-state(scrollable: top) {
.back-to-top {
translate: 0 0;
}
}
為了簡潔起見,我們隱藏了示例 CSS 的其餘部分。
嘗試向下滾動文件,並注意“返回頂部”連結如何因此出現,由於 transition 而從視口右側平滑動畫。如果你透過啟用連結或手動滾動返回頂部,“返回頂部”連結將平滑地移出螢幕。
僅當實現滾動吸附時才相關,滾動狀態snapped查詢(寫為scroll-state(snapped: value))測試容器是否將沿給定軸吸附到滾動吸附容器祖先。如果不是,查詢返回 false。
在這種情況下,value 表示你正在測試元素吸附能力的方向,例如:
x:測試容器是否水平吸附到其滾動吸附容器祖先。
inline:測試容器是否在內聯方向上吸附到其滾動吸附容器祖先。
y:測試容器是否在兩個方向上吸附到其滾動吸附容器祖先。
要評估具有非 none snapped 滾動狀態查詢的容器,它必須是一個具有滾動吸附容器祖先的容器,也就是說,該祖先的 scroll-snap-type 值不是 none。容器查詢 scroll-state(snapped: none) 匹配沒有滾動容器祖先的滾動狀態容器。
評估將在滾動吸附容器上觸發 scrollsnapchanging 事件時進行。
如果測試透過,則 @container 塊內的規則將應用於匹配的滾動吸附目標容器的後代。
在此示例中,我們將檢視一個具有垂直吸附子元素的滾動吸附容器,並使用 snapped 查詢僅在子元素吸附或即將吸附時為其設定樣式。
HTML 由一個 <main> 元素組成,該元素將成為滾動吸附容器。內部有幾個 <section> 元素,它們將成為吸附目標。每個 <section> 都包含一個包裝器 <div> 和一個 <h2> 標題。包含包裝器的目的是建立一個樣式目標,因為容器查詢允許對容器的後代進行樣式設定,而不是容器本身。
<main>
<section>
<div class="wrapper">
<h2>Section 1</h2>
</div>
</section>
...
</main>
為了簡潔起見,我們隱藏了大部分 HTML。
<main>
<section>
<div class="wrapper">
<h2>Section 1</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 2</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 3</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 4</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 5</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 6</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 7</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 8</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 9</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 10</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 11</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 12</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 13</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 14</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 15</h2>
</div>
</section>
<section>
<div class="wrapper">
<h2>Section 16</h2>
</div>
</section>
</main>
* {
box-sizing: border-box;
}
html {
height: 100%;
}
/* body and main sizing */
body {
display: flex;
align-items: center;
justify-content: center;
height: inherit;
}
main {
gap: 50px;
}
我們在 <main> 元素上設定了 scroll 的 overflow 值和固定的 height,以將其轉換為垂直滾動容器。我們還設定了 y mandatory 的 scroll-snap-type 值,將 <main> 轉換為滾動吸附容器,吸附目標將沿 y 軸吸附到該容器;mandatory 意味著吸附目標將始終被吸附到。
main {
overflow: scroll;
scroll-snap-type: y mandatory;
height: 450px;
width: 250px;
border: 3px solid black;
}
透過設定非 none 的 scroll-snap-align 值,將 <section> 元素指定為吸附目標。center 值表示它們將以其中心點吸附到容器。
section {
font-family: "Helvetica", "Arial", sans-serif;
width: 150px;
height: 150px;
margin: 50px auto;
scroll-snap-align: center;
}
.wrapper {
width: 100%;
height: 100%;
border-radius: 5px;
background: #eeeeee;
box-shadow:
inset 1px 1px 4px rgb(255 255 255 / 0.5),
inset -1px -1px 4px rgb(0 0 0 / 0.5);
display: flex;
align-items: center;
justify-content: center;
transition:
0.6s background,
0.6s color;
}
h2 {
font-size: 1rem;
letter-spacing: 1px;
}
我們希望能夠查詢 <section> 元素。具體來說,我們希望測試 <section> 元素是否正在吸附到其容器,因此我們透過在其上設定 scroll-state 的 container-type 值,將它們指定為滾動狀態查詢容器。我們還為它們指定了一個 container-name,這並非嚴格必需,但如果我們的程式碼以後變得更復雜,並且我們有多個希望使用不同查詢定位的滾動狀態查詢容器,則會很有用。
section {
container-type: scroll-state;
container-name: snap-container;
}
接下來,我們定義一個 @container 塊,該塊設定我們在此查詢中定位的容器名稱以及查詢本身——snapped: y。此查詢僅當 <section> 元素垂直吸附到其容器時才應用塊中包含的規則。如果是這種情況,我們將新的 background 和 color 應用於 <section> 元素的子 .wrapper <div> 以突出顯示它。
@container snap-container scroll-state(snapped: y) {
.wrapper {
background: purple;
color: white;
}
}
渲染結果如下所示。嘗試上下滾動容器,並注意當 <section> 吸附到其容器時,其樣式如何變化。
滾動狀態stuck查詢(寫為scroll-state(stuck: value))測試具有stickyposition值的容器是否粘滯到其滾動容器祖先的邊緣。如果不是,則查詢返回 false。
在這種情況下,value 表示你正在測試的滾動容器邊緣,例如:
top:測試容器是否粘滯到其滾動容器祖先的頂部邊緣。
block-end:測試容器是否粘滯到其滾動容器祖先的塊結束邊緣。
none:測試容器是否未粘滯到其滾動容器祖先的任何邊緣。請注意,即使容器未設定 position: sticky,none 查詢也會匹配。
如果查詢返回 true,則 @container 塊內的規則將應用於匹配的 position: sticky 容器的後代。
讓我們看一個例子,其中有一個包含溢位內容的滾動容器,其中的標題設定為 position: sticky,並在滾動到該位置時粘滯到容器的頂部邊緣。我們將使用 stuck 滾動狀態查詢,以便在標題粘滯到頂部邊緣時對其進行不同的樣式設定。
在 HTML 中,我們有一個 <article> 元素,其中包含足夠的內容以導致文件滾動。它使用幾個 <section> 元素進行結構化,每個元素都包含一個帶有巢狀內容的 <header>。
<article>
<h1>Sticky reader with scroll-state container query</h1>
<section>
<header>
<h2>This first section is interesting</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</header>
...
</section>
<section>
<header>
<h2>This one, not so much</h2>
<p>Confecta res esset.</p>
</header>
...
</section>
...
</article>
為了簡潔起見,我們隱藏了大部分 HTML。
<article>
<h1>Sticky reader with scroll-state container query</h1>
<section>
<header>
<h2>This first section is interesting</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</header>
<p>
Id deserunt exercitation in incididunt in dolor ipsum enim occaecat quis
officia et. In dolore Lorem anim enim. Dolor nulla deserunt laboris irure
incididunt labore tempor amet consectetur. Commodo eu tempor qui laboris
duis ipsum adipisicing sunt. Do anim laboris commodo aliquip consequat ut
eiusmod mollit sint nostrud sunt exercitation do.
</p>
<p>
<strong>Est proident voluptate dolore.</strong> Aute irure ea culpa mollit
<em>anim aute proident consectetur.</em> Duis deserunt consequat elit non.
Cupidatat et amet anim labore est. Incididunt aute incididunt ex amet
sint.
</p>
<img src="#" alt="Placeholder" />
<p>
Ullamco duis qui amet sunt eu nulla deserunt dolore officia irure nulla.
<a href="#">Qui enim dolore est virtus;</a>
Erat enim consectetur.
</p>
<p>
Dolor aliquip officia id esse Lorem ullamco ea veniam.
<strong>Voluptate cillum commodo anim veniam;</strong>
Ad nulla amet anim eu incididunt reprehenderit proident in aliqua sit
commodo magna.
</p>
</section>
<section>
<header>
<h2>This one, not so much</h2>
<p>Confecta res esset.</p>
</header>
<p>
<strong>Nam quid possums facere delius?</strong> Tu quidem reddes; Omnis
peccant para dicts.
</p>
<p>
<em>Pariatur ex cupidatat exercitation</em> reprehenderit quis culpa est
proident pariatur ut.
</p>
<img src="#" alt="Placeholder" />
<p>
Non nulla pariatur cillum pariatur.
<a href="#">Ipsum magna proident fugiat qui duis et.</a>
Reprehenderit sit ipsum ut adipisicing aliqua eiusmod nulla consectetur
deserunt dolor dolor.
</p>
<p>
Cupidatat deserunt adipisicing adipisicing occaecat voluptate duis laboris
excepteur labore et in aliquip aute. Quis aliquip reprehenderit dolor
nostrud cupidatat nostrud nisi occaecat elit. Magna dolor ullamco eiusmod
deserunt elit cillum qui amet. Dolor ad consequat anim commodo eu sunt do
tempor eu velit est.
</p>
</section>
<section>
<header>
<h2>Hopefully this section provides some clarity?</h2>
<p>Dolor consectetur esse aute eiusmod ex reprehenderit cupidatat.</p>
</header>
<p>
<strong>Ipsum quis sint incididunt aliquip</strong>. Duis tempor sunt enim
Lorem ut officia cillum magna.
</p>
<img src="#" alt="Placeholder" />
<p>
<a href="#">Sint modo partes vitae beatae.</a>
Ipsum esse nostrud incididunt ipsum ipsum esse aliquip Lorem enim.
<strong>Sed hoc sane concedays.</strong> Voluptate qui consequat dolor
dolor dolore ex. Enim dolor enim sit proident. Ad laborum incididunt
dolore aliquip exercitation exercitation. Sunt cupidatat esse enim duis
proident.
</p>
<p>
Labore dolor cupidatat ut velit in minim cupidatat enim nisi proident
eiusmod.
<strong
>Non nostrud consectetur est occaecat ut esse esse tempor eiusmod
non.</strong
>
Cupidatat aliqua dolore est sit ad exercitation nostrud nostrud eu. Qui
consequat et aliquip ea labore.
</p>
<p>
Pariatur quis quis nostrud exercitation pariatur magna veniam Lorem
commodo cupidatat irure reprehenderit. Nostrud pariatur est pariatur elit
sit ea voluptate minim mollit. Aliqua pariatur cupidatat et cillum. Velit
exercitation adipisicing laboris ullamco. Incididunt id eiusmod id cillum
qui anim. Aliquip minim nostrud excepteur dolore deserunt pariatur eu
eiusmod reprehenderit ullamco magna.
</p>
</section>
<section>
<header>
<h2>A summary of sorts</h2>
<p>Irure adipisicing occaecat dolore in ex voluptate.</p>
</header>
<img src="#" alt="Placeholder" />
<p>
<strong>An quidem modi?</strong>
<strong
>Excepteur non Lorem ex aliqua est reprehenderit incididunt sunt in
ullamco in et;</strong
>
Aliqua veniam nulla magna anim labore amet proident nisi mollit non.
Consequat incididunt exercitation nisi consequat culpa officia aliqua
veniam. Anim aliqua consectetur pariatur mollit proident incididunt id.
</p>
<p>
Non labore, inquit, de nomin. <em>Fall igniter possimus.</em>
<a href="#">Preterits, inquit, gaud.</a>
Est commodo adipisicing qui duis excepteur sit ea irure amet voluptate
deserunt anim deserunt.
</p>
<p>
Ad mollit laboris reprehenderit magna tempor. Consequat pariatur esse
ipsum duis laboris.
</p>
</section>
</article>
每個 <header> 都具有 sticky 的 position 值和 0 的 top 值,這使得它們粘滯到滾動容器的頂部邊緣。為了測試 <header> 元素是否粘滯到容器頂部邊緣,它們被指定為滾動狀態查詢容器,其 container-type 值為 scroll-state。container-name 並非嚴格必需,但如果此程式碼新增到具有多個透過不同查詢定位的滾動狀態查詢容器的程式碼庫中,則會很有用。
/* General styling */
* {
box-sizing: border-box;
}
html {
font-family: "Helvetica", "Arial", sans-serif;
height: 100%;
}
body {
height: inherit;
width: 100%;
max-width: 540px;
padding: 20px;
margin: 0 auto;
}
p {
line-height: 1.5;
}
img {
display: block;
width: 90%;
margin: 30px auto;
padding: 20px;
border: 2px solid gray;
aspect-ratio: 3/2;
}
header {
background: white;
position: sticky;
top: 0;
container-type: scroll-state;
container-name: sticky-heading;
}
我們還為 <header> 元素中的 <h2> 和 <p> 元素提供了一些基本樣式,以及一個 transition 值,以便當它們的 background 值更改時,它們會平滑地動畫。
h2,
header p {
margin: 0;
transition: 0.4s background;
}
h2 {
padding: 20px 5px;
margin-bottom: 10px;
}
header p {
font-style: italic;
padding: 10px 5px;
}
接下來,我們定義一個 @container 塊,該塊設定我們在此查詢中定位的容器名稱以及查詢本身——stuck: top。此查詢僅當 <header> 元素粘滯到其滾動容器的頂部時才應用塊中包含的規則。在這種情況下,不同的 background 和 box-shadow 將應用於包含的 <h2> 和 <p>。
@container sticky-heading scroll-state(stuck: top) {
h2,
p {
background: #cccccc;
box-shadow: 0 5px 2px #00000077;
}
}
為了簡潔起見,我們隱藏了 CSS 的其餘部分。
嘗試上下滾動文件,並注意當 <h2> 和 <p> 元素粘滯到其容器頂部邊緣時,它們如何轉換為新的配色方案。