关于 css-scroll-driven-native
css-scroll-driven-native 是使用原生 CSS 时间线、无需 JavaScript 添加滚动效果的技能,适用于渐进增强,并要求静态内容回退和减少动态效果保护。
主要功能
- 01CSS scroll() 与 view() 时间线
- 02进度条、显现和视差效果
- 03@supports 静态回退指导
- 04减少动态效果保护
- 05Playwright 视觉验证
适用场景
- 01添加页面滚动进度条
- 02卡片进入视口时显现
- 03制作轻量视差效果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rheinmir/ setup --skill css-scroll-driven-native安装后在 Claude Code 中输入/css-scroll-driven-native确认已加载。
附带文件assets/demo.cssassets/demo.html
详细介绍
Skill:css-scroll-driven-native
使用公开的 CSS 规范实现页面滚动效果——animation-timeline: scroll() / view() + animation-range,无需一行 JavaScript。
WHAT
用途和上下文
- **用途:**使用纯 CSS
animation-timeline添加滚动效果(进度条、进入视口时显示、轻度视差),作为渐进增强——不支持该特性的浏览器或启用了减少动态效果设置的用户,仍能看到完整的静态内容。 - **触发条件(何时使用):**用户提到「css scroll driven animation」「animation-timeline」「不用 js 的滚动动画」「纯 css 页面滚动」「scroll-driven CSS」或 /css-scroll-driven-native;或者希望在
scroll-effects之上添加零 JS 的「流畅感」。根据「何时选这个而非scroll-effects」(Reference 部分)中的表格进行选择。 - **非目标:**不作为需要立即确保跨浏览器稳定运行的生产环境主机制(此时应使用
scroll-effects,即 JS IntersectionObserver);不编写 JS;不硬编码浏览器版本号。
心智模型
timeline (scroll(root) | view()) + animation-range → keyframes;全部放在 @supports → @media not (prefers-reduced-motion: reduce) 中;这两个代码块之外 = 静态状态,完整显示内容。
输入和输出约定
| 字段 | 必填? | 含义 | |
|---|---|---|---|
| In | 所需机制(progress / reveal / parallax) | 是 | 从 3 种机制中选择 1–3 种 |
| In | 项目的 design.md | 否 | 如有,则据此调整颜色和间距 token |
| Out | 从 assets/demo.css / assets/demo.html 改编的 CSS(+ 最少标记) | 是 | 所有动画均放在 @supports 中,并设置 reduce-motion 防护 |
| Out | 验证证据 | 是 | 使用 playwright-verify 提供 0%/50%/100% 滚动截图,以及 reduce-motion 截图 |
规则和能力
规则(必须遵守):
- RULE-01(MUST):始终提供
@supports回退:所有动画都必须放在@supports (animation-timeline: scroll())或@supports (animation-timeline: view())中。@supports代码块之外必须是默认的静态状态——元素完整显示,不播放动画,绝不能默认隐藏或设置 opacity:0。如果为显示效果设置opacity:0,该值只能放在@supports内,不能放在基础规则中。 - RULE-02(MUST):
prefers-reduced-motion:将动画放在@media not (prefers-reduced-motion: reduce)中(嵌套在@supports内,见demo.css)。用户启用 reduce-motion 后,所有元素都必须恢复为与不支持该特性的浏览器完全相同的静态状态。 - RULE-03(MUST):不得在代码或注释中硬编码版本号——每次实际使用时都要检查 caniuse.com/css-scroll-driven-animations(支持情况见 Reference 部分的表格)。
- RULE-04(MUST):仍必须声明
animation-duration(1ms或任何大于 0 的值),即使实际时长由时间线控制——有些引擎需要该值才能触发动画。 - RULE-05(MUST):使用
playwright-verify在 Chromium 浏览器中验证(CDP 默认支持滚动驱动动画):在滚动位置为 0%/50%/100% 时截图,并断言进度条/scaleX 和卡片 opacity 会随滚动位置变化;同时使用模拟的prefers-reduced-motion: reduce再截图(PlaywrightemulateMedia),以断言动画不会播放,但内容仍完整显示。 - 能力:读取 skill 资源和
design.md;将 CSS/HTML 写入目标项目;运行支持媒体模拟的无头 Chromium 浏览器。
失败边界
- 要求「必须立即确保在所有浏览器上稳定运行」→ clarify/改用
scroll-effects作为基础,本 skill 仅用于覆盖增强。 @supports条件不成立或启用 reduce-motion 时内容被隐藏 → failed(违反 RULE-01/02),交付前修复。- Chromium 中 0%/50%/100% 的截图完全相同 → failed(动画未触发,通常是缺少
animation-duration)。
HOW
主工作流
| 步骤 | 类型 | 输入 | 操作 | 输出/退出 | 失败/下一步 |
|---|---|---|---|---|---|
| W01 | 判断 | yêu cầu + đích trình duyệt | 根据对比表选择此 skill 或 scroll-effects;检查 caniuse | 决策 | 需要确保跨浏览器运行 → B01 |
| W02 | 确定性 | assets/demo.* | 阅读 assets/demo.html + assets/demo.css,提取所需机制 | 代码片段 | — |
| W03 | 效果 | 代码片段,design.md | 调整颜色/间距 token;将动画放在 @supports + reduce-motion 中 | 项目中的 CSS | — |
| W04 | 确定性 | 已接入的页面 | 验证 RULE-05:截取 0/50/100% 的截图 + emulateMedia reduce | 截图 + 断言 | 断言失败 → 修复,重复 W04 |
分支
| ID | 类型 | 条件 | 行为 | 跳过 / 失败 | 重新汇合 |
|---|---|---|---|---|---|
| B01 | 可选(用户) | 需要确保跨浏览器运行,但仍希望获得比 0-JS 更流畅的效果 | 组合使用:以 scroll-effects 为基础,浏览器支持时由此 skill 覆盖 | 只需支持 Chromium → 跳过 | W02 |
验证与停止
在 W04 中进行确定性断言(scaleX/opacity 随滚动位置变化;reduce-motion 下没有动画,内容完整)。需要人工检查:流畅度/是否符合设计。两类截图都通过后停止;连续 2 轮仍失败 → 附上截图告知用户。
示例
- 正向:“用纯 CSS 添加阅读进度条” → 在
@supports+ reduce-motion 防护条件下使用.csdn-progress和animation-timeline: scroll(root)→ 截取 0%/50%/100% 的截图,确认 scaleX 为 0 → ~0.5 → 1。 - **边界/失败:**Reveal card 在基础规则中设置
opacity:0→ 在不支持该功能的 Firefox 中,card 会消失 → 违反 RULE-01;将opacity:0移入@supports,然后重新验证 reduce-motion。
参考 — 何时选择此方案,何时选择 scroll-effects
css-scroll-driven-native(此 skill) | scroll-effects | |
|---|---|---|
| JS | 0 行 | IntersectionObserver + rAF |
| 浏览器支持 | Chrome/Edge 支持良好;Firefox/Safari 正在推出支持,可能尚未默认启用 | 所有现代浏览器 |
| 使用场景 | 渐进增强——为已支持的浏览器增添“流畅度”,如果需要立即确保生产环境支持多浏览器,则不可将其作为主要机制 | 需要立即确保稳定运行、不等待支持推出时,作为主要机制 |
建议:在 @supports (animation-timeline: scroll()) 中使用此 skill,并采用静态回退方案(不播放动画、不隐藏内容)——也可以组合使用:以 scroll-effects 为基础,浏览器支持时由此 skill 覆盖。
⚠️ 用于生产环境前,请检查实际支持情况:caniuse.com/css-scroll-driven-animations — 不要依赖本文档中记载的固定数据;API 正在快速推出,支持情况可能已经变化。
当前浏览器支持情况(记录于撰写此 skill 时,2026-09 — 可能已经变化,请务必自行检查):
| 浏览器 | animation-timeline: scroll() | animation-timeline: view() |
|---|---|---|
| Chrome / Edge | 支持 | 支持 |
| Firefox | 需启用 flag / 正在推出支持 | 需启用 flag / 正在推出支持 |
| Safari | 正在推出支持,尚不稳定 | 正在推出支持,尚不稳定 |
参考 — 资源
assets/demo.html + assets/demo.css — 3 种演示机制,阅读后进行调整(如果项目中有 design.md,请根据它调整颜色/间距 token)。使用支持此功能的浏览器(新版 Chrome/Edge)直接打开即可查看实际效果;不支持的浏览器会自动回退到静态状态。
参考 — 3 种机制(最简标记 + 机制)
1. 页面滚动进度条
固定在页面顶部的进度条,其长度随页面已滚动的百分比变化。
<div class="csdn-progress"></div>
.csdn-progress {
animation-name: progress-scale;
animation-duration: 1ms; /* giá trị bất kỳ để kích hoạt engine — thời lượng thật do timeline điều khiển */
animation-timeline: scroll(root);
animation-fill-mode: both;
}
@keyframes progress-scale {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
scroll(root) 会跟踪整个页面的滚动进度——无需 scroll 侦听器,也无需手动计算 scrollY / scrollHeight。
2. 元素进入视口时显示
<article class="csdn-card">…</article>
.csdn-card {
animation-name: reveal-in;
animation-timeline: view();
animation-range: entry 0% cover 40%;
animation-fill-mode: both;
}
view() 是每个元素根据自身在视口中的位置使用的独立时间线——完全取代 IntersectionObserver。animation-range: entry 0% cover 40% 表示动画从元素开始进入视口时(entry 0%)开始播放,直到元素已经“覆盖”其经过视口路径的 40%。
3. Parallax nhẹ dùng view()
Nền và nội dung dùng animation-range khác nhau trên cùng một timeline view() → tạo cảm giác lớp trôi khác tốc độ, không cần tính toán scrollY thủ công.
.parallax-bg { animation-timeline: view(); animation-range: cover 0% cover 100%; } /* trôi chậm, suốt cả quãng */
.parallax-content { animation-timeline: view(); animation-range: entry 0% cover 35%; } /* chạy nhanh, chỉ đoạn đầu */
Xem assets/demo.css mục 3 để có keyframes đầy đủ.
Origin
- Bổ sung cho
skills/scroll-effects(JS-based, chạy mọi trình duyệt) một lựa chọn 0-JS cho trình duyệt đã hỗ trợ — hai skill KHÔNG thay thế nhau, dùng theo bảng "Khi nào chọn cái này" ở trên.