当前位置:首页 > 文章列表 > 文章 > 前端 > CSS animation-timeline怎样按滚动进度驱动进度条

CSS animation-timeline怎样按滚动进度驱动进度条

来源:17golang原创 2026-11-05 03:35:22 0浏览 收藏
热门推荐
漫画APP
动画内容聚合,热门资源快捷查看
立即下载

如果页面内容比较长,阅读进度条不一定要依赖 JavaScript 监听 scroll 事件。CSS 的 animation-timeline 可以把动画从默认的“按时间播放”改成“按滚动进度播放”,再配合 scroll(),就能让一个元素的宽度从 0% 逐渐变成 100%。

最小做法是:给页面或内容区制造真实的滚动轴,让进度条绑定 animation-timeline: scroll(),然后用关键帧改变它的宽度。若目标环境不支持滚动驱动动画,就保留一个静态的基础样式。

先把目标拆成四个部分

这类需求最容易混淆的是“动画”和“时间线”。普通 CSS 动画默认使用文档时间线,页面加载后经过多少时间,动画就推进多少;animation-timeline 则允许把推进来源换成滚动进度或元素可见度。

本文只做阅读进度条:滚动容器提供进度,scroll() 生成匿名滚动进度时间线,@keyframes 描述宽度变化,进度条负责显示结果。view() 会在兼容边界一节对比,但不把它混入主实现。

部分职责排查重点
滚动容器产生可计算的滚动距离是否真的有溢出和滚动条
scroll()选择滚动来源和方向scroller、axis 是否选对
@keyframes把时间线进度映射成样式关键帧是否改变了目标属性
进度条把 0% 到 100% 变成可见宽度定位和尺寸是否不会遮住内容

用最小结构把滚动进度接到进度条

先看一个不依赖脚本的最小版本。示例让整个文档作为滚动来源,进度条固定在页面顶部;动画本身只负责把伪元素的 transform 从 0 缩放到 1。




一篇需要滚动阅读的文章

这里放置正文内容,内容高度应当超过视口。

实际项目可以继续放置段落、代码和图片。

/* 进度条固定在顶部,但不参与鼠标命中 */
.reading-progress {
  position: fixed;
  inset: 0 0 auto;
  height: 4px;
  background: #1b75d0;
  transform-origin: left center;
  transform: scaleX(0);
  z-index: 10;
  pointer-events: none;
}

/* 用关键帧把滚动时间线映射成从 0 到 1 的横向缩放 */
@keyframes reading-progress-width {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

/* scroll() 默认寻找最近的滚动祖先;页面滚动时也可显式使用 root */
.reading-progress {
  animation: reading-progress-width linear both;
  animation-timeline: scroll(root block);
}

这里的 linear 只是让关键帧按时间线线性推进,真正改变动画进度的是最后一行 animation-timeline。不要只写 animation 而漏掉时间线,否则进度条会按默认文档时间线播放。

滚动容器通过 scroll 时间线和关键帧驱动阅读进度条的静态结构说明图
图1:结构说明图,展示滚动容器如何通过 animation-timeline: scroll() 推进进度条关键帧。

选对 scroller 和滚动轴

scroll() 可以接滚动来源和轴向两个参数。nearest 表示最近的可滚动祖先,root 表示根元素,self 表示当前元素自身;轴向可以写 block、inline、x 或 y。

如果你要做一个局部文章容器的进度条,最好把时间线绑定到这个容器,而不是让进度条误跟随整个页面。下面把滚动区域明确放在 .reader 上,并让进度条元素位于该区域内部。


局部滚动文章

把多段正文放在这里,使 reader 的内容高度超过自身高度。

进度条会随着 reader 的 block 轴滚动而变化。

/* 让 reader 成为最近的垂直滚动祖先 */
.reader {
  position: relative;
  height: 28rem;
  overflow-y: auto;
  border: 1px solid #d8e1ec;
}

/* 局部进度条固定在 reader 顶部,避免盖住正文点击区域 */
.reader-progress {
  position: sticky;
  inset-block-start: 0;
  height: 4px;
  background: #0f8b8d;
  transform: scaleX(0);
  transform-origin: left center;
  z-index: 1;
  pointer-events: none;
  animation: reader-progress linear both;
  /* reader 是最近滚动祖先,block 表示随垂直阅读方向推进 */
  animation-timeline: scroll(nearest block);
}

/* 关键帧只描述显示属性,不负责寻找滚动容器 */
@keyframes reader-progress {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

如果容器使用横向滚动,改成 scroll(nearest inline) 或 scroll(x)。如果指定的轴没有滚动条,时间线会处于不活动状态,动画看起来就像完全没有生效。因此,调试时先确认 overflow、容器尺寸和内容溢出,再检查关键帧。

补上兼容降级和动画偏好

滚动驱动动画属于浏览器平台能力,不能假定所有访问者都支持。最实用的降级方式是先给进度条一个不依赖动画的基础外观,再用 @supports 在支持时启用时间线。这样即使动画规则被忽略,页面也不会出现一条完全不可见的装饰层。

/* 基础回退:不支持滚动时间线时仍然保留清晰的顶部标记 */
.reading-progress {
  width: 100%;
  background: #d7e8f6;
}

/* 只有浏览器理解 scroll() 时才启用动态宽度映射 */
@supports (animation-timeline: scroll()) {
  .reading-progress {
    width: auto;
    animation: reading-progress-width linear both;
    animation-timeline: scroll(root block);
  }
}

/* 尊重用户的减少动态效果偏好,保留静态提示而不强制播放动画 */
@media (prefers-reduced-motion: reduce) {
  .reading-progress {
    animation: none;
    transform: scaleX(1);
  }
}

view() 与 scroll() 的关注点不同:前者根据目标元素在滚动视口中的可见程度推进,适合做卡片进入动画;后者根据滚动容器已经滚过的距离推进,更适合本文的阅读进度条。两者都依赖明确的滚动上下文,不能用一个没有溢出的普通容器代替。

scroll view 和 supports 静态回退边界的 CSS 时间线对比说明图
图2:边界说明图,对比滚动进度时间线、可见度时间线和不支持时的静态降级路径。

按固定顺序排查不生效

遇到进度条停在原地时,建议按下面的顺序检查,通常不需要立刻改成 JavaScript:

  1. 确认有滚动距离。检查目标容器是否设置了合适的高度或宽度,内容是否真的溢出;没有滚动条就没有可推进的 scroll() 时间线。
  2. 确认轴向一致。垂直阅读一般用 block 或 y,横向列表用 inline 或 x。书写模式变化时,逻辑轴比固定物理轴更稳妥。
  3. 确认关键帧改变了目标属性。如果关键帧写的是 width,目标元素不能又被固定宽度覆盖;使用 transform: scaleX() 时要保留正确的 transform-origin。
  4. 确认简写顺序。animation 简写可能重置 animation-timeline。先写动画简写,再写 animation-timeline,不要在后面再次用简写覆盖它。
  5. 确认降级规则没有隐藏结果。检查 @supports 条件、层叠顺序和 prefers-reduced-motion 是否把动态规则改成了静态状态。
/* 用支持条件做最小排查,不在不支持的环境中强行覆盖样式 */
@supports (animation-timeline: scroll()) {
  .reading-progress {
    /* 先设置动画参数,再在下一行指定时间线,避免被简写重置 */
    animation: reading-progress-width linear both;
    animation-timeline: scroll(root block);
  }
}

/* 不支持时保留静态底色,帮助用户识别页面顶部的阅读提示 */
@supports not (animation-timeline: scroll()) {
  .reading-progress {
    transform: scaleX(1);
  }
}

最后记住这张速查表

需求写法注意点
跟随页面垂直滚动scroll(root block)根页面必须有可滚动内容
跟随最近局部容器scroll(nearest block)最近祖先要有滚动条
跟随横向滚动scroll(nearest inline)确认 inline 轴确实溢出
浏览器不支持@supports not (...)保留静态颜色或静态宽度
用户减少动态效果prefers-reduced-motion: reduce关闭动画并保留可理解的状态

核心顺序可以压缩成一句话:先让容器产生真实滚动,再选择 scroll() 的来源和轴,接着用关键帧描述视觉变化,最后用 @supports 和减少动态效果媒体查询补上边界。这样一个阅读进度条就能保持纯 CSS,同时在不支持新时间线的环境中仍有可见的基础反馈。

常见追问

为什么 animation-timeline 写了却没有动画?

优先检查目标滚动轴是否存在滚动条,再检查 animation 简写是否在后面重置了时间线,以及关键帧是否真的改变了目标元素。

scroll() 和 view() 能互相替代吗?

不能完全替代。scroll() 表达滚动容器的整体进度,view() 表达某个元素进入和离开视口的可见度进度,适用的阅读模型不同。

一定要把进度条放进滚动容器吗?

不一定,但要明确时间线寻找的滚动祖先。放在局部容器内时更容易使用 scroll(nearest ...);放在页面外层时则要显式考虑根文档滚动。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
CSS anchor-size怎样让弹出层宽度跟随触发按钮CSS anchor-size怎样让弹出层宽度跟随触发按钮
上一篇
CSS anchor-size怎样让弹出层宽度跟随触发按钮
CSS timeline-scope怎样让不同滚动容器共享命名时间线
下一篇
CSS timeline-scope怎样让不同滚动容器共享命名时间线
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    888次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    888次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    971次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    957次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    782次使用