使用容器大小和樣式查詢

Baseline 廣泛可用 *

此特性已經非常成熟,可以在許多裝置和瀏覽器版本上使用。自 2023 年 2 月起,所有主流瀏覽器均已支援。

* 此特性的某些部分可能存在不同級別的支援。

容器查詢允許你根據特定容器的特性,將樣式應用於巢狀在該容器內的元素。查詢會根據查詢條件對於該容器是否為真而返回 true 或 false。

容器查詢類似於媒體查詢@media @規則允許根據視口大小或其他裝置特性來應用樣式。類似地,@container @規則允許根據包含元素的大小或其他樣式特性(而非視口特性)來應用樣式。容器查詢與媒體查詢具有相同的語法規則和邏輯運算子。

css
@container <container-condition># {
  /* <stylesheet> */
}

容器查詢有三種類型

容器大小查詢

大小查詢允許根據包含元素的當前大小來應用樣式,包括方向和寬高比。包含元素需要被顯式宣告為大小查詢容器

容器樣式查詢

樣式查詢允許根據包含元素的樣式特性來應用樣式。任何非空元素都可以是樣式查詢容器。目前,樣式查詢支援的唯一樣式特性是 CSS 自定義屬性。在這種情況下,查詢會根據包含元素的自定義屬性的計算值返回 true 或 false。當容器樣式查詢得到完全支援時,你將能夠根據任何屬性、宣告或計算值將樣式應用於任何元素的後代——例如,當容器為 display: inline flex 或具有不透明的背景顏色時。

容器滾動狀態查詢

滾動狀態查詢允許你根據滾動狀態條件,選擇性地將 CSS 規則應用於容器的後代,例如查詢的元素是否部分滾動,或者容器是否吸附到滾動吸附容器上。包含元素需要被顯式宣告為滾動狀態查詢容器

在本指南中,我們將透過以下內容學習容器查詢的基礎知識:

  1. 容器大小查詢,
  2. 為容器命名以限制其範圍,以及
  3. @container @規則的 <container-condition> 中使用 style() 函式式表示法來建立使用自定義屬性的樣式查詢

滾動狀態查詢在使用容器滾動狀態查詢中討論。

容器大小查詢

容器大小查詢由大小條件過濾。如果容器元素已被宣告為容器,並且容器條件對該元素為真,則關聯的樣式將應用於其包含的元素。元素的大小容器是具有包含性(containment)的最近祖先。

透過將其 container-type 屬性(或 container 簡寫屬性)設定為 sizeinline-size,元素被宣告為大小查詢容器

css
@container (orientation: landscape) {
  /* styles applied to descendants of this size container */
}

.sizeContainer {
  container-type: size;
}

宣告大小查詢容器會為其新增包含性。這是效能上的必需——一直查詢 DOM 中每個元素的大小,對效能和使用者體驗都是不利的。此外,如果後代元素的樣式改變了容器元素的大小,可能會發生無限迴圈。

在容器大小查詢中,<container-condition> 包含一個或多個 <size-query>。每個大小查詢包括一個大小特性名稱、一個比較運算子和一個值。可以查詢的大小特性僅限於 widthheightinline-sizeblock-sizeaspect-ratioorientation。組合一個或多個 <size-query> 的布林語法和邏輯與 @media 大小特性查詢相同。

css
form {
  container-type: inline-size;
}

@container (10em <= width <= 20em) {
  /* styles */
}

此示例中的 <container-condition> 包含一個 <size-query>——(10em <= width <= 20em)。在這種情況下,所有 <form> 元素都是任何未命名容器查詢的潛在匹配項。我們容器查詢中宣告的樣式將應用於所有寬度在 10em30em 之間(含)的表單的後代。

為容器命名

<container-condition> 可以包含一個可選的、區分大小寫的 container-name。容器名稱使容器條件更具體——它僅針對那些在 container-name 屬性中設定了該名稱的元素進行評估。

container-name 屬性指定一個查詢 <container-name> 值的列表,這些值可以在 @container 規則中使用;它們是區分大小寫的 <ident> 值。容器名稱使得可以定位元素的任何容器祖先。如果沒有容器名稱,查詢只匹配最近的容器祖先。

css
@container [ [ <container-name> ]? <container-query> ]# {
  /* <stylesheet> */
}

在為 @container @規則新增名稱後,你可以使用 container-name 屬性或 container 簡寫屬性來定位特定的容器元素。已命名的 @container @規則內的樣式將僅應用於滿足容器查詢的、且在設定了這些名稱的容器內的匹配元素。

css
@container card (orientation: landscape) {
  /* styles */
}

.todo-panel > li {
  container-type: inline-size;
  container-name: card;
}

在上面的示例中,容器查詢塊內的樣式將應用於所有寬度大於其高度的 <li> 元素的後代。請注意,其他應用了 container-name: card 且匹配大小查詢的元素,其後代元素也將應用這些樣式。

css
@container wide (width >= 20em) {
  /* styles applied to descendants of wide .sizeContainer */
}

@container narrow (width < 20em) {
  /* styles applied to descendants of narrow .sizeContainer */
}

.sizeContainer {
  container-type: size;
  container-name: wide narrow;
}

在上面的示例中,該元素有兩個容器名稱:widenarrow。任何帶有 class="sizeContainer" 的元素的後代都將應用 widenarrow 查詢的樣式。

預設值 container-type: normal 會阻止容器成為大小容器,但它仍然可以是樣式容器。預設值 container-name: none 表示容器沒有名稱,但這不會阻止該元素匹配未命名的查詢。

使用容器查詢,我們不僅限於大小查詢!你還可以查詢容器的樣式特性。

容器樣式查詢

容器樣式查詢是一種 @container 查詢,它評估在一個或多個 style() 函式式表示法中定義的容器元素的計算樣式。用於將樣式特性組合成樣式查詢的布林語法和邏輯與CSS 特性查詢中的相同。唯一的區別是函式名稱——在 <style-feature> 中是 style(),而在 <support-condition> 中是 supports()

css
@container style(<style-feature>),
    not style(<style-feature>),
    style(<style-feature>) and style(<style-feature>),
    style(<style-feature>) or style(<style-feature>) {
  /* <stylesheet> */
}

每個 style() 函式的引數是單個 <style-feature>。根據 CSS 包含性規範,<style-feature> 可以是有效的 CSS 宣告、CSS 屬性或 <custom-property-name>。目前唯一支援的樣式特性是自定義屬性,可以帶值也可以不帶值。請參閱瀏覽器相容性表格

如果 <style-feature> 包含一個值,那麼當作為 style() 引數傳遞的自定義屬性(或將來是 CSS 宣告)的計算值對於被查詢的容器為真時,樣式查詢評估為 true。否則,它解析為 false。不帶值的樣式特性在計算值與給定屬性的初始值不同時評估為 true。

將來,我們將能夠編寫如下的樣式查詢:

css
@container style(color: green) and style(background-color: transparent),
    not style(background-color: red),
    style(--themeBackground),
    style(--themeColor: blue) or style(--themeColor: purple),
    (width <= 100vw) and style(max-width: 600px) {
  /* <stylesheet> */
}

style() 函式式表示法用於區分樣式查詢和大小查詢。雖然尚未支援,但我們最終將能夠查詢常規的 CSS 宣告,如 max-width: 600px。查詢 @container (max-width: 600px) 是一個大小查詢;需要使用 container-typecontainer 簡寫屬性來設定包含性。如果容器寬度為 600px 或更小,該查詢將返回 true。這與查詢 @container style(max-width: 600px) 不同,後者是一個樣式查詢;當支援時,如果容器的 max-width 值為 600px,該查詢將返回 true。

在支援對常規 CSS 宣告和屬性的樣式查詢之前,我們只能將自定義屬性作為 style() 的引數,可以帶值也可以不帶值。

css
@container style(--themeBackground),
    style(--themeColor: blue) or style(--themeColor: purple) {
  /* <stylesheet> */
}

有幾點需要注意,雖然已經提到過,但仍很重要:

  • 所有元素都可以是樣式查詢容器;不需要設定 container-type。當後代樣式不影響祖先的計算樣式時,就不需要包含性。
  • <container-condition> 可以同時包含樣式和大小特性。如果在查詢中包含大小特性,請確保你的容器元素設定了 container-typesizeinline-size
  • 如果你不希望某個元素被視為容器,可以給它一個不會被使用的 container-name。設定 container-name: none 會移除與容器關聯的任何查詢名稱;但這不會阻止該元素成為樣式容器。
  • 在撰寫本文時(2024 年 2 月),容器樣式查詢僅適用於 style() 查詢中的 CSS 自定義屬性值。

現在,讓我們深入瞭解一下不同的 <style-feature> 型別。

自定義屬性的樣式查詢

自定義屬性的樣式查詢允許你查詢父元素的自定義屬性(也稱為“CSS 變數”)。它們被包含在 <style-query> 中,就像你在特性查詢中包含任何常規 CSS 屬性一樣:可以帶值也可以不帶值。

獨立的自定義屬性查詢

style() 函式式表示法的 <style-query> 引數可以只包含一個 CSS 變數名;即一個沒有值的自定義屬性。當不包含值時,如果其值與 @property @規則中的 initial-value 描述符的值相同(如果存在),查詢將返回 false。如果自定義屬性值與 initial-value 不同,或者如果自定義屬性在未註冊的情況下被宣告並具有任何值,則樣式查詢將返回 true 並匹配所有這些元素。

未註冊的自定義屬性

當透過 CSS 自定義屬性值賦值引入 CSS 變數時,無值的自定義屬性查詢總是返回 true。

css
:root {
  --theme-color: rebeccapurple;
}

@container style(--theme-color) {
  /* <stylesheet> */
}

在這個例子中,容器查詢匹配聲明瞭 --theme-color 屬性的元素及其所有後代。由於 CSS 變數 --theme-color 是在 :root 上宣告的,樣式查詢 style(--theme-color) 對於該 DOM 節點內的每個元素都將為 true。

已註冊的屬性

已註冊的自定義屬性的行為有所不同。當使用 @property CSS @規則或透過 JavaScript 的 CSS.registerProperty() 顯式定義時,樣式查詢 style(--theme-color) 僅在元素的 --theme-color 計算值與該自定義屬性原始定義中設定的 initial-value 不同時才返回 true。

css
@property --theme-color {
  initial-value: rebeccapurple;
  inherits: true;
}

:root {
  --theme-color: rebeccapurple;
}

main {
  --theme-color: blue;
}

@container style(--theme-color) {
  /* <stylesheet> */
}

在這個例子中,:root 元素不匹配樣式查詢,因為自定義屬性的值與 initial-value 的值相同。該元素(以及所有繼承該值的元素)的自定義屬性值仍然是 rebeccapurple。只有那些與初始值不同的元素,即本例中的 <main> 及其繼承了該已更改值的後代,才會匹配。

帶值的自定義屬性

如果樣式查詢為自定義屬性包含了一個值,那麼該屬性的元素計算值必須完全匹配,只有在自定義屬性是透過包含 syntax 描述符的 @property @規則(或 CSS.registerProperty() 方法呼叫)定義時,等價值才算匹配。

css
@container style(--accent-color: blue) {
  /* <stylesheet> */
}

這個容器樣式查詢匹配任何 --accent-color 自定義屬性的計算值blue 的元素。

在這種情況下,其他等同於 sRGB blue 的顏色值(例如十六進位制程式碼 #0000ff)僅在 --accent-color 屬性透過 @propertyCSS.registerProperty() 定義為顏色時才會匹配,例如:

css
@property --accent-color {
  syntax: "<color>";
  inherits: true;
  initial-value: #0000ff;
}

在這種情況下,如果 --accent-color 的值被設定為 blue#00f#0000ffrgb(0 0 255 / 1)rgb(0% 0% 100%),它都會對 @container style(--accent-color: blue) 返回 true。

示例

在這個示例中,我們有一個包含四個單選按鈕的 <fieldset>。第四個選項包含一個用於輸入自定義顏色的文字 <input>

html
<fieldset>
  <legend>Change the value of <code>--theme</code></legend>
  <ol>
    <li>
      <input type="radio" name="selection" value="red" id="red" />
      <label for="red">--theme: red;</label>
    </li>
    <li>
      <input type="radio" name="selection" value="green" id="green" />
      <label for="green">--theme: green</label>
    </li>
    <li>
      <input type="radio" name="selection" value="blue" id="blue" />
      <label for="blue">--theme: blue</label>
    </li>
    <li>
      <input type="radio" name="selection" value="currentColor" id="other" />
      <label for="other">Other</label>
      <label for="color">color:</label>
      <input text="checkbox" name="selection" value="currentColor" id="color" />
    </li>
  </ol>
</fieldset>
<output>I change colors</output>

每當選擇一個單選按鈕時,JavaScript 都會更新 <body> 元素上的 CSS --theme 變數的值,該元素是 <fieldset><output> 元素的祖先。當文字 <input> 更新時,只有當“其他”單選按鈕被選中時,other 單選按鈕的 value 才會更新,這又會更新 --theme 的值。

js
const radios = document.querySelectorAll('input[name="selection"]');
const body = document.querySelector("body");
const other = document.getElementById("other");
const color = document.getElementById("color");

for (const radio of radios) {
  radio.addEventListener("change", (e) => {
    body.style.setProperty("--theme", e.target.value);
  });
}
color.addEventListener("input", (e) => {
  other.style.setProperty("value", e.target.value);
  if (other.checked) {
    body.style.setProperty("--theme", e.target.value);
  }
});

我們使用 @property @規則來定義一個 CSS 變數 --theme<color> 值,並設定 initial-valuered,以確保無論使用何種語法,等效的顏色都能匹配(例如,red 等於 rgb(255 0 0)#ff0000#f00)。

css
@property --theme {
  syntax: "<color>";
  inherits: true;
  initial-value: red;
}

第一個樣式特性查詢是一個沒有值的自定義屬性。當自定義屬性值的計算值與該屬性的 initial-value 不同時,此查詢型別返回 true。在這種情況下,當 --theme 的值是任何與 red 的任何語法等價值(如 #ff0000)不同的值時,它將為 true。當為 true 時,<output> 將有一個 5px 的虛線輪廓。輪廓顏色是 --theme 的當前值。預設文字color是灰色。

css
@container style(--theme) {
  output {
    outline: 5px dotted var(--theme);
    color: #777777;
  }
}

第二個和第三個樣式查詢為自定義屬性包含了值。如果容器的 --theme 值與列出的值是等效的顏色,即使該值與 initial-value 相同,它們也會匹配。第一個查詢匹配 --theme 值等效於 redbluegreen 的元素。當匹配時,color 將是 --theme 的當前顏色值(在 bluegreen 的情況下,會覆蓋第一個樣式查詢中設定的灰色)。

第二個樣式查詢指出,當 --theme 等效於 red 時,<output> 的內容也將是粗體。我們這樣做是為了更好地演示容器查詢是匹配的。

css
@container style(--theme: green) or style(--theme: blue) or style(--theme: red) {
  output {
    color: var(--theme);
  }
}

@container style(--theme: red) {
  output {
    font-weight: bold;
  }
}

嘗試在文字框中輸入不同的顏色值。你可能會注意到,與 red 等效的 sRGB 值會使 <output> 變紅——因為它匹配 style(--theme: red)——同時移除了輪廓,因為如果元素的 --theme 值與 @property @規則定義的 --theme 的初始值相同,則 style(--theme) 返回 false。任何非紅色的有效 sRGB 顏色值,包括 currentColorhsl(180 100% 50%) 等,都會使第一個樣式查詢返回 true;它們是與 initial-value 不同的值。

因為我們設定了 syntax: "<color>";,所以該 CSS 變數只能被賦予有效的 <color> 值。color 屬性的有效值,如果不是 <color> 值,例如 unsetinherit,對於此自定義屬性是無效的,並將被忽略。

如果你輸入 unsetgibberish,JavaScript 會將 <body> 上的 style 更新為 --theme: unset--theme: gibberish。這兩者都不是顏色,都是無效的並被忽略。這意味著初始值被繼承且未改變,style(--theme) 返回 false,而 style(--theme: red) 返回 true。

注意:在宣告自定義屬性時,請考慮使用帶有 syntax 描述符的 @property,以便瀏覽器可以正確比較計算值。

巢狀查詢

容器查詢可以巢狀在其他容器查詢中。當所有包裝的容器查詢都為 true 時,在多個巢狀容器查詢中定義的樣式將被應用。

css
@container style(--theme: red) {
  output {
    outline: 1px dotted;
  }
  @container style(--theme: purple) {
    output {
      outline: 5px dotted;
    }
  }
}

在這種情況下,如果 <output> 巢狀在設定了 --theme: purple 的容器中,並且該容器又巢狀在 --theme 值為 red 的容器中,那麼 <output> 將有一個 5px 的虛線邊框。

樣式查詢 CSS 宣告和屬性

目前尚未在任何瀏覽器中支援,style() 函式式表示法可以包含常規的 CSS 宣告,包括 CSS 屬性和屬性值對。

css
@container style(font-weight: bold) {
  b,
  strong {
    background: yellow;
  }
}

當支援時,這個基本示例將在父元素已經是 bold 的情況下,使任何 <b><strong> 元素的背景顏色變為黃色。

匹配是針對父容器的計算值進行的;如果父元素的計算 font-weightbold(而不是 bolder900),則匹配成功。就像自定義屬性容器樣式查詢一樣,我們不必將任何元素定義為樣式容器,因為所有元素預設都是樣式容器。只要一個元素沒有設定 container-name,如果它設定了或繼承了 font-weight: bold,它就會匹配。

查詢簡寫屬性的樣式特性,如果其每個具體屬性的計算值都匹配,則為 true,否則為 false。例如,如果構成該簡寫屬性的所有 12 個具體屬性(border-bottom-style 等)都設定為相同的等價值,則 @container style(border: 2px solid red) 將解析為 true。

全域性 CSS 值 revertrevert-layer 作為 <style-feature> 中的值是無效的,並導致容器樣式查詢為 false。

不要將你在樣式查詢中查詢的樣式應用到你正在用該查詢設定樣式的元素上,因為這可能會導致無限迴圈。

預計樣式查詢也將在布林上下文中接受屬性。如果屬性的值是該屬性的初始值(即未被更改),樣式查詢將返回 false,否則返回 true。

css
@container style(font-weight) {
}

上面的示例將對任何 font-weight 值與其初始值不同的元素返回 true。例如,使用者代理樣式表為標題<th> 元素設定了 font-weight: bold。一些瀏覽器將 <strong><b> 設定為 bold,另一些則設定為 bolder<optgroup> 有時也會被使用者代理設定非 normalfont-weight。只要元素的 font-weight 不是該使用者代理的預設值,樣式查詢就將返回 true。

這些特性目前尚未在任何瀏覽器中得到支援。

規範

規範
CSS 條件規則模組第五版
# container-rule

瀏覽器相容性

另見