Getting started with CSS container queries title. A vibrant gradient behind artwork representing a web browser and a mechanical keyboard.

CSS 容器查詢入門

閱讀時間 8 分鐘

截至今年,所有主流瀏覽器都支援容器查詢。但它們是什麼,我們如何使用它們來構建更健壯、更靈活的佈局?我們還需要媒體查詢嗎?讓我們一探究竟。

關於媒體查詢用於佈局的問題

為了理解容器查詢的便利性,我們來看一個新聞資訊流佈局的例子,看看在哪裡可以應用它們。新聞資訊流是文章的集合,每篇文章都包含圖片、標題和文字摘要。頁面右側還有一個側邊欄,列出熱門文章。

News feed layout shown on desktop

我們可以將它分成兩個網格:左側一個4列網格,右側一個單列(側邊欄)。

The news feed grid layout

在左側,有一篇橫跨四列的大型特色文章。在此下方,兩篇文章各橫跨兩列。它們採用水平佈局,圖片在左,文字在右。在此下方是四篇較小的文章,每篇橫跨一列。一列相同樣式的文章也出現在右側作為側邊欄。

我們可以檢視此佈局,發現三種不同的文章樣式,所有這些都可以作為單獨的元件來開發。但讓我們看看在較小的視口上設計會發生什麼。

Mobile and tablet versions of the news feed layout

在移動裝置尺寸下,所有文章(包括特色文章)的圖片都堆疊在文字上方。它們的佈局無法區分。在稍大的尺寸下,文章採用水平佈局。在更大的視口(我們可能認為是接近平板電腦尺寸的)上,特色文章下方有兩篇水平文章,下方有四篇堆疊的文章。總共有三種不同的單個文章佈局。

News feed layout shown on desktop

如果我們要使用媒體查詢來查詢視口大小來編寫此佈局,我們可能需要建立單獨的元件來處理各種斷點下不同文章佈局的行為。我們的程式碼很容易變得有點笨重,並且難以維護。

將內容適配到可用空間

想象一下,一位編輯過來,想在我們的新聞資訊流旁邊放置不同的內容。我們原來的5列布局在可用空間中不再好看,必須重新設計。在這種情況下,我們可以將一些文章垂直堆疊。

Our layout adjusted to accommodate additional content alongside

使用媒體查詢來檢測視口寬度,我們的佈局無法響應可用空間的變化。如果我們能查詢父元素(或**容器**)的寬度,那就好多了。

什麼是容器查詢?

容器查詢允許我們查詢元素的大小,而不是視口的大小,並相應地設定其後代元素的樣式。我們可以以類似媒體查詢的方式使用它們,但它們為我們提供了更大的佈局靈活性,並有可能大大簡化我們的程式碼。

使用容器查詢構建元件佈局

以單個文章元件為例。我們將逐步介紹如何使用容器查詢來構建響應式文章元件佈局。

Article component layout at three different sizes

建立容器

在編寫容器查詢之前,我們需要一個要查詢的容器元素!在我們的新聞資訊流佈局中,我們需要一個包裝每篇文章的容器元素來作為容器。由於我們的網格是文章列表,每篇文章的容器元素將是<li>。我們會給它一個類名article-container,以避免任何混淆。

The elements of our container query

html
<ul class="grid">
  <li class="article-container">
    <article>...</article>
  </li>
  <li class="article-container">
    <article>...</article>
  </li>
  <li class="article-container">
    <article>...</article>
  </li>
  ...
</ul>

我們使用兩個 CSS 屬性建立容器:container-namecontainer-typecontainer-name 是可選的,但如果有多個容器在頁面上,它會很有用,因為它讓我們清楚地知道我們在引用哪個容器。容器名稱可以是任何我們想要的。我們將這個命名為“article”。

對於基於大小的容器查詢,container-type 應為 inline-sizeinline-size 是一個邏輯值,因此在水平書寫模式(預設)下,它指的是寬度,而在垂直書寫模式下,它指的是高度。size 是另一個可能的值,但它指的是CSS containment 模組,正如 Stephanie Eckles 在她的 Smashing Magazine 文章中所解釋的那樣,它與我們這裡無關。

css
.article-container {
  container-name: article;
  container-type: inline-size;
}

在撰寫本文時,無法查詢塊尺寸。

簡寫

簡寫屬性 container 允許我們同時設定容器名稱和容器型別(此屬性需要容器名稱)。

css
.article-container {
  container: article / inline-size;
}

查詢容器

定義了容器後,編寫容器查詢與編寫媒體查詢類似。編寫查詢時,我們可以選擇指定一個命名容器,也可以省略它,在這種情況下,查詢將預設使用最近的容器。如果我們沒有定義容器,那麼我們的容器查詢將非常像媒體查詢——也就是說,它將查詢視口大小。

指定一個命名容器可能很有幫助,這樣我們可以確切知道正在查詢哪個容器。這對於我們可能有多個巢狀容器的佈局尤其有用。

css
/* Without a named container */
@container (width > 700px) {
  /* Styles applied to elements within any container when the container is over 700px wide  */
}

/* Specifying a named container */
@container article (width > 700px) {
  /* Styles applied to elements within the 'article' container when the container is over 700px wide  */
}

與媒體查詢一樣,我們可以使用任意數量的容器查詢。

css
.article-container {
  container: article / inline-size;
}

article {
  display: grid;
  gap: 1rem;
}

@container article (inline-size > 500px) {
  /* Styles for horizontal article */
  article {
    grid-template-columns: 1fr 2fr;
  }
}

@container article (inline-size > 800px) {
  article {
    /* Styles for article in a large space (e.g. featured article) */
    grid-template-columns: 1fr 1fr;
    gap: 2rem;
    font-size: 1.2rem;
  }

  h3 {
    font-size: 2rem;
  }
}

新的媒體查詢語法

您可能會注意到我們編寫這些容器查詢的方式與傳統媒體查詢略有不同。我們使用的是媒體查詢範圍語法,而不是 min-widthmax-width。這使得我們的查詢更簡潔。

css
/* Old syntax for styles between 700px and 900px */
@container (min-width: 700px) and (max-width: 900px) {
}

/* New syntax */
@container (700px <= width <= 900px) {
}

它也更利於使用邏輯屬性。與其編寫依賴於最小或最大寬度的樣式,不如說“如果內聯尺寸**大於**(或**小於**)x,則應用這些樣式”。

我們之前的容器查詢示例可以重寫為使用 inline-size 而不是 min-width

css
@container article (inline-size > 700px) {
  article {
    /* Styles for horizontal article */
  }
}

巢狀容器

除了響應式文章元件外,我們自己的網格佈局也需要響應可用空間。

Layout grid at three different sizes

這意味著我們需要在網格周圍建立額外的容器。我們需要調整標記以包含這個額外的包裝元素。

html
<div class="grid-container">
  <ul class="grid">
    <li class="article-container">...</li>
    <li class="article-container">...</li>
    <li class="article-container">...</li>
    ...
  </ul>
</div>
css
.grid-container {
  container: layout / inline-size;
}

我們將編寫容器查詢,在空間足夠時分別為我們的網格指定兩列布局和四列布局。

css
/* Initial styles for single column layout */
.grid {
  display: grid;
  gap: 1rem;
}

@container layout (inline-size > 800px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
  }

  /* The featured article should span two columns */
  .article-container:first-child {
    grid-column: span 2;
  }
}

@container layout (inline-size > 1000px) {
  .grid {
    grid-template-columns: repeat(4, 1fr);
  }

  .article-container:first-child {
    grid-column: span 4;
  }

  .article-container:nth-child(2),
  .article-container:nth-child(3) {
    grid-column: span 2;
  }
}

如果我們調整元件的大小,我們可以看到我們的網格佈局和巢狀的文章都響應可用空間。

容器單位

您可能已經熟悉視口單位,它們可用於相對於視口調整元素大小。而容器單位則使我們能夠相對於容器調整元素大小。

容器單位對於設定我們的文章元件樣式非常有用。我們可以使用它們來指定內邊距和字型大小,從而減少為不同斷點調整這些設定的需要。

cqi 單位用於指定容器內聯尺寸的百分比。

css
article {
  padding: 4cqi;
}

(我們不需要在容器查詢中編寫這些樣式。只要定義了容器,它們就會響應容器。)

為了防止內邊距變得過大或過小,我們可以使用 clamp() 函式。它解析為中間值,因此透過傳遞兩個固定值以及我們的靈活 cqi 值,我們可以確保內邊距永遠不會小於 1rem 或大於 3rem

css
article {
  padding: clamp(1rem, 4cqi, 2rem);
}

同樣,我們可以使用 clamp 函式和容器單位來設定字型大小。

瀏覽器支援與回退

截至 2023 年,所有主要瀏覽器都支援容器查詢。然而,我們應該意識到並非所有使用者都擁有最新的瀏覽器。如果您需要支援舊版瀏覽器的使用者,有一個易於使用的 Chrome 團隊的 polyfill

樣式查詢

到目前為止,我們已經介紹瞭如何使用容器查詢來查詢元素的內聯尺寸來構建佈局。但容器查詢的應用遠不止於此。我們還可以查詢帶有自定義屬性的元素的樣式。

在我們的示例佈局中,我們可能希望透過不同的樣式來吸引“特色”文章的注意力。在我們的標記中設定自定義屬性,然後我們可以為具有特定自定義屬性值的元素應用樣式。

html
<div class="grid-container">
  <ul class="grid">
    <li class="article-container">...</li>
    <li class="article-container">...</li>
    <li class="article-container" style="--featured: true">...</li>
    ...
  </ul>
</div>
css
@container style(--featured: true) {
  article {
    border-radius: 0.2rem;
    background: pink;
    border: 1px solid deeppink;
    padding: clamp(1rem, 5cqi, 3rem);
  }
}

我們不需要定義容器,因為每個元素都自動具有樣式容器。在 Una Kravets 的文章中可以瞭解更多關於樣式容器查詢的資訊。

侷限性和瀏覽器支援

在撰寫本文時,Chrome 和 Edge 支援容器樣式查詢。Safari 或 Firefox 目前不支援。在CSS Containment Module Level 3 規範中,為查詢任何屬性-值對(不僅僅是自定義屬性)提供了支援。但目前還沒有瀏覽器支援這一點。

我們還需要媒體查詢嗎?

如果我們能夠使用容器查詢來查詢視口大小元素大小,我們是否還需要媒體查詢?當然需要!媒體查詢用於查詢的不僅僅是大小。我們可以檢測使用者的偏好,例如 prefers-reduced-motionprefers-color-scheme,僅舉兩例。

仍然可能出現需要根據視口大小為巢狀容器內的元素設定樣式的情況,而媒體查詢可能是最簡單的方法。但我預測,在不久的將來,容器查詢將在佈局方面在很大程度上取代媒體查詢,而媒體查詢將主要保留用於上述等其他媒體特性。

總結

容器查詢為我們提供了對響應式佈局的更多控制,同時也幫助我們編寫更簡潔、更健壯、更易於維護的 CSS。既然它們已經獲得了廣泛的瀏覽器支援,現在是嘗試它們的好時機。最棒的是,您不必立即全部投入:如果有一個元件您在使用媒體查詢時難以構建,那麼值得看看容器查詢,因為它們可能是您正在尋找的答案。

在此處檢視結合本文所有示例的完整演示

其他資源