简介纯CSS3 Loading文字加载动效是一份面向前端开发者和网页设计师的动画源码示例动画核心完全由CSS3 animation驱动无需依赖JavaScript实现加载反馈适合网页加载初期使用。压缩包仅7KB共7个文件包括3个CSS样式文件、2个JS脚本文件、1个htm和1个html页面文件CSS负责定义文字拆分与滚动动画JS主要用于辅助文字拆分或后续交互扩展说明文档则介绍了动画参数的调节方法。资源提供完整可运行的HTML示例页面并展示了animation-name、animation-duration、animation-iteration-count、animation-direction等子属性的组合用法通过调整animation-timing-function和animation-delay还可快速改变滚动速度与节奏便于扩展为左右滑动、旋转等更多效果。目前已有281人学习下载适合想通过轻量案例理解CSS3动画原理、并为页面增加趣味加载效果的初中级前端人员。 上个月接了个活动页视觉稿里“加载中”三个字带了一组很有识别度的动效设计师特意强调要用品牌色渐变、逐字弹跳而且文字本身还要有呼吸感。按老思路丢一张GIF进去先不说服务质量光是体积和色值就有得扯换个活动主题就得重新导出。我直接改成纯CSS3 Loading文字加载动效——HTML就一个容器加几个span动画全部交给keyframes处理。做完之后整个资源包轻了不少动效可以不依赖图片任意改色后面几次活动我都是复制这套样式再调参数省事很多。先说结论如果你也遇到“加载中”要动得好看、还要跟着设计走的需求纯CSS3是性价比很高的方案。这篇文章我会从原理讲到实战把几个常用的文字加载动效写法都拆开附上可直接复制的代码和踩坑记录适合前端入门到进阶的开发者参考。1. 这个动效需求背后真正要解决的是什么1.1 为什么偏偏是“文字”加载动效页面加载时用户最怕的是“没反应”。转圈、进度条、骨架屏本质上都是在告诉用户“系统还活着你等一下”。但有些场景里光有图形反馈不够——比如表单提交、支付确认、文件上传这类操作有明确的状态语义用户需要知道“正在执行的是哪一步”。这时候用文字做加载提示信息传递比纯图形更直接“正在提交”“正在校验”“加载中”这几个字本身就承担了解释功能。文字加载动效的价值在于它把“状态提示”和“视觉反馈”合在了一起。我见过不少项目用一张Loading图片图片上写着“加载中”结果图片是位图换主题色还得重新作图。纯CSS3方案把文字作为真实文本存在页面上样式随意控制颜色、字体、大小、间距全部继承CSS后期维护成本几乎为零。1.2 相比GIF和JS动画库CSS3赢在哪儿先替GIF说句公道话它确实简单丢一个 进去就能转。但GIF在加载动效里有两个硬伤一个是颜色受限GIF格式只有256色品牌色里常见的渐变蓝、渐变紫导出来会有色阶断层另一个是尺寸控制为了清晰度做大了体积飙升做小了模糊而且GIF本身无法根据文字内容动态变化。JS动画库比如老牌的Animate.css、GSAP能力确实强缓动函数多、控制粒度高但一个问题是不值得。一个只在加载状态出现几秒的动效引入一个几十KB甚至上百KB的库首屏性能白被拖累。CSS3动画直接跑在浏览器的合成器线程部分变换和透明度变化不占用主线程CPU动画丝滑程度并不输给JS方案。而且纯CSS3不需要等待JavaScript解析执行页面结构出来就能动稳定性也更好。2. 核心动效原理从关键帧到逐字控制2.1 一个CSS3动画最基础的三个参数写动画其实就是在告诉浏览器一件事元素从什么状态开始经过多长时间变成什么状态然后是否重复。这就落到三个核心属性上animation-name绑定的是keyframes关键帧的名称关键帧里定义动画过程中每个阶段的样式。animation-duration一次完整动画的时长单位是秒或毫秒比如0.6s就是600毫秒。animation-iteration-count循环次数加载动效一般用infinite无限循环。我用一个生活化的类比解释关键帧就像导演给演员写好的分镜脚本0%时刻是什么表情50%时刻变成什么表情100%时刻又是什么表情duration是一场戏的播放总时长iteration-count是这场戏循环播放的次数。2.2 animation-delay如何实现“逐字错位”文字逐字弹跳的核心不是每个字自己有多花哨而是“错位”这两个字。如果四个字同时弹跳那看起来就是一个整体在动没有逐字推进的感觉。让每个字比前一个字晚一点点启动就会形成一种波浪式扫过的视觉效应。这个错位由animation-delay控制。这里是新手容易出问题的地方很多人以为设置delay就是让动画“延迟开始”那动画开始前元素是什么状态默认情况下动画开始前元素应用的是自身原本的静态样式动画结束后又回到静态样式。所以在逐字弹跳里如果你只设置了delay动画还没轮到这个字启动时它可能保持完全静止甚至和动画里的第一帧样式不一致看起来会“闪”一下。解决办法是配合animation-fill-mode: both。both的意思是动画开始前的等待阶段强制应用第一帧的样式动画结束后如果有回放或停止则保持最后一帧的样式。这样每个文字在还没轮到它动的时候就已经是动画第一帧的“待启动”状态整条时间线严丝合缝。2.3 transform和opacity是动效的最佳组合在动效设计里有个常见的“黄金法则”做位移动效优先用transform做显隐动效优先用opacity。原因在于这两个属性不会触发浏览器重新布局layout也不会触发重新绘制paint而是走合成器线程由GPU直接处理性能最好。比如弹跳效果我会用transform: scale()来做大小变化而不是去改font-size。改font-size会引发附近文本的重新排版代价昂贵scale只是视觉上的放大缩小不影响布局。同样淡入淡出用opacity不要去用display:none和visibility切换它们无法参与CSS动画的平滑过渡。这套思路不仅适用Loading文字任何动效优化的底层逻辑都是这样。3. 实操完整实现“加载中”逐字弹跳动效3.1 HTML结构一个容器加四个span先看结构我这里用“加载中”三个字加三个点意图是既有明确文字又有轻微的节奏点缀。div classloading aria-label加载中 span加/span span载/span span中/span span classdot./span span classdot./span span classdot./span /div注意容器上加了一个aria-label加载中同时给内部文字标了aria-hidden点也可以一并处理这是给屏幕阅读器看的。因为CSS动效对读屏软件来说是不可感知的如果页面里的“加载中”只有视觉呈现盲人用户会完全不知道发生了什么。这个细节在项目验收时经常被忽略但做无障碍审计时会被重点提到。3.2 CSS从静态样式到动画注入先写静态样式让文字排列好再注入动画。.loading { display: flex; justify-content: center; align-items: center; font-size: 32px; font-weight: 600; color: #4f6ef7; letter-spacing: 2px; } .loading span { display: inline-block; animation: loadingBounce 1.2s ease-in-out infinite both; } .loading .dot { animation-name: loadingDot; } .loading span:nth-child(1) { animation-delay: 0s; } .loading span:nth-child(2) { animation-delay: 0.15s; } .loading span:nth-child(3) { animation-delay: 0.3s; } .loading span:nth-child(4) { animation-delay: 0.45s; } .loading span:nth-child(5) { animation-delay: 0.6s; } .loading span:nth-child(6) { animation-delay: 0.75s; }这里有个实用提醒animation-delay的步长要根据总时长来推算。比如总时长1.2秒想让6个字均匀错开那每个字之间的间隔就是1.2s / 6 0.2s。我写0.15s是为了让波浪更密集一点看起来节奏是错落有致还是前后拥挤完全靠这个数字微调。用flex布局后span默认是行内元素display:inline-block是必须的否则transform在部分浏览器上不生效。然后是核心的关键帧keyframes loadingBounce { 0%, 60%, 100% { transform: scale(1); opacity: 0.4; } 30% { transform: scale(1.3); opacity: 1; } } keyframes loadingDot { 0%, 60%, 100% { transform: translateY(0); opacity: 0.3; } 30% { transform: translateY(-8px); opacity: 1; } }我把三个字设计成“放大提亮”三个点设计成“上浮提亮”。文字和点用不同的关键帧是为了避免视觉上全部一模一样那样容易显得刻板。0%, 60%, 100%相同的关键帧位置意味着一个周期里元素有很长一段是静止的只有中间一段发生动作弹跳的“停顿感”就出来了。这也是加载动效常用的节奏控制动一下、停一会儿、再动一下比一直高频抖动更有呼吸感。3.3 变体一渐隐渐显的“呼吸”效果弹跳动效偏活泼适合年轻化的产品。如果做后台管理系统的加载态更适合内敛一点的“呼吸”效果文字整体柔和地变淡变亮像呼吸一样不打扰用户。.loading { display: flex; justify-content: center; align-items: center; font-size: 28px; color: #5a6d7e; } .loading span { display: inline-block; animation: loadingFade 2s ease-in-out infinite both; } keyframes loadingFade { 0%, 100% { opacity: 0.3; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-4px); } }这个效果的要点是时长拉长ease-in-out缓动配上2秒周期文字在底部和顶部之间平滑过渡视觉上非常安静。实际项目中我通常把这种动效用在“数据加载较慢但不想让用户焦虑”的场景比如报表页等待接口返回。3.4 变体二底部水波纹效果还有一种常见玩法是让文字“坐”在一排水波纹上非常适合“进度刷新”类场景。水波纹本身是几个圆弧的缩放和位移。.loading { display: flex; flex-direction: column; align-items: center; font-size: 24px; color: #333; } .wave { margin-top: 12px; display: flex; gap: 4px; } .wave i { width: 6px; height: 6px; background: #4f6ef7; border-radius: 50%; animation: waveMove 1s ease-in-out infinite both; } .wave i:nth-child(1) { animation-delay: 0s; } .wave i:nth-child(2) { animation-delay: 0.1s; } .wave i:nth-child(3) { animation-delay: 0.2s; } .wave i:nth-child(4) { animation-delay: 0.3s; } .wave i:nth-child(5) { animation-delay: 0.4s; } keyframes waveMove { 0%, 100% { transform: translateY(0); opacity: 0.4; } 50% { transform: translateY(-10px); opacity: 1; } }如果想把水波纹做得更细腻可以再叠加一个scale变化让圆点上升时缩小下落时变大模拟水波的挤压感。核心还是同一套“nth-child animation-delay”的错位逻辑你可以在这个基础上自由改颜色、数量、幅度。4. 常见问题与排查技巧实录4.1 动画不生效百分之八十是这几种原因我把平时遇到的“动画没反应”的排查顺序列成了一张表现象可能原因解决办法动画完全不出现元素有display:none或父级隐藏检查元素是否实际在渲染树中只有部分文字动没有写display:inline-block给每个动画目标加display:inline-block动了一下就停了忘记写animation-iteration-count: infinite明确设为无限循环文字位置抖动动画中transform和top/left混用统一用transform做位移动画延迟阶段闪烁没设置animation-fill-mode: both加上both让等待期应用第一帧样式低版本浏览器不运行缺少-webkit-前缀补全-webkit-animation等前缀实际开发里我踩得最多的是第二种。很多新手会直接把动画设置在span上但span默认是行内元素transform在部分浏览器上不生效动画自然纹丝不动。加上display:inline-block或者display:block就能解决。4.2 动画运行久了会“卡顿”“掉帧”是怎么回事CSS3动画看起来很简单但性能问题一点都不简单。最容易犯的错是动画里同时改了margin、padding、width这些布局属性这些属性一旦变化浏览器就得重新计算页面布局。如果是复杂页面布局一旦频繁重算掉帧肉眼可见。性能优化的原则很简单动画只使用transform和opacity。如果需要渐变色变化优先考虑用伪元素叠加一个透明度的变化而不是直接给背景色加过渡。给常驻的动效元素加一句will-change: transform;提前告知浏览器哪些属性会变让它做优化准备。但要注意别滥用will-change使用过多反而会占用大量内存。如果页面同时有多个Loading动效尽量错开它们的动画周期避免同时到达最复杂的帧。我碰到过一个比较极端的案例页面上一共挂了8个带动画的模块每个动画里都用了filter: blur()做模糊效果结果低端手机上滚动页面像幻灯片一样。后来把模糊效果改成用半透明背景模拟性能立刻恢复。加载动效本身是“锦上添花”千万别让它成为性能瓶颈。4.3 用户偏好问题动效可以关掉吗最后提一个很容易被忽略的点系统层面有“减弱动态效果”的偏好设置很多没有意识到这个选项的用户也可能开启它。CSS里有一个媒体查询专门处理这种情况。media (prefers-reduced-motion: reduce) { .loading span { animation: none; } .loading span { opacity: 1; } }这样处理之后对于明确表示“我不喜欢动画”的用户页面上只显示静态文字不会因为强制动画造成晕眩等不适。这个细节在B端产品里尤其重要因为后台管理员可能一天要用十几个小时闪烁的动画长时间挂着确实影响体验。4.4 更好的做法把Loading做成可复用组件写到这里我偏向于建议你把做好的动效封装成一个组件而不是每个页面都复制一份HTML和CSS。封装时需要注意两点文字内容要能配置这样“提交中”“保存中”“加载中”都能共用一套动画文字颜色和字号也要暴露成变量方便不同的使用场景做样式覆盖。.loading { --loading-font-size: 32px; --loading-color: #4f6ef7; --loading-delay-step: 0.15s; font-size: var(--loading-font-size); } .loading span { animation-delay: calc(var(--loading-delay-step) * var(--i, 0)); }这里我用了一个--i自定义属性配合nth-child单独设置比如.loading span:nth-child(1) { --i: 0; }然后延迟时间就可以通过calc()计算出来。改动一个CSS变量就能调整整个动画的节奏比逐字改animation-delay灵活很多。这个思路在你接手别人的项目、需要快速配出不同Loading风格时特别实用。最后再分享一点我的体会做动效不只是“让页面更好看”它其实是在替产品说一句话“别走马上就好。”纯CSS3方案之所以值得掌握是因为它在性能、可维护性、可访问性之间拿到了一个平衡点。我后来做活动页设计稿里的各种Loading场景基本都能用这套思路快速搭出来改个延迟时间、换一组关键帧又是一个全新的质感。如果你接下来要自己动手做我建议你从今天的第一个弹跳案例开始先把“nth-child animation-delay fill-mode: both”这套组合吃透再去试着给每个文字增加不同的transform做出属于自己的文字Loading效果。动效这个东西看十遍不如亲手调一遍参数。本文还有配套的精品资源点击获取