CSS新規範:樣式查詢

前端小智發表於2022-12-29
微信搜尋 【大遷世界】, 我會第一時間和你分享前端行業趨勢,學習途徑等等。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

最近,Chrome團隊釋出了對一個新的CSS規範的實驗性支援,即樣式查詢。簡而言之,它讓我們查詢容器的樣式,而不是隻查詢尺寸。在查詢容器尺寸不夠的情況下,這可能很有幫助。

CSS 容器查詢

介紹樣式查詢之前,我們先來回顧容器查詢。

CSS 容器查詢(Container Queries)是一項新的 CSS 功能,允許開發人員根據元素的大小來應用樣式。這意味著,開發人員可以為不同大小的裝置或瀏覽器視窗應用不同的樣式,而無需使用媒體查詢或使用 JavaScript 來檢測裝置大小。

image.png

我們來看看一個例子:

.o-grid__item {
  container-type: inline-size;
}

.c-article {
  /* The default style */
}

@container (min-width: 400px) {
  .c-article {
    /* The styles that will make the article horizontal**
    ** instead of a card style.. */
  }
}

首先,我們需要在定義 container-type。然後,使用 @container開始查詢。一旦滿足了這個條件,CSS將應用於該容器內的元件。

樣式查詢

簡單地說,樣式查詢讓我們查詢一個容器的CSS屬性或CSS變數。

樣式查詢仍然是試驗性的,目前只在Chrome Canary中實現。要測試它們,請進入chrome://flags並啟用 "Experimental Web Platform features"的切換。

例如,我們可以檢查容器是否有 display: flex,並在此基礎上為子元素設計樣式。

.page-header {
  display: flex;
}

@container style(display: flex) {
  .page-header__start {
    flex: 1;
    display: flex;
    align-items: center;
    border-right: 1px solid lightgrey;
  }
}

理想情況下,上述做法應該是可行的,但目前Chrome Canary中的樣式查詢原型僅侷限於CSS變數。樣式查詢預計將在Chrome M111中出現。

現在,我們可以檢查變數--boxed: true是否被新增到容器中,如果是,我們可以在此基礎上改變子元素的樣式。

請看下圖:

image.png

請注意,容器查詢和樣式查詢的主要區別在於,前者是針對大小的查詢,後者是針對樣式的查詢。

.card-container {
  --boxed: true;
}

@container style(--boxed: true) {
  .card {
    /* boxed styles */
  }
}

問題

在探討我們可以在哪裡使用樣式查詢之前,我們先來回答大家常見的一個問題:樣式查詢能解決什麼問題?容器查詢還不夠嗎?

這是一個好問題。在容器查詢中,我們可以根據一個元件的父級寬度來控制它的樣式,這非常有用。不過,在某些情況下,我們可能不需要查詢尺寸,而是想查詢一個容器的計算樣式。

為了讓你有更好的瞭解,請看下圖:

image.png

這是一篇來自CMS的文章正文。我們有一個預設的圖片樣式和另一個看起來有特色的樣式。

下面是對應的程式碼:

<figure>
  <img src="cheesecake.jpg" alt="" />
  <figcaption>....</figcaption>
</figure>
figcaption {
  font-size: 13px;
  padding: 4px 8px;
  background: lightgrey;
}

當我們開始對特色的進行造型時,我們需要覆蓋上述內容,並有一個CSS類,我們可以用它進行造型。

.featured-figure {
  display: flex;
  flex-wrap: wrap;
}

.featured-figure figcaption {
  font-size: 16px;
  padding: 16px;
  border-left: 3px solid;
  margin-left: -6rem;
  align-self: center;
}

當我們開始為突出顯示的元素新增樣式時,我們需要覆蓋上述樣式並定義一個 CSS 類,以便可以對其進行樣式設定。

.featured-figure {
  display: flex;
  flex-wrap: wrap;
}

.featured-figure figcaption {
  font-size: 16px;
  padding: 16px;
  border-left: 3px solid;
  margin-left: -6rem;
  align-self: center;
}

很酷,這個方法行。我們能不能做得更好?是的!使用樣式查詢,我們可以在 figure 中新增 display: flex 或一個 CSS 變數 --featured: true,然後基於這個進行樣式設定。

<figure>
  <img src="cheesecake.jpg" alt="" />
  <figcaption>....</figcaption>
</figure>
figure {
  container-name: figure;
  --featured: true;
}

/* Featured figure style. */
@container figure style(--featured: true) {
  img {
    /* Custom styling */
  }

  figcaption {
    /* Custom styling */
  }
}

如果 --featured: true 不存在,我們將預設使用基本 figure 設計。我們可以使用 not 關鍵字來檢查 figure 是否沒有 display: flex

/* Default figure style. */
@container figure not style(--featured: true) {
  figcaption {
    /* Custom styling */
  }
}

要知道的幾個細節預設情況下,每個元素都是樣式容器

所以根本不需要定義一個樣式容器。預設情況下,它就在那裡。

我們不能用類名來解決這個問題嗎?

是的,我們可以。使用樣式查詢的目的是使 CSS 更易讀並更容易修改。上述邏輯可以作為一個元件 CSS 寫出,而無需將所有這些樣式新增到條件類中。

事例:https://codepen.io/shadeed/pe...

減少 CSS 特定性問題

我喜歡使用樣式查詢的原因是,它將減少 CSS 特定性,因為我們將不太依賴 CSS 變化類或 HTML 資料屬性來對元件變化進行樣式設定。

在下面的 CSS 中,我們為 section 新增了基本樣式。沒有什麼特別的。

.section {
  background-color: lightgrey;
}

.section__title,
.section__desc {
  color: #222;
}

我們需要一種方法來為它設定不同的主題,因此我們使用了變化類。

.section--dark {
  background-color: #222;
}

.section--dark .section__title,
.section--dark .section__desc {
  color: #fff;
}

使用樣式查詢,我們可以在 .section 元件周圍使用容器,然後在不在 CSS 中建立更多特定性的情況下為標題和描述打標籤。

@container style(--theme: dark) {
  .section {
    background-color: #222;
  }

  .section__title,
  .section__desc {
    color: #fff;
  }
}

這看起來乾淨多了。

接下來,我們探索幾種樣式查詢可能有幫助的使用情況。

使用情況和示例

基於上下文的樣式設定

image.png

這是一種常見的使用情況,在同一包裝器中我們使用了相同的元件但用法不同。在右側,我們有一個文章元件,可能包含一個數字或不包含。

目前,我們可能會使用一個新的 CSS 類來解決樣式設定問題,或者可能在文章元件本身上使用變化類。

.most-popular {
  counter-reset: list;
}

.most-popular article {
  /* custom styling */
}

或者我們可能在 HTML 中使用 data 屬性。

.most-popular[data-counter="true"] {
  counter-reset: list;
}

.most-popular[data-counter="true"] .article {
  /* custom styling */
}

使用 CSS 樣式查詢,我們可以在父元素中新增一個 CSS 變數,並根據此對文章進行樣式設定。看看這個:

.most-popular {
  --counter: true;
}

@container style(--counter: true) {
  .articles-list {
    counter-reset: list;
  }

  .article {
    display: flex;
    align-items: flex-start;
  }

  .article:before {
    counter-increment: list;
    content: counter(list);
  }
}

我們甚至不需要在文章元件上使用變化類。也不需要使用 CSS 巢狀。

示例:https://codepen.io/shadeed/pe...

元件級的主題切換

我們構建的一些元件根據特定條件需要使用不同的主題。在下面的示例中,我們有一個包含不同統計元件的儀表板。

基於包裝器,我們需要切換元件的主題。

image.png

目前,我們可以使用特殊類根據它們的容器為自定義統計元件新增樣式。

.special-wrapper .stat {
  background-color: #122c46;
}

.special-wrapper .stat__icon {
  background-color: #2e547a;
}

.special-wrapper .stat__title {
  background-color: #b3cde7;
}

上面的做法一點也沒有錯,也不壞,但因為我們巢狀了CSS,所以增加了特殊性。讓我們探討一下如何用樣式查詢來實現上述內容。

首先,我們需要在特殊包裝器上定義一個切換按鈕。然後,我們可以檢查該開關是否處於啟用狀態,並對狀態元件進行相應的設計。

.special-wrapper {
  --theme: dark;
  container-name: stats;
}

@container stats style(--theme: dark) {
  .stat {
    /* Add the dark styles. */
  }
}

image.png

在這種情況下,樣式查詢的有用之處在於,將上述樣式放在 CSS 中的一個地方是有意義的。

/* stat.css */
.stat {
  /* default styling */
}

@container stats style(--theme: dark) {
  .stat {
    /* custom styling */
  }
}

頭像組

在這個例子中,我們有一組使用者的頭像。我們需要根據在父代上設定的一個CSS變數,以不同的方式來佈置它們。我從Atlassian設計系統中挑選了這個例子。

image.png

<div class="avatars-wrapper">
  <div class="avatars-list">
    <div class="avatar"></div>
    <!-- more avatars -->
  </div>
</div>

在CSS中,我給容器新增了一個名字,並定義了--appearance: default變數。

.avatars-wrapper {
  container-name: avatars;
}

.avatars-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

有了這個,我們就可以使用樣式查詢來改變基於--appearance變數的佈局。

@container avatars style(--appearance: stack) {
  .avatar {
    box-shadow: 0 0 0 2px #fff;
  }

  .avatar + .avatar {
    margin-inline-start: -0.5rem;
  }
}

@container avatars style(--appearance: grid) {
  .avatars-list {
    gap: 0.5rem;
    max-width: 200px;
  }
}

地址:https://codepen.io/shadeed/pe...

條件裝飾樣式

在某些情況下,我們可能需要根據文字元素在 HTML 中的位置為其新增條件裝飾樣式。

image.png

標題和段落下方有一個旋轉的背景效果。這是透過偽元素實現的:

<div class="content">
  <h2><!-- Title here --></h2>
  <p><!-- Description --></p>
</div>

要對它們進行樣式設定,我們可以使用 CSS 變數並檢查它是否已切換,然後相應地新增樣式。在示例中,:after 偽元素被新增到 .content 容器的每個子元素。

.content {
  --decorated: true;
}

@container style(--decorated: true) {
  :after {
    content: "";
    position: absolute;
    inset: 0;
    background-color: var(--dec-color, green);
    opacity: 0.1;
    z-index: -1;
    transform: rotate(-1.5deg);
  }
}

image.png

地址:https://codepen.io/shadeed/pe...

RTL 樣式:卡片元件

寫 RTL 樣式時,第一步是在 <html> 元素中新增 dir=rtl。一旦新增,每個元素的 direction CSS 屬性都會變為 direction: rtl

隨著邏輯屬性的興起,我們不需要完全重寫 CSS。考慮以下示例:

.item {
  margin-inline-start: 1rem;
}

對於從左到右的佈局,上述內容將計算為 margin-left。對於從右到左的佈局,它將是 margin-right。很酷,對吧?但是我們仍然沒有檢查漸變方向的邏輯 CSS。

樣式查詢可以用於解決這個問題。考慮以下示例:

image.png

我們有一個元件,由兩個元素組成,這兩個元素都應根據文件改變方向:

  • 漸變:對於 LTR 佈局,它從左到右。
  • 箭頭方向:指向右邊。
  • 上述內容無法使用邏輯 CSS 控制。目前,我們這樣做:
html[dir="rtl"] .card {
  background: linear-gradient(to left, ...);
}

html[dir="rtl"] .card__cta {
  transform: scaleX(-1);
}

使用樣式查詢,我們可以查詢容器並檢查direction是否等於 rtl,並根據此對樣式進行更改。

.card {
  --bg-angle: to right;
  background: linear-gradient(var(--bg-angle), #5521c3, #5893eb);
}

@container card style(direction: rtl) {
  .card {
    --bg-angle: to left;
  }

  .card__cta {
    transform: scaleX(-1);
  }
}

請注意,樣式查詢的當前原型不支援 style() 查詢中的 CSS 屬性。因此,我在示例中使用了 CSS 變數。

新聞模組

這是我在 bbc.com 上發現的真實問題。最初,我們有以下新聞元件。

image.png

根據其容器,樣式應略有改變。考慮以下圖:

image.png

注意元件現在有兩個修改:

  • 白色背景。
  • 標題和描述容器四周填充。
  • 這是 BBC.com 上 CSS 的樣式:
.media--padded {
  background: #fff;
}

.media--padded .media__content {
  padding: 0.75rem 0.75rem 3rem 0.75rem;
}

我們如何透過樣式查詢來解決這個問題呢?很簡單,我們需要一種方法來告訴元件,如果你住在這個容器內,卡片的樣式應該被填充。

.special-container {
  --card--padded: true;
}

@container style (--card-padded: true) {
  .media {
    background: #fff;
  }

  .media__content {
    padding: 0.75rem 0.75rem 3rem 0.75rem;
  }
}

總結

CSS 樣式查詢是 CSS 的強大補充。我迫不及待地想看看社群中的其他人會用它們做什麼。哦,我也忍不住想在 iShadeed 實驗室中為樣式查詢建立一個新目錄。敬請期待!

原文:https://ishadeed.com/article/...

編輯中可能存在的bug沒法實時知道,事後為了解決這些bug,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章