222222222222

现代 CSS

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; }

六、渐进采用建议

  1. 先用 @supports 做特性检测,保证旧浏览器不崩:
@supports (container-type: inline-size) {
  .card-wrap { container-type: inline-size; }
}
  1. 容器查询优先替换“用 JS 测宽度”的旧逻辑;
  2. View Transitions 先用在列表→详情这类明确的转场上;
  3. 新项目直接用 Tailwind 4,老项目等稳定后再迁移(配置迁移工具已提供)。

小结

现代 CSS 的主题是把控制权还给浏览器:布局交给容器查询,作用域交给 @scope,动画交给 View Transitions,样式工程交给 Tailwind 4。每拿下一个特性,你的 JS 包就能再瘦一圈。

标签: none

暂无评论