📋 目錄
過去兩年 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 Nesting | 93%+ |
| Container Queries | 92%+ |
| :has() | 93%+ |
| color-mix() | 91%+ |
| oklch() | 91%+ |
| Scroll-driven Animations | 80%+ |
如果你的用戶群中有 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 終於有這些功能了。
延伸閱讀
- Interop 2026 瀏覽器大一統 — 瀏覽器相容性狀態
- Container Queries 元件級響應式 — 響應式設計新標準
本文是「2026 CSS 實用技術」系列文章之一。