css-scroll-driven-native

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Skill: css-scroll-driven-native

Skill: css-scroll-driven-native

Hiệu ứng cuộn trang bằng CSS spec công khai —
animation-timeline: scroll()
/
view()
+
animation-range
— không một dòng JavaScript.
使用公开 CSS 规范实现页面滚动效果——
animation-timeline: scroll()
/
view()
+
animation-range
——不写一行 JavaScript。

WHAT

内容

Purpose và context

目的与上下文

  • Purpose: thêm hiệu ứng cuộn (progress bar, reveal-on-view, parallax nhẹ) bằng CSS thuần
    animation-timeline
    làm progressive enhancement — trình duyệt chưa hỗ trợ hoặc bật reduce-motion vẫn thấy đủ nội dung tĩnh.
  • Trigger (when to use): user nói "css scroll driven animation", "animation-timeline", "scroll animation không js", "css thuần cuộn trang", "scroll-driven CSS", hoặc /css-scroll-driven-native; hoặc muốn thêm "độ mượt" 0-JS phía trên
    scroll-effects
    . Chọn theo bảng "Khi nào chọn cái này vs
    scroll-effects
    " (mục Reference).
  • Non-goals: không phải cơ chế chính khi cần chạy chắc production đa trình duyệt ngay (đó là
    scroll-effects
    , JS IntersectionObserver); không viết JS; không cứng số phiên bản trình duyệt.
  • 目的: 使用纯 CSS
    animation-timeline
    添加滚动效果(进度条、进入视窗时显现、轻量级视差),作为渐进式增强——不支持该功能的浏览器或启用 reduce-motion 的用户仍可看到完整的静态内容。
  • 触发条件(何时使用): 用户说
    css scroll driven animation
    、
    animation-timeline
    、
    scroll animation không js
    、
    css thuần cuộn trang
    、
    scroll-driven CSS
    或
    /css-scroll-driven-native
    ;或者希望在
    scroll-effects
    基础上增加“零 JS”的流畅效果。根据“何时选择此方案与
    scroll-effects
    ”对比表(参考部分)进行选择。
  • 非目标: 当需要立即确保在生产环境中兼容多个浏览器时,不应将其作为主要机制(应使用基于 JS IntersectionObserver 的
    scroll-effects
    );不编写 JS;不在代码中硬编码浏览器版本。

Mental model

核心模型

timeline (scroll(root) | view()) + animation-range → keyframes; toàn bộ nằm trong @supports → @media not (prefers-reduced-motion: reduce); ngoài hai khối đó = trạng thái tĩnh hiện đủ nội dung
.
timeline (scroll(root) | view()) + animation-range → keyframes
;全部放在
@supports
→
@media not (prefers-reduced-motion: reduce)
中;位于这两个代码块之外时,呈现内容完整的静态状态。

Input và output contract

输入与输出约定

FieldRequired?Ý nghĩa
Incơ chế cần (progress / reveal / parallax)cóchọn 1–3 trong 3 cơ chế
In
design.md
của dự án
khôngcó thì đổi token màu/spacing theo nó
OutCSS (+ markup tối thiểu) adapt từ
assets/demo.css
/
assets/demo.html
cómọi animation trong
@supports
+ reduce-motion guard
Outbằng chứng verifycóảnh 0%/50%/100% scroll + ảnh reduce-motion qua
playwright-verify
字段是否必填含义
输入所需机制(progress / reveal / parallax)是从 3 种机制中选择 1–3 种
输入项目的
design.md
否如存在,则根据它调整颜色和 spacing token
输出基于
assets/demo.css
/
assets/demo.html
适配的 CSS(+ 最少 markup)
是所有 animation 均置于
@supports
+ reduce-motion guard 中
输出验证证据是通过
playwright-verify
获取 0%/50%/100% 滚动位置截图,以及 reduce-motion 截图

Rules và capabilities

规则与能力

Rules (BẮT BUỘC):
  • RULE-01 (MUST): Luôn có fallback
    @supports
    : mọi animation nằm trong
    @supports (animation-timeline: scroll())
    hoặc
    @supports (animation-timeline: view())
    . Bên NGOÀI khối
    @supports
    là trạng thái TĨNH mặc định — phần tử hiện đủ nội dung, không animation, KHÔNG BAO GIỜ ẩn/opacity:0 làm mặc định. Nếu viết
    opacity:0
    cho hiệu ứng reveal, giá trị đó CHỈ được đặt bên trong
    @supports
    , không phải ở rule gốc.
  • RULE-02 (MUST):
    prefers-reduced-motion
    : bọc animation trong
    @media not (prefers-reduced-motion: reduce)
    (lồng bên trong
    @supports
    , xem
    demo.css
    ). Người dùng bật reduce-motion → mọi phần tử về trạng thái tĩnh giống hệt trình duyệt không hỗ trợ.
  • RULE-03 (MUST): KHÔNG cứng số phiên bản vào code hay comment — kiểm tra caniuse.com/css-scroll-driven-animations mỗi lần dùng thật (bảng hỗ trợ ở mục Reference).
  • RULE-04 (MUST):
    animation-duration
    vẫn phải khai (
    1ms
    hoặc giá trị bất kỳ >0) dù thời lượng thật do timeline điều khiển — một số engine yêu cầu giá trị này để kích hoạt animation.
  • RULE-05 (MUST): Verify bằng
    playwright-verify
    trên trình duyệt Chromium (CDP mặc định hỗ trợ scroll-driven animations): chụp ảnh tại 0%/50%/100% scroll, assert progress bar/scaleX và card opacity đổi theo vị trí cuộn; đồng thời chụp thêm với
    prefers-reduced-motion: reduce
    giả lập (Playwright
    emulateMedia
    ) để assert KHÔNG animation nhưng nội dung vẫn hiện đủ.
  • Capabilities: đọc asset skill +
    design.md
    ; ghi CSS/HTML vào dự án đích; chạy trình duyệt Chromium headless có giả lập media.
规则(必须遵守):
  • RULE-01(必须):始终提供
    @supports
    fallback
    :所有 animation 均放在
    @supports (animation-timeline: scroll())
    或
    @supports (animation-timeline: view())
    中。
    @supports
    代码块之外默认为静态状态——元素完整显示内容,不包含 animation,绝不能默认隐藏元素或设置
    opacity:0
    。如果为 reveal 效果编写
    opacity:0
    ,该值只能放在
    @supports
    内部,不能放在基础规则中。
  • RULE-02(必须):
    prefers-reduced-motion
    :将 animation 包裹在
    @media not (prefers-reduced-motion: reduce)
    中(嵌套在
    @supports
    内部,参见
    demo.css
    )。当用户启用 reduce-motion 时,所有元素都会回到与不支持该功能的浏览器完全相同的静态状态。
  • RULE-03(必须):不得在代码或注释中硬编码浏览器版本——每次实际使用时都应检查 caniuse.com/css-scroll-driven-animations(支持情况表见参考部分)。
  • RULE-04(必须):即使实际时长由 timeline 控制,仍必须声明
    animation-duration
    (
    1ms
    或任意大于 0 的值)——部分引擎需要该值才能激活 animation。
  • RULE-05(必须):使用
    playwright-verify
    在 Chromium 浏览器中验证(CDP 默认支持 scroll-driven animations):分别截取 0%/50%/100% 滚动位置的图片,断言 progress bar/scaleX 和 card opacity 会随滚动位置变化;同时使用模拟的
    prefers-reduced-motion: reduce
    再截取图片(Playwright
    emulateMedia
    ),断言此时没有 animation,但内容仍完整显示。
  • 能力:读取 skill asset +
    design.md
    ;向目标项目写入 CSS/HTML;运行支持媒体模拟的 headless Chromium。

Failure boundaries

失败边界

  • Yêu cầu "phải chạy chắc trên mọi trình duyệt ngay" → clarify/chuyển
    scroll-effects
    làm nền, skill này chỉ override.
  • Nội dung bị ẩn khi
    @supports
    sai hoặc reduce-motion bật → failed (vi phạm RULE-01/02), sửa trước khi giao.
  • Ảnh 0%/50%/100% giống hệt nhau trên Chromium → failed (animation không kích hoạt, thường thiếu
    animation-duration
    ).
  • 要求“必须立即在所有浏览器中稳定运行” → clarify/切换到
    scroll-effects
    作为基础,此 skill 仅执行覆盖。
  • 当
    @supports
    编写错误或启用 reduce-motion 时内容被隐藏 → 失败(违反 RULE-01/02),必须先修复再交付。
  • Chromium 中 0%/50%/100% 的图片完全相同 → 失败(animation 未激活,通常是因为缺少
    animation-duration
    )。

HOW

方法

Main workflow

主要工作流

StepTypeInputsActionOutputs/exitFailure/next
W01judgmentyêu cầu + đích trình duyệtChọn skill này hay
scroll-effects
theo bảng so sánh; kiểm caniuse
quyết địnhcần chắc đa trình duyệt → B01
W02deterministic
assets/demo.*
Đọc
assets/demo.html
+
assets/demo.css
, lấy cơ chế cần
snippet—
W03effectsnippet,
design.md
ADAPT token màu/spacing; đặt animation trong
@supports
+ reduce-motion
CSS trong dự án—
W04deterministictrang đã gắnVerify RULE-05: chụp 0/50/100% +
emulateMedia
reduce
ảnh + assertassert đỏ → sửa, lặp W04
步骤类型输入操作输出/退出条件失败/下一步
W01判断需求 + 目标浏览器根据对比表选择此 skill 或
scroll-effects
;检查 caniuse
决策需要确保多浏览器兼容 → B01
W02确定性
assets/demo.*
读取
assets/demo.html
+
assets/demo.css
,提取所需机制
snippet—
W03效果实现snippet、
design.md
ADAPT 颜色/spacing token;将 animation 放入
@supports
+ reduce-motion 中
项目中的 CSS—
W04确定性已集成的页面验证 RULE-05:截取 0/50/100% 图片 +
emulateMedia
reduce
图片 + assertassert 失败 → 修复并重复 W04

Branches

分支

IDKindGuardHành viSkip / failureRejoin
B01user_optionalcần chạy chắc đa trình duyệt nhưng vẫn muốn 0-JS mượt hơnkết hợp:
scroll-effects
làm nền, skill này override khi trình duyệt hỗ trợ
chỉ cần Chromium → skipW02
ID类型条件行为跳过/失败汇合点
B01user_optional需要确保多浏览器稳定运行,但仍希望获得更流畅的 0-JS 效果组合使用:以
scroll-effects
为基础,在浏览器支持时由此 skill 覆盖
只需要 Chromium → 跳过W02

Validation và stopping

验证与停止条件

Assert tất định ở W04 (scaleX/opacity đổi theo vị trí cuộn; reduce-motion không animation, nội dung đủ). Cần mắt: độ mượt/hợp design. Dừng khi hai loại ảnh đều đạt; 2 vòng vẫn đỏ → báo user kèm ảnh.
在 W04 执行确定性断言(scaleX/opacity 随滚动位置变化;reduce-motion 下没有 animation 且内容完整)。还需要人工检查流畅度及设计一致性。当两类图片均通过时停止;如果 2 轮后仍然失败,则向用户报告并附上图片。

Examples

示例

  • Positive: "thêm progress bar đọc bài bằng css thuần" →
    .csdn-progress
    với
    animation-timeline: scroll(root)
    trong
    @supports
    + reduce-motion guard → ảnh 0%/50%/100% cho scaleX 0 → ~0.5 → 1.
  • Boundary/failure: reveal card đặt
    opacity:0
    ở rule gốc → trên Firefox chưa hỗ trợ card biến mất → vi phạm RULE-01, chuyển
    opacity:0
    vào trong
    @supports
    rồi verify lại với reduce-motion.
  • 正向示例: “使用纯 CSS 为文章添加阅读进度条” → 使用带
    animation-timeline: scroll(root)
    的
    .csdn-progress
    ,置于
    @supports
    + reduce-motion guard 中 → 提供 0%/50%/100% 的图片,展示 scaleX 从 0 → 约 0.5 → 1。
  • 边界/失败示例: 在基础规则中为 reveal card 设置
    opacity:0
    → 在尚不支持该功能的 Firefox 上 card 会消失 → 违反 RULE-01,应将
    opacity:0
    移入
    @supports
    内,然后使用 reduce-motion 重新验证。

Reference — Khi nào chọn cái này vs
scroll-effects

参考——何时选择此方案与
scroll-effects

css-scroll-driven-native
(skill này)
scroll-effects
JS0 dòngIntersectionObserver + rAF
Hỗ trợ trình duyệtChrome/Edge tốt; Firefox/Safari đang rollout, có thể chưa bật mặc địnhMọi trình duyệt hiện đại
Khi dùngProgressive enhancement — thêm "độ mượt" cho trình duyệt đã hỗ trợ, KHÔNG phải cơ chế chính nếu cần chạy chắc production đa trình duyệt ngayCơ chế chính khi cần chạy chắc ngay, không đợi rollout
Khuyến nghị: dùng skill này bên trong
@supports (animation-timeline: scroll())
, fallback tĩnh (không animation, không ẩn nội dung) — hoặc kết hợp cả hai:
scroll-effects
làm nền, skill này override khi trình duyệt hỗ trợ.
⚠️ Kiểm tra hỗ trợ thật trước khi dùng production tại caniuse.com/css-scroll-driven-animations — đừng tin số liệu cứng ghi trong tài liệu này, API đang rollout nhanh và bảng hỗ trợ có thể đã đổi.
Bảng hỗ trợ trình duyệt hiện tại (ghi tại thời điểm viết skill, 2026-09 — có thể đã đổi, luôn tự kiểm tra):
Trình duyệt
animation-timeline: scroll()
animation-timeline: view()
Chrome / EdgeCóCó
FirefoxBehind flag / đang rolloutBehind flag / đang rollout
SafariĐang rollout, chưa ổn địnhĐang rollout, chưa ổn định
css-scroll-driven-native
(此 skill)
scroll-effects
JS0 行IntersectionObserver + rAF
浏览器支持Chrome/Edge 支持良好;Firefox/Safari 正在 rollout,可能尚未默认启用所有现代浏览器
使用场景渐进式增强——为已支持的浏览器增加“流畅度”;如果需要立即确保生产环境中的多浏览器兼容,则不应将其作为主要机制需要立即确保稳定运行、无需等待 rollout 时使用的主要机制
建议:在
@supports (animation-timeline: scroll())
内使用此 skill,并提供静态 fallback(无 animation、不隐藏内容);也可以组合使用两者:以
scroll-effects
为基础,在浏览器支持时由此 skill 覆盖。
⚠️ 投入生产环境前务必检查实际支持情况:访问 caniuse.com/css-scroll-driven-animations——不要相信本文档中记录的固定数据,该 API 正在快速 rollout,支持情况可能已经发生变化。
当前浏览器支持表(记录于 skill 编写时,2026-09——可能已经发生变化,请始终自行检查):
浏览器
animation-timeline: scroll()
animation-timeline: view()
Chrome / Edge支持支持
FirefoxBehind flag / 正在 rolloutBehind flag / 正在 rollout
Safari正在 rollout,尚未稳定正在 rollout,尚未稳定

Reference — Assets

参考——Assets

assets/demo.html
+
assets/demo.css
— 3 cơ chế demo, đọc rồi ADAPT (đổi token màu/spacing theo
design.md
của dự án nếu có). Mở trực tiếp bằng trình duyệt hỗ trợ (Chrome/Edge mới) để xem chạy thật; trình duyệt chưa hỗ trợ sẽ tự rơi về trạng thái tĩnh.
assets/demo.html
+
assets/demo.css
——包含 3 种机制的 demo;读取后再进行 ADAPT(如果项目存在
design.md
,则根据它调整颜色和 spacing token)。可直接在受支持的新版 Chrome/Edge 中打开查看实际运行效果;不受支持的浏览器会自动回退到静态状态。

Reference — 3 cơ chế (markup tối thiểu + cơ chế)

参考——3 种机制(最少 markup + 机制)

1. Progress bar theo cuộn trang

1. 随页面滚动的进度条

Thanh cố định trên cùng, dài theo % đã cuộn hết trang.
html
<div class="csdn-progress"></div>
css
.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)
bám vào tiến độ cuộn của toàn trang — không cần
scroll
listener, không cần tính
scrollY / scrollHeight
bằng tay.
固定在页面顶部,宽度对应页面已滚动的百分比。
html
<div class="csdn-progress"></div>
css
.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
listener,也不需要手动计算
scrollY / scrollHeight
。

2. Reveal-on-view khi phần tử vào khung nhìn

2. 元素进入视窗时执行 Reveal-on-view

html
<article class="csdn-card">…</article>
css
.csdn-card {
  animation-name: reveal-in;
  animation-timeline: view();
  animation-range: entry 0% cover 40%;
  animation-fill-mode: both;
}
view()
là timeline riêng của TỪNG phần tử theo vị trí trong viewport của chính nó — thay hẳn IntersectionObserver.
animation-range: entry 0% cover 40%
nghĩa là animation chạy từ lúc phần tử bắt đầu vào viewport (
entry 0%
) tới khi đã "cover" 40% quãng đường qua viewport.
html
<article class="csdn-card">…</article>
css
.csdn-card {
  animation-name: reveal-in;
  animation-timeline: view();
  animation-range: entry 0% cover 40%;
  animation-fill-mode: both;
}
view()
是每个元素根据自身在 viewport 中位置生成的独立 timeline,可完全取代 IntersectionObserver。
animation-range: entry 0% cover 40%
表示 animation 从元素开始进入 viewport(
entry 0%
)时运行,直到元素完成 viewport 穿越路径的 40%(“cover”)。

3. Parallax nhẹ dùng
view()

3. 使用
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.
css
.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 đủ.
背景和内容在同一个
view()
timeline 上使用不同的
animation-range
→ 营造不同速度的层间漂移效果,无需手动计算
scrollY
。
css
.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 */
有关完整的 keyframes,请查看
assets/demo.css
的第 3 节。

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.
  • 为
    skills/scroll-effects
    (基于 JS,兼容所有浏览器)补充一个面向受支持浏览器的 0-JS 选项——两个 skill 不可相互替代,应根据上文的“何时选择此方案”对比表使用。