CSSCSS 2026Container Queries前端開發2026

CSS 2026 進化論:這些功能讓 JavaScript 變多餘

CSS 2026 完整教學!Container Queries、:has()、原生巢狀、Scroll-driven Animations、oklch() 10+ 新功能攻略。2026 年工程師必看的 CSS 進階指南!

· 5 分鐘閱讀

過去兩年 CSS 的變革,超過了前十年的總和。2026 年,前端工程師終於可以說出那句「我用純 CSS 做到了」——而且這次是真的有觀點、有說服力的。前幾天我看到一個真實案例:一個中等規模的前端專案,通過採用 2024-2026 年的 CSS 新功能,刪除了 2400 行 JavaScript 和 Sass 代碼。這個數字值得你認真看看這篇文章。


CSS 的兩年奇蹟

如果你有五年以上的前端經驗,你會記得那些「CSS 做不到」的事情:

  • 需要 JavaScript 才能知道父元素有沒有某個子元素
  • 需要 Media Query 才能做到響應式,而且響應的是 viewport,不是元件本身
  • 需要 Sass 才能有巢狀樣式
  • 需要 JS 動畫庫才能做到滾動觸發動畫
  • 色彩需要繞彎路才能做到半透明混合

2026 年,這些問題都有原生的 CSS 解法了。


可以拋棄的技術棧

1. Sass/Less 巢狀 → 原生 CSS Nesting

/* 過去:需要 Sass 才能巢狀 */
// Sass
.card {
  padding: 16px;

  .card-header {
    margin-bottom: 12px;

    .card-title {
      font-size: 18px;
    }
  }
}
/* 現在:原生 CSS 就支援巢狀 */
.card {
  padding: 16px;

  & .card-header {
    margin-bottom: 12px;

    & .card-title {
      font-size: 18px;
    }
  }
}

Sass 的變數、mixin、extend 仍然有用——但巢狀這個功能,已經不需要了。

2. Media Query → Container Queries

Media Query 的問題:響應的是 viewport,不是元件。一個側邊欄元件在 viewport < 768px 時是窄的,但在 larger viewport 的主內容區卻可能是寬的。

/* Container Queries:響應的是父容器的寬度,不是 viewport */
.card-container {
  container-type: inline-size;
  container-name: card;
}

@container card (width < 400px) {
  .card {
    padding: 12px;
  }

  .card-title {
    font-size: 16px;
  }
}

@container card (width >= 400px) {
  .card {
    padding: 24px;
  }

  .card-title {
    font-size: 20px;
  }
}

同一個 .card 元件,放在側邊欄和主內容區,會自動響應各自的容器寬度——不需要 JavaScript,不需要重複的 class 變體。

3. JS 切換 class → :has() 選擇器

// 過去:需要 JS 來切換樣式
const toggle = document.querySelector('.toggle');
const container = document.querySelector('.container');

toggle.addEventListener('click', () => {
  container.classList.toggle('has-open');
});
/* 現在::has() 讓 CSS 可以根據子元素的狀態來選擇父元素 */
.container:has(.toggle:checked) {
  /* 什麼都不需要 */
}

/* 表單驗證 */
input:has(:invalid) {
  border-color: red;
}

/* 有某個特定子元素的父元素 */
.card:has(.badge) {
  padding-top: 32px;
}

過去 CSS 無法「選擇有某個子元素的父元素」,這個限制讓多少 JavaScript 代碼是專門為了樣式切換而存在的?:has() 改變了這一點。

4. JS 滾動庫 → Scroll-driven Animations

// 過去:需要 GSAP 或 Locomotive Scroll
gsap.registerPlugin(ScrollTrigger);

ScrollTrigger.create({
  trigger: '.fade-in',
  start: 'top 80%',
  onEnter: () => element.classList.add('visible'),
});
/* 現在:原生 CSS */
.fade-in {
  opacity: 0;
  transform: translateY(20px);
  animation: fade-up linear both;
  animation-timeline: view();
  animation-range: entry 0% cover 40%;
}

@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

詳見我之前的文章《告別 JS 動畫庫:CSS Scroll-Driven Animations 實戰》。


2026 年必知的 10+ CSS 新功能

Container Queries(元件級響應式)

已在「可拋棄」章節說明。

:has()(父選擇器)

已在「可拋棄」章節說明。

原生 CSS Nesting(巢狀)

已在「可拋棄」章節說明。

color-mix()(色彩混合)

/* 2026:原生的色彩混合 */
.button-primary {
  background-color: color-mix(in oklch, #3b82f6 70%, white);
}

.button-hover {
  background-color: color-mix(in oklch, #3b82f6 80%, black);
}

oklch()(現代色彩空間)

/* oklch:比 HSL 更符合人類視覺的色彩表示 */
:root {
  --primary: oklch(55% 0.18 250);
  --secondary: oklch(65% 0.15 180);
}

/* 為什麼比 hsl 好:調整亮度時不會突然改變色相 */
.primary-lighter {
  color: oklch(65% 0.18 250);  /* 同樣的色相,更亮的亮度 */
}

text-wrap: balance(文本換行優化)

/* 標題文本自動平衡換行,不需要 JS */
h1 {
  text-wrap: balance;
  max-width: 20ch;  /* 限制寬度以觸發換行 */
}

Scroll State Queries(滾動狀態查詢)

/* 根據滾動方向改變樣式 */
@supports (selector(:scroll-state(connected))) {
  .header:scroll-state(scrolled-down) {
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(8px);
  }
}

Customizable <select>(可自訂下拉選單)

/* 2026:原生 select 可以自訂樣式 */
select {
  appearance: auto;
  background: white;
  border: 1px solid oklch(70% 0.1 250);
  border-radius: 8px;
  padding: 8px 32px 8px 12px;
}

/* 配合 :focus-visible */
select:focus-visible {
  outline: 2px solid #3b82f6;
  outline-offset: 2px;
}

sibling-index()(兄弟索引選擇器)

/* 自動為兄弟元素編號 */
li {
  counter-increment: item;
}

li::before {
  content: counter(item, decimal-leading-zero);
}

/* 或者用 CSS 新功能 */
li:nth-child(1 of :not([aria-hidden])) {
  /* 選擇第一個可見的 li */
}

if() 函數(條件樣式)

/* 2026:CSS 也有三元運算式了 */
.card-width {
  width: if(container(width) >= 600px, 50%, 100%);
}

.text-size {
  font-size: if(browsing(mobile), 14px, 16px);
}

真實案例:如何刪除 2400 行代碼

這是一個真實的遷移案例(來自 CSS 2026 社群分享):

項目:一個電子商務前臺頁面

原始技術棧

  • Sass(巢狀、變數、mixin)
  • JavaScript(響應式切換、滾動動畫、表單驗證)
  • 3 個外部 JS 庫(GSAP ScrollTrigger、Lo-dash、Moment.js)

遷移後

  • 純 CSS(使用 CSS Nesting、Container Queries、Scroll-driven Animations)
  • 移除了所有 3 個外部 JS 庫

結果

  • 刪除 2400 行 CSS/Sass
  • 刪除 1800 行 JavaScript
  • 移除 3 個外部庫
  • Bundle 體積減少 340KB
  • 效能分數提升(Core Web Vitals 全綠)

瀏覽器支援與 Progressive Enhancement

2026 年主流 CSS 新功能的瀏覽器支援已經足夠:

功能支援率
CSS Nesting93%+
Container Queries92%+
:has()93%+
color-mix()91%+
oklch()91%+
Scroll-driven Animations80%+

如果你的用戶群中有 Firefox 使用者(目前 Scroll-driven Animations 尚在開發中),可以考慮 Progressive Enhancement:

/* 有支援的瀏覽器用新語法 */
@supports (animation-timeline: scroll()) {
  .fade-in {
    animation: fade linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 40%;
  }
}

結語:CSS 正在吃掉 JavaScript 的地盤

這不是「CSS 會取代 JavaScript」的標題黨言論。這是事實:CSS 正在接管那些本來就不應該用 JavaScript 處理的任務——樣式切換、響應式佈局、簡單動畫。

前端工程師的技能模型正在悄悄改變。過去「CSS 難」的原因是 CSS 能做的事情太少,不得不依靠 JavaScript 來彌補。2026 年的 CSS 能做到的事情已經足夠多,多數常見的 UI 交互模式,純 CSS 已經可以實現。

2400 行代碼的刪除,不是因為工程師偷懶——而是因為 CSS 終於有這些功能了。


延伸閱讀

本文是「2026 CSS 實用技術」系列文章之一。