关于 css-native
css-native 是一项使用原生 CSS 构建网页动画和视觉效果的创意编码技能。它涵盖滚动驱动效果、View Transitions、弹出层定位等技术,并说明何时可能适合改用库。
主要功能
- 01滚动驱动的 CSS 动画
- 02用于页面切换的 View Transitions
- 03原生进入与退出转场
- 04弹出层锚点定位
- 05CSS 与动画库的选择指导
适用场景
- 01为页面添加滚动联动显现效果
- 02为隐藏状态打开的对话框添加动画
- 03定位并动画化提示框
- 04选择 CSS 或动画库
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ athevon/ genjutsu --skill css-native安装后在 Claude Code 中输入/css-native确认已加载。
详细介绍
版本敏感。 以下每个 API 名称、SDK 门槛和浏览器支持声明,均已于 2026-09-08 根据一手来源核实。核实了哪些内容以及核实时间,见
_jutsu/VERSIONS.md。如果这个日期已经很久远,请在依据版本号采取行动前重新核实。
CSS 原生功能 - 零依赖动画与视觉技巧
何时使用 CSS 原生功能,何时使用库
| 情况 | 决策 |
|---|---|
| 页面上的动画少于 3 个 | CSS 原生功能 |
| 滚动驱动的显现/视差效果 | CSS 原生功能(animation-timeline);始终放在 @supports (animation-timeline: scroll()) 内,并确保内容默认可见——Firefox 尚无正式版支持 |
从 display: none 进入/退出 | CSS 原生功能(@starting-style + transition-behavior: allow-discrete) |
| 工具提示/弹出层定位 | CSS 原生功能(锚点定位) |
| 页面过渡(MPA 或 SPA) | CSS 原生功能(视图过渡 API) |
| 复杂的多步骤时间线(5 个以上补间) | GSAP |
| 动态列表中的交错动画(数量未知) | CSS 原生功能(animation-delay: calc(sibling-index() * 60ms));自 2026 年 8 月起达到 Baseline。只有在交错动画必须在运行时中断或重新排序时,才考虑使用库 |
| 可中断的物理弹簧动画 | Framer Motion |
| SVG 形状之间的变形 | GSAP MorphSVG |
经验法则:如果能用一个 @keyframes + 一个 animation-timeline 表达,就继续使用 CSS。需要命令式控制、序列协调或运行时值时,就改用库。
滚动驱动动画
滚动进度时间线
根据容器的滚动位置生成动画。
.progress-bar {
animation: grow-width linear both;
animation-timeline: scroll(root block);
}
@keyframes grow-width {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
scroll(<scroller> <axis>)- scroller:nearest|root|self,axis:block|inline|x|y- 默认值:
scroll(nearest block)
视图进度时间线
当元素进入/离开滚动视口时生成动画。
.reveal {
animation: fade-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(2rem); }
to { opacity: 1; transform: translateY(0); }
}
animation-range
控制时间线中驱动动画的区段。
/* Named ranges: cover | contain | entry | exit | entry-crossing | exit-crossing */
animation-range: entry 0% entry 100%; /* animate during entry only */
animation-range: contain 0% contain 100%; /* animate while fully visible */
animation-range: entry 25% exit 75%; /* custom start/end */
使用 滚动驱动动画工具 交互式查看各个范围。
视图过渡 API
同文档(SPA)
document.startViewTransition(() => {
// Update the DOM synchronously
updateContent();
});
/* Control the transition animation */
::view-transition-old(root) {
animation: fade-out 200ms ease-out;
}
::view-transition-new(root) {
animation: fade-in 300ms ease-in;
}
/* Named transitions for specific elements */
.hero-image { view-transition-name: hero; }
::view-transition-group(hero) {
animation-duration: 400ms;
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
跨文档(MPA)
/* Both pages need this */
@view-transition { navigation: auto; }
/* Outgoing page */
.card { view-transition-name: card-detail; }
/* Incoming page */
.detail-hero { view-transition-name: card-detail; }
view-transition-class(分组样式)
.card { view-transition-class: card; }
::view-transition-group(*.card) {
animation-duration: 350ms;
animation-timing-function: var(--ease-spring);
}
@starting-style
从 display: none 开始的原生进入动画——无需使用 JS 变通方法控制时序。
.dialog {
opacity: 1;
transform: translateY(0);
transition: opacity 300ms ease, transform 300ms ease,
display 300ms allow-discrete;
@starting-style {
opacity: 0;
transform: translateY(-1rem);
}
}
.dialog[hidden] {
opacity: 0;
transform: translateY(-1rem);
display: none;
}
关键规则:
transition-behavior: allow-discrete(或在 transition 中使用简写allow-discrete)可启用对display和overlay的过渡@starting-style块定义元素首次渲染时的「起始」状态- 与
[popover]和<dialog>搭配,可创建无需任何 JS 动画代码的原生模态框
锚点定位
相对于触发元素定位工具提示、弹出层和浮动 UI 的 CSS 原生方式。
.trigger {
anchor-name: --my-trigger;
}
.tooltip {
position: fixed;
position-anchor: --my-trigger;
position-area: top center;
margin-bottom: 0.5rem;
/* Fallback if no space on top */
position-try-fallbacks: --bottom;
}
@position-try --bottom {
position-area: bottom center;
margin-top: 0.5rem;
}
与 @starting-style 搭配,为工具提示添加动画:
.tooltip[popover]:popover-open {
opacity: 1;
transform: scale(1);
transition: opacity 150ms ease, transform 150ms ease,
display 150ms allow-discrete, overlay 150ms allow-discrete;
@starting-style {
opacity: 0;
transform: scale(0.96);
}
}
容器查询 + 上下文动画
根据组件的容器尺寸而非视口调整动画。
.card-container {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
.card-content {
animation: slide-in-right 400ms var(--ease-out-expo);
}
}
@container card (max-width: 399px) {
.card-content {
animation: fade-in 300ms ease;
}
}
关键帧中的容器相对单位:
@keyframes slide-in-right {
from { transform: translateX(10cqw); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
高级视觉技巧
clip-path 过渡
.reveal {
clip-path: inset(0 100% 0 0);
transition: clip-path 600ms cubic-bezier(0.77, 0, 0.175, 1);
}
.reveal.visible {
clip-path: inset(0 0 0 0);
}
形状变形:在 circle()、ellipse()、polygon()、inset() 之间过渡,只要函数类型和点数一致即可。
backdrop-filter
.glass {
background: oklch(0.98 0.01 250 / 0.6);
backdrop-filter: blur(12px) saturate(1.8);
-webkit-backdrop-filter: blur(12px) saturate(1.8); /* Safari */
}
mix-blend-mode
.overlay-text {
mix-blend-mode: difference;
color: white; /* inverts over any background */
}
网格渐变(近似实现)
.mesh {
background:
radial-gradient(at 20% 30%, oklch(0.7 0.2 310) 0%, transparent 50%),
radial-gradient(at 80% 60%, oklch(0.6 0.18 250) 0%, transparent 50%),
radial-gradient(at 50% 80%, oklch(0.75 0.15 170) 0%, transparent 50%),
oklch(0.15 0.02 280);
}
conic-gradient 效果
.spinner {
background: conic-gradient(from 0deg, transparent 0%, oklch(0.7 0.15 250) 100%);
border-radius: 50%;
mask: radial-gradient(farthest-side, transparent calc(100% - 4px), black calc(100% - 4px));
animation: spin 1s linear infinite;
}
不要这样做
| 不佳做法 | 良好做法 | 原因 |
|---|---|---|
transition: all 300ms | transition: opacity 300ms, transform 300ms | all 会在每次属性变化时触发过渡,导致意外动画,并阻止浏览器优化 |
为 width、height、top、left 设置动画 | 为 transform、opacity、clip-path、filter 设置动画 | 触发布局的属性会在每一帧强制重排,而仅触发合成的属性则由 GPU 处理 |
| 使用没有回退方案的滚动驱动动画 | @supports (animation-timeline: scroll()) { ... } | Firefox 的正式发布渠道完全不支持(仅 Nightly 支持,且需启用 layout.css.scroll-driven-animations.enabled),Safari 直到 26 才推出此功能——约六分之一的访客看不到任何效果 |
使用 @starting-style,但不设置 transition-behavior | 始终为 display/overlay 配合使用 allow-discrete | 如果不这样做,display: none 的过渡会完全跳过 |
使用锚点定位,但不设置 position-try-fallbacks | 始终定义回退位置 | 如果首选位置没有空间,元素会被裁剪出视口 |
在滚动驱动动画中使用 animation-fill-mode: forwards | 滚动驱动动画使用 both | forwards 可能会将元素锁定在最终状态,即使用户向回滚动也是如此 |
深入了解
| 需求 | 参考资料 |
|---|---|
滚动驱动动画、View Transitions、@starting-style、锚点定位和容器查询的浏览器支持表、回退模式及渐进增强策略(以及无障碍和性能说明) | references/modern-css.md |
评论
支持 Markdown