開始使用樣式查詢

最近能夠查詢父系內嵌大小和容器查詢單位值的功能,已經在所有新型瀏覽器引擎中穩定支援。

瀏覽器支援

  • 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 設為 container-name,並在樣式查詢中參照,根據 .card-list 的樣式將樣式套用至 .card

/* 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 套用方塊,但您可能注意到程式碼區塊中有多餘的功能。目前,目前無法只查詢 --detail@container style(--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,可能會出現局部多雲的風格。

您可以在設定 DOM 模型時 (也就是在架構中建構元件時),輕鬆透過 JavaScript 更新自訂屬性值,或是使用 <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 樣式查詢的樣式。這已經是目前規格等級的一部分,但尚未在任何瀏覽器中實作。解決尚未解決的問題時,布林值評估應加入目前的規格層級,而範圍查詢預計會在下一個規格層級加入。