
CSS 正在把 JS 的活抢回去
过去几年,很多“必须用 JS 才能做”的效果已经被 CSS 原生实现:滚动驱动动画、弹层、主题切换、页面转场。这不只是写法变化,而是更少的代码、更少的布局抖动、更好的可访问性。
下面这四个特性,是 2026 年最值得投入学习的。
一、容器查询:组件自适应,而不是页面自适应
媒体查询看的是视口,容器查询看的是父容器。这让“同一个卡片在侧栏和主区显示不同布局”成为可能,组件终于真正自洽。
.card-wrap { container-type: inline-size; container-name: card; }
.card { display: grid; gap: 12px; grid-template-columns: 1fr; }
/* 容器宽度 >= 480px 时切换为双列 */
@container card (min-width: 480px) {
.card { grid-template-columns: 200px 1fr; }
.card .title { font-size: 1.5rem; }
}
/* 容器查询单位:按容器宽度的 1% 计算 */
.card .meta { font-size: clamp(0.75rem, 3cqi, 1rem); }<aside style="width:320px">
<div class="card-wrap">
<article class="card">…</article>
</div>
</aside>
<main>
<div class="card-wrap">
<article class="card">…</article>
</div>
</main>同一份组件代码,在窄侧栏里是单列,在主内容区自动变双列——无需 JS 测量宽度。
二、@scope:把样式关进笼子
BEM、CSS Modules 本质上都是在解决“选择器全局污染”。@scope 是语言层面的答案:
@scope (.card) to (.card__footer) {
/* 只在 .card 内生效,且不穿透到 .card__footer 内部 */
img { border-radius: 8px; }
:scope { padding: 16px; }
.title { font-weight: 600; }
}to (...) 定义“作用域下界”,非常适合组件库与微前端场景:样式既不外泄,也不会误伤子组件。
三、View Transitions:原生页面转场
/* 声明参与转场的元素 */
.avatar { view-transition-name: avatar; }
.card-title { view-transition-name: title; }
/* 自定义转场动画 */
::view-transition-old(avatar) {
animation: fade-out 200ms ease-out;
}
::view-transition-new(avatar) {
animation: fade-in 250ms ease-in;
}
@keyframes fade-in { from { opacity: 0; transform: scale(0.9); } }
@keyframes fade-out { to { opacity: 0; transform: scale(1.05); } }SPA 里手动触发:
function navigateTo(url) {
if (!document.startViewTransition) {
render(url);
return;
}
// 浏览器截图旧状态 → 执行更新 → 截图新状态 → 自动补间
document.startViewTransition(async () => {
await render(url);
});
}多页应用(MPA)也能用,只需在 CSS 里加一行:
@view-transition { navigation: auto; }四、Tailwind CSS 4:CSS 优先的配置
Tailwind 4 把配置从 tailwind.config.js 移到了 CSS 里,并用 Rust 引擎(Lightning CSS)大幅提速。
/* app.css */
@import "tailwindcss";
@theme {
--color-brand: oklch(0.72 0.16 195);
--font-display: "Inter", sans-serif;
--spacing: 0.25rem;
--breakpoint-3xl: 120rem;
}
/* 自定义工具类,无需写插件 */
@utility tab-4 {
tab-size: 4;
}
/* 容器查询内置 */
@container (min-width: 32rem) {
.prose { font-size: 1.125rem; }
}<!-- 容器查询与新版调色板 -->
<div class="@container">
<article class="@md:grid-cols-2 grid gap-4 bg-brand/10">…</article>
</div>构建配置也更简单:
// vite.config.ts
import tailwindcss from "@tailwindcss/vite";
export default { plugins: [tailwindcss()] };五、还有几个顺手的新特性
/* 1. 原生 CSS 嵌套,不用预处理器 */
.card {
padding: 1rem;
& .title { font-weight: 600; }
&:hover { box-shadow: 0 2px 8px rgb(0 0 0 / 0.1); }
}
/* 2. :has() —— 父选择器终于来了 */
.form:has(input:invalid) { border-color: crimson; }
.card:has(> img) { padding-top: 0; }
/* 3. 滚动驱动动画,无需 JS 监听 scroll */
@keyframes reveal { from { opacity: 0; translate: 0 40px; } }
.section {
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 10% cover 40%;
}
/* 4. 弹层无需 position:fixed 与 z-index 战争 */
.dialog { popover: auto; }六、渐进采用建议
- 先用
@supports做特性检测,保证旧浏览器不崩:
@supports (container-type: inline-size) {
.card-wrap { container-type: inline-size; }
}- 容器查询优先替换“用 JS 测宽度”的旧逻辑;
- View Transitions 先用在列表→详情这类明确的转场上;
- 新项目直接用 Tailwind 4,老项目等稳定后再迁移(配置迁移工具已提供)。
小结
现代 CSS 的主题是把控制权还给浏览器:布局交给容器查询,作用域交给 @scope,动画交给 View Transitions,样式工程交给 Tailwind 4。每拿下一个特性,你的 JS 包就能再瘦一圈。
暂无评论