A
約 2 分鐘閱讀

你可能還不知道的現代 CSS 功能 — Nesting、:has() 與 @container

CSS 在這幾年彷彿開了外掛,推出了許多大家敲碗已久的功能。如果你還停留在 SASS/SCSS 的時代,是時候來看看原生 CSS 現在有多強大了。

1. 原生巢狀(Nesting)

以前我們一定要用 SCSS 才能這樣寫:

/* SCSS */
.card {
  background: white;

  .title {
    color: black;
  }
}

現在,原生 CSS 直接支援了!所有現代瀏覽器都已經支援這個語法。

/* Native CSS */
.card {
  background: white;

  & .title {
    color: black;
  }

  &:hover {
    background: #f0f0f0;
  }
}

優點:不用編譯器,瀏覽器原生讀得懂。結構更清晰,減少重複寫 selector。

2. 父層選擇器 :has()

這大概是 CSS 歷史上被敲碗最久的功能。以前我們只能往下選(Parent > Child),不能往上選(Child < Parent)。

:has() 讓你終於可以說:「如果這個卡片裡面有圖片,就讓卡片自動變成左右兩欄的 grid 版面」。

/* 如果 .card 裡面包含 .image,就讓 .card 變成 grid layout */
.card:has(.image) {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

/* HTML: <input id="x"><label for="x">...</label> */
/* 如果 input 被勾選了,就把緊接在後面的 label 變紅色 */
input:checked + label {
  color: red;
}

/* HTML: <label>...</label><input id="x">(label 在前、input 在後時)*/
/* :has() 讓我們終於能「往前選取」:根據後面兄弟元素的狀態,反過來選取前面的元素 */
label:has(+ input:checked) {
  color: red;
}

威力強大:它不只是父層選擇器,更像是「條件選擇器」。

3. 容器查詢(Container Queries)

RWD(響應式設計)一直以來都是基於 視窗寬度(Viewport Width),也就是 @media (max-width: 768px)

但這有個問題:一個卡片元件,放在側邊欄(窄)和放在主內容區(寬),我們希望它長得不一樣。但 @media 不知道卡片現在在多寬的容器裡。

@container 解決了這個問題。它是基於父容器的寬度來做變化。

.card-container {
  container-type: inline-size; /* 宣告這是一個容器 */
}

.card {
  display: flex;
  flex-direction: column;
}

/* 當容器寬度大於 400px 時,變成橫排 */
@container (min-width: 400px) {
  .card {
    flex-direction: row;
  }
}

這對於元件化開發(Component-Driven Development)來說是革命性的改變。元件終於可以真正做到「隨處可用,自動適應」。

結語

這些 CSS 新招早就不是什麼做夢才有的「未來科技」了,現在主流瀏覽器幾乎都全面支援。下次開新專案的時候,不如大膽一點,跳過 CSS 預處理器,直接來感受原生 CSS 的威力吧,保證寫起來超有成就感的!


站內相關文章: