開始使用樣式查詢

尤娜.克雷維茲 (Una Kravets)
Una Kravets

查詢父項內嵌大小和容器查詢單位值的功能,目前在所有新型瀏覽器引擎中都獲得穩定支援。

瀏覽器支援

  • 105
  • 105
  • 110
  • 16

資料來源

不過,包含規格不僅包含大小查詢,還可讓您查詢父項的樣式值。自 Chromium 111 起,您將可為自訂屬性值套用樣式包含的樣式,以及查詢自訂屬性值的父項元素。

瀏覽器支援

  • 111
  • 111
  • x
  • x

資料來源

這表示我們在 CSS 中對樣式有更邏輯的控制,讓您能夠更妥善地分隔應用程式的邏輯和資料層與樣式。

CSS 包含模組第 3 級規格 (涵蓋大小和樣式查詢),可讓您從父項查詢任何樣式,包括屬性和 font-weight: 800 等值組合。不過,隨著這項功能推出,樣式查詢目前僅支援 CSS 自訂屬性值。對於合併樣式及區隔設計資料,這個做法仍相當實用。以下說明如何搭配 CSS 自訂屬性使用樣式查詢:

開始使用樣式查詢

假設我們有以下 HTML:

<ul class="card-list">
  <li class="card-container">
    <div class="card">
      ...
    </div>
  </li>
</ul>

如要使用樣式查詢,您必須先設定容器元素。視您查詢的是直接或間接父項而定,採取的做法也會稍有不同。

查詢直接父項

樣式查詢圖表。

與樣式查詢不同,您不需要使用 container-typecontainer 屬性將包含項目套用至 .card-container.card 就能查詢其直接父項的樣式。不過,我們需要將樣式 (這裡是指自訂屬性值) 套用至容器 (在本例中為 .card-container) 或任何「包含」在 DOM 中設定樣式的元素。我們無法對使用這項查詢設定樣式的直接元素套用查詢的樣式,因為這可能會導致無限迴圈。

如要直接查詢父項,您可以寫入:

/* styling .card based on the value of --theme on .card-container */
@container style(--theme: warm) {
  .card {
    background-color: wheat;
    border-color: brown; 
    ...
  }
}

您可能已經注意到,樣式查詢會使用 style() 包裝查詢。這有助於區分樣式的大小值。舉例來說,您可以將容器寬度的查詢為 @container (min-width: 200px) { … }。如果父項容器的寬度至少為 200 像素,就會套用樣式。不過,min-width 也可以是 CSS 屬性,您可以使用樣式查詢查詢 min-width 的 CSS 值。因此,建議使用 style() 包裝函式來清楚說明差異:@container style(min-width: 200px) { … }

設定非直接父項樣式

如要查詢非直接父項元素的樣式,則必須為該元素設定 container-name。舉例來說,我們可以根據 .card-list 的樣式為 .card 套用樣式,方法是提供 .card-list 一個 container-name,然後在樣式查詢中參照該樣式。

/* styling .card based on the value of --moreGlobalVar on .card-list */
@container cards style(--moreGlobalVar: value) {
  .card {
    ...
  }
}

一般而言,最佳做法是為容器命名,以便清楚描述查詢內容,並使容器能更輕鬆地存取這些容器。舉例來說,如果您想直接在 .card 內設定元素樣式,就很適合使用這種做法。在 .card-container 上缺少已命名容器,就無法直接查詢。

但這些事在實務上卻更有意義。以下列舉幾個例子:

實際設定查詢的樣式

這張示範圖片包含多張產品資訊卡,部分資訊卡含有「全新」或「低存貨」標記,以及帶有紅色背景的「低庫存」資訊卡。

如果您有可重複使用的元件包含多個變化版本,或者您無法控制所有樣式,但在某些情況下需要套用變更,樣式查詢就特別實用。本例顯示共用相同資訊卡元件的一組產品資訊卡。部分產品資訊卡會顯示額外詳細資料/附註,例如「新品」或「低存貨」,而是由名為「--detail」的自訂屬性觸發。此外,如果產品的狀態為「低庫存」,就會套用紅色邊框背景。這類資訊可能由伺服器轉譯,並可透過內嵌樣式套用到資訊卡,如下所示:

 <div class="product-list">
  <div class="product-card-container" style="--detail: new">
    <div class="product-card">
      <div class="media">
        <img .../>
      <div class="comment-block"></div>
    </div>
  </div>
  <div class="meta">
    ...
  </div>
  </div>
  <div class="product-card-container" style="--detail: low-stock">
    ...
  </div>
  <div class="product-card-container">
    ...
  </div>
  ...
</div>

透過這類結構化資料,您可以將值傳遞至 --detail,並使用以下 CSS 自訂屬性來套用樣式:

@container style(--detail: new) {
  .comment-block {
    display: block;
  }
  
  .comment-block::after {
    content: 'New';
    border: 1px solid currentColor;
    background: white;
    ...
  }
}

@container style(--detail: low-stock) {
  .comment-block {
    display: block;
  }
  
  .comment-block::after {
    content: 'Low Stock';
    border: 1px solid currentColor;
    background: white;
    ...
  }
  
  .media-img {
    border: 2px solid brickred;
  }
}

上述程式碼允許為 --detail: low-stock--detail: new 套用方塊,但您可能已註意到程式碼區塊中有多餘的功能。目前無法只使用 @container style(--detail) 查詢 --detail 是否存在,這樣更容易分享樣式並減少重複性。這項功能目前在工作群組中討論

天氣資訊卡

上一個範例使用包含多個可能值的單一自訂屬性,並套用樣式。但您也可以使用及查詢多項自訂屬性,將這兩者結合在一起。以此天氣資訊卡為例:

天氣卡示範。

如要設定這些資訊卡的背景漸層和圖示樣式,請找出天氣特性,例如「陰天」、「下雨」或「晴天」:

@container style(--sunny: true) {
  .weather-card {
    background: linear-gradient(-30deg, yellow, orange);
  }
  
  .weather-card:after {
    content: url(<data-uri-for-demo-brevity>);
    background: gold;
  }
}

如此一來,您就能根據每張資訊卡的獨特特性,設定其樣式。不過,您也可以為特徵 (自訂屬性) 組合設定樣式,方法與使用媒體查詢相同的方式使用 and 組合器。例如,某日晴天和晴天會如下所示:

@container style(--sunny: true) and style(--cloudy: true) {
    .weather-card {
      background: linear-gradient(24deg, pink, violet);
    }
  
  .weather-card:after {
      content: url(<data-uri-for-demo-brevity>);
      background: violet;
  }
}

區分資料與設計

在這些示範中,將資料層 (顯示於網頁上的 DOM) 與套用的樣式分開,具有結構優勢。樣式是以元件樣式中可能存在的變化版本編寫,端點則可能會傳送用於設定元件樣式的資料。您可以使用單一值 (例如第一個範例是更新 --detail 值) 或多個變數 (例如在第二個範例中為 --rainy--cloudy--sunny)。最棒的是,您也可以合併這些值,檢查 --sunny--cloudy 可能顯示局部多雲的樣式。

你可以順暢透過 JavaScript 更新自訂屬性值,例如在設定 DOM 模型時 (例如在架構中建構元件時),或是隨時使用 <parentElem>.style.setProperty('--myProperty’, <value>) 更新。I

以下示範在幾行程式碼中,更新按鈕的 --theme,並使用樣式查詢和該自訂屬性 (--theme) 套用樣式:

使用樣式查詢設定資訊卡的樣式,用於更新自訂屬性值的 JavaScript 如下:

const themePicker = document.querySelector('#theme-picker')
const btnParent = document.querySelector('.btn-section');

themePicker.addEventListener('input', (e) => {
  btnParent.style.setProperty('--theme', e.target.value);
})

本文介紹的功能只是第一步。您將能透過容器查詢取得更多內容,以便建立動態的回應式介面。具體來說,樣式查詢還有幾個待解決的問題。一種是實作 CSS 樣式 (自訂屬性以外) 的樣式查詢。這已屬於目前的規格層級,但尚未在任何瀏覽器中導入。待解決的「問題」解決後,系統應將布林結構定義評估新增至目前的規格層級,而範圍查詢則規劃於規格的下一個層級進行。