主题
空间转换与动画(二)
本页对应 空间转换与动画,共 8 段视频,约 51 分钟。
学习目标
- 能使用
animation-iteration-count设置动画播放次数,并用infinite实现无限循环播放。 - 能使用
animation-direction: alternate实现动画往返播放,并说明其与reverse反向播放的区别。 - 能使用
animation-play-state: paused配合:hover实现鼠标移入暂停动画。 - 能按顺序编写
animation复合属性,正确省略无需设置的属性,并说明play-state需单独设置。 - 能独立完成走马灯案例的布局与动画,通过补充“假首图”和调整位移距离解决首尾衔接跳闪问题。
- 能使用
steps()逐帧函数完成精灵图动画,使背景或图片按指定帧数逐格切换。
知识点
过渡与动画:先分清“两个状态”和“多个状态”
为什么需要:过渡只能让元素在两个状态之间变化,比如从 A 到 B;而动画可以把多个关键状态串起来,并且能控制重复播放、最终停在哪儿、是否暂停。
怎么想:把动画理解成“关键帧 + 播放规则”。关键帧描述每个阶段长什么样,播放规则描述播几次、往哪播、快慢如何。
怎么做:先定义 @keyframes,再用 animation 把动画挂到元素上。笔记给了两种定义方式:
css
/* 方式一 */
@keyframes 动画名称 {
from {}
to {}
}
/* 方式二 */
@keyframes 动画名称 {
0% {}
10% {}
......
100% {}
}使用动画时,动画名称和动画时长必须赋值:
css
animation: 动画名称 动画花费时长;易错点:animation 里取值不分先后顺序,但如果有两个时间值,第一个是动画时长,第二个是延迟时间。动画名称和时长不能省。
animation 复合属性:一张表记住“谁必须、谁可选”
为什么需要:动画属性很多,分开写清楚但代码长;复合写法能一行写完,适合真实项目。
怎么想:先记必须项,再记常用项。笔记提示:动画名称和动画时长必须赋值,其余有默认值。
怎么做:复合属性表如下。

拆分写法表如下。

转写稿里重点补充了几个属性:
- 播放次数:默认 1 次;
infinite表示无限循环。可以联想“英菲尼迪”的英文infinite帮助记单词。 - 播放方向:
alternate是“反复播放”,第一次正着播,第二次反着播,来回走;reverse才是反向播放。转写稿特别提醒 PPT 里把alternate标成“反向”不够准确,实际应理解为反复。 - 暂停:
animation-play-state: paused;通常配合:hover使用,鼠标移入暂停。它不写在animation复合属性里,是单独控制的。
易错点:复合写法里没有 play-state 的位置;中间某些属性不需要时,不是随便乱序,而是按顺序写、跳过的地方用空格隔开。转写稿调试时就是按 VS Code 提示的顺序逐项填,不需要的跳过。
案例:走马灯——先让整体动起来
为什么需要:走马灯是“多个图片整体左移”的典型场景,能练会 transform: translate() 与 animation 的配合。
怎么想:不要控制每一张图片,而是把图片装进一个长盒子 ul,让 ul 整体移动;外层盒子设置 overflow: hidden,只露出显示区域。
怎么做:HTML 结构保留笔记代码:
html
<li><img src="./images/1.jpg" alt="" /></li>
<li><img src="./images/2.jpg" alt="" /></li>
<li><img src="./images/3.jpg" alt="" /></li>
<li><img src="./images/4.jpg" alt="" /></li>
<li><img src="./images/5.jpg" alt="" /></li>
<li><img src="./images/6.jpg" alt="" /></li>
<li><img src="./images/7.jpg" alt="" /></li>
<!-- 替身:填补显示区域的露白 -->
<li><img src="./images/1.jpg" alt="" /></li>
<li><img src="./images/2.jpg" alt="" /></li>
<li><img src="./images/3.jpg" alt="" /></li>CSS:
css
.box {
width: 600px;
height: 112px;
border: 5px solid #000;
margin: 100px auto;
overflow: hidden;
}
.box ul {
display: flex;
animation: move 6s infinite linear;
}
/* 定义位移动画;ul使用动画;鼠标悬停暂停动画 */
@keyframes move {
0% {
transform: translate(0);
}
100% {
transform: translate(-1400px);
}
}
.box:hover ul {
animation-play-state: paused;
}调试推导:转写稿先让 ul 左移一张图宽度,观察是否超出黑框;再推“走到第 7 张算完”其实不够。第一次动画结束时,最后几张刚露出来就立刻跳回第二次开头,视觉上会“抽一下”。原因是动画只播一轮,播完回到初始状态,用户还没看完最后几张就被切回开头。
解决思路:复制开头图片到结尾做“替身”。第一次结束时先露出假的开头图片,紧接着切回真正的开头,视觉上就接上了。对应笔记原理:复制开头图片到结尾位置,图片累加宽度等于区域宽度。转写稿用 480 宽图片推导时,补充 3 张替身后总宽变 10 张,动画要移动 7 张图片宽度,才能把 7 张真图全部移出去、露出替身。
易错点:动画加错层级——应加在 ul 或图片容器上,不要加错到外层盒子;移动距离要按“真图数量 × 单图宽度”算,不要凭感觉写。

精灵动画:用 steps(N) 做逐帧播放
为什么需要:精灵图把多个动作画在一张图上,逐帧播放能做出人物跑动等效果。
怎么想:显示区域盒子尺寸等于一张精灵小图尺寸;背景图向左移动,移动距离等于精灵图总宽度;用 steps(N) 让背景图一格一格跳,N 等于小图个数。
怎么做:核心示意如图。

css
div {
width: 140px;
height: 140px;
border: 1px solid #000;
background-image: url(./images/bg.png);
animation: run 1s steps(12) infinite;
}
@keyframes run {
from {
background-position: 0 0;
}
to {
background-position: -1680px 0;
}
}调试推导:转写稿先不用 steps(),发现背景图连续滑动,中间会补帧,看起来是“滑过去”而不是“一格一格跳”;加上 steps(12) 后,12 个小图逐格切换。1680 ÷ 12 = 140,正好一张小图宽 140px。
易错点:steps(N) 的 N 要等于精灵小图个数;动画要加在显示背景图的元素上,别加错到父盒子;移动距离是精灵图总宽度,不是显示区域宽度。
多组动画:一个元素同时做多件事
为什么需要:有时一个元素既要位移又要变色,可以写多组动画。
怎么做:
css
animation:
动画一,
动画二,
... ...
;易错点:多组动画用逗号分隔;每组动画的名称和时长都要写清楚,别把两组参数混在一起。
案例目标与页面结构

这个综合案例把背景图、绝对定位和关键帧动画放在一起:底层是铺满页面的大背景,中间放三朵云做轻微漂浮,最后让文字图片在屏幕中央做一次“默认→小→大→小→默认”的强调动画。
为什么需要:单个属性会写还不够,真实页面要先搭结构、再定位置、最后加动画。
怎么想:先保证背景能铺满,再让云错落分布,最后处理文字居中与缩放。
怎么做:按下面三段代码依次完成。
易错点:不要一上来就写动画,先确认背景高度、定位参照和居中方式,否则动画一动位置就偏。
背景铺满:先给 html 和 body 高度
css
/* 大背景 */
/* 默认状态HTML和body的高度是0,所以导致cover缩放背景图不成功 */
html {
height: 100%;
}
body {
height: 100%;
background: url(../images/f1_1.jpg) no-repeat center 0 / cover;
/* background-size: cover; */
}为什么需要:cover 要让背景图按容器尺寸缩放并覆盖容器,如果容器高度是 0,背景图就没有可铺满的空间。
怎么想:转写稿里强调过,默认状态下 html 和 body 的高度是 0,所以只写 background-size: cover 不一定成功;先把高度链路打通。
怎么做:给 html 和 body 都设 height: 100%,再用 background 简写设置图片、不重复、水平居中且垂直从 0 开始、cover 覆盖。
易错点:只给 body 设高度而漏掉 html,或者把 center 0 / cover 的位置和尺寸写乱;调试时先临时加背景色,确认容器确实有高度。
云彩位置和循环动画
html
<!-- 云 -->
<div class="cloud">
<img src="./images/yun1.png" alt="云彩图片1">
<img src="./images/yun2.png" alt="云彩图片2">
<img src="./images/yun3.png" alt="云彩图片3">
</div>css
/* 云 */
.cloud img {
position: absolute;
left: 50%;
}
.cloud img:nth-child(1) {
margin-left: -250px;
top: 20px;
animation: cloud 1s infinite alternate linear;
}
.cloud img:nth-child(2) {
margin-left: 400px;
top: 100px;
animation: cloud 1s infinite alternate linear 0.4s;
}
.cloud img:nth-child(3) {
margin-left: -550px;
top: 200px;
animation: cloud 1s infinite alternate linear 0.6s;
}
@keyframes cloud {
100% {
transform: translate(20px);
}
}为什么需要:三朵云不能叠在一起,也不能完全同步飘动,否则画面很死。
怎么想:先用 position: absolute 把云从普通文档流中拿出来,再统一 left: 50% 到页面中线附近,然后用不同的 margin-left 和 top 错开位置。动画只做很小的水平位移,所以用 translate(20px)。
怎么做:三张图分别设置不同的 margin-left、top;动画统一用 cloud 1s infinite alternate linear,第二、第三张分别加 0.4s、0.6s 延迟,让它们不同步。这里转写稿里提到的“ineration-count”应写作 iteration-count,“infinite”表示无限循环,“alimate”应写作 alternate,表示反复播放。
易错点:left: 50% 后负的 margin-left 是往左错开,正值往右;动画名称、关键帧名要一致;alternate 是来回播放,不是单纯“反向”,转写稿里也补充过真正反向是 reverse,但本案例云彩用的是 alternate。
文字动画
html
<!-- 文字 -->
<div class="text">
<img src="./images/font1.png" alt="文字图片">
</div>css
/* 文字 */
.text img {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
animation: text 1s;
}
/* 默认 → 小 → 大 → 小 → 默认 */
@keyframes text {
0% {
transform: translate(-50%, -50%) scale(1);
}
20% {
transform: translate(-50%, -50%) scale(0.1);
}
40% {
transform: translate(-50%, -50%) scale(1.4);
}
70% {
transform: translate(-50%, -50%) scale(0.8);
}
100% {
transform: translate(-50%, -50%) scale(1);
}
}为什么需要:文字图片需要真正居中,同时做出一次强调动画,让用户视线落到主视觉上。
怎么想:绝对定位 left: 50%; top: 50% 只是把图片左上角放到中心,必须再用 translate(-50%, -50%) 把自身宽高的一半拉回去。缩放动画的每一帧都要保留这个 translate,否则一缩放就偏。
怎么做:在关键帧里按 0%、20%、40%、70%、100% 分别写 translate(-50%, -50%) scale(...),形成默认→小→大→小→默认。
易错点:只写 scale() 会覆盖原来的 translate,导致文字不再居中;transform 中多个函数要写在同一个属性里;动画默认只播放一次,本案例文字只做一次强调,所以 animation: text 1s; 足够。
动画属性补充与调试顺序
转写稿里补充了动画属性:默认播放一次;iteration-count: infinite 可无限循环;alternate 可反复播放;animation-play-state: paused 常配合 :hover 做鼠标移入暂停;复合写法按 animation 的顺序写,缺省项可跳过,但 play-state 一般不写在复合属性里。这里的同音字要纠正:dration 是 duration,tamps 是 steps,逐帧动画不要写成“古帧”,补帧也不要写成“补真”。
为什么需要:理解这些属性,才能看懂云动画为什么能一直飘、为什么能来回飘。
怎么想:先写结构,再写定位,再写关键帧,最后把动画属性挂上去;动画不动时先查名称和关键帧,再查属性顺序。
怎么做:本案例云用 infinite alternate,文字用一次播放;调试时先注释动画看静态位置,确认背景、云、文字都对了再开动画。
易错点:duration 和 direction 别混;alternate 不是 reverse;复合写法中没写的属性用默认值,不要硬塞空格占位。
课件图示







代码示例
示例一:走马灯(无缝循环 + 悬停暂停)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>走马灯</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
li { list-style: none; }
/* 显示区域:只露出 3 张图(480 × 3 = 1440) */
.box {
width: 1440px;
height: 270px;
border: 5px solid #000;
margin: 100px auto;
overflow: hidden;
}
/* 长盒子:容纳全部图片,动画加在它身上,而不是每张图上 */
.box ul {
display: flex;
width: 4800px; /* 10 张 × 480 */
animation: move 6s infinite linear;
}
.box ul img {
display: block; /* 去掉 inline 图片底部的基线空隙 */
width: 480px;
height: 270px;
}
/* 位移:真图 7 张全部移出去 = 7 × 480 = 3360 */
@keyframes move {
0% { transform: translate(0); }
100% { transform: translate(-3360px); }
}
/* 鼠标悬停暂停动画 */
.box:hover ul {
animation-play-state: paused;
}
</style>
</head>
<body>
<div class="box">
<ul>
<li><img src="./images/1.jpg" alt=""></li>
<li><img src="./images/2.jpg" alt=""></li>
<li><img src="./images/3.jpg" alt=""></li>
<li><img src="./images/4.jpg" alt=""></li>
<li><img src="./images/5.jpg" alt=""></li>
<li><img src="./images/6.jpg" alt=""></li>
<li><img src="./images/7.jpg" alt=""></li>
<!-- 替身:填补显示区域的露白,让动画首尾无缝衔接 -->
<li><img src="./images/1.jpg" alt=""></li>
<li><img src="./images/2.jpg" alt=""></li>
<li><img src="./images/3.jpg" alt=""></li>
</ul>
</div>
</body>
</html>要点解释
.box { overflow: hidden; }:父盒子只当“取景框”,超出部分裁掉,屏幕上只露 3 张图。- 动画加在
ul上而不是li上:让所有小图“整体移动”,小图被大盒子带着走。 - 位移终点
-3360px= 7 张真图 × 480,不是 3 张 × 480 = 1440。必须把 7 张真图全部移出去,末尾那 3 张“替身”才能正好补上显示区,形成无缝。 - 替身图(复制开头的 1、2、3)是无缝动画的核心原理:动画最后一帧露出的其实是“假 1、假 2、假 3”,下一轮动画重新开始时正好接上真 1,视觉上就看不出跳变。
易错点
- 忘记复制替身 → 动画最后一帧会“抽一下”,画面猛地跳回第一张。
- 位移距离算错(写成
-1440px)→ 替身还没露出来就结束了,同样会抽。 - 忘记
overflow: hidden→ 所有图片全部暴露在页面上。 animation-play-state不能写进animation复合属性里,必须单独写一行。- 图片没设
display: block时,底部会多出几像素基线空隙,ul高度会不准。
示例二:精灵动画(逐帧 + steps)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>精灵动画</title>
<style>
/* 显示区域:尺寸 = 一张精灵小图的尺寸 */
div {
width: 140px;
height: 140px;
border: 1px solid #000;
background-image: url(./images/bg.png);
animation: run 1s steps(12) infinite;
}
/* 移动背景图,移动距离 = 整张精灵图宽度 12 × 140 = 1680 */
@keyframes run {
from { background-position: 0 0; }
to { background-position: -1680px 0; }
}
</style>
</head>
<body>
<div></div>
</body>
</html>要点解释
- 盒子尺寸
140 × 140必须和一张小精灵图一致,否则会把相邻格子的画面“切”进来。 - 动画移动的是
background-position,不是transform;因此精灵图必须用background-image引入,不能用<img>。 steps(12):告诉浏览器“不要给我补帧,我让你跳几下你就跳几下”,正好对应 12 个分解动作,所以看起来一格一格地跑。infinite:无限循环,人物就一直跑。
易错点
- 忘写
steps()→ 背景会连续匀速滑动,出现“半张图”的残影。 steps(N)里的 N 必须等于精灵小图个数,写错就会错位。- 位移距离写成
-140px(只移动一格)→ 只会播一帧。 - 速度曲线用
linear之外的默认值 + 没写steps()时,动画会有“快慢快慢”的加減速感。
示例三:多关键帧 + 复合属性 + alternate 反复
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>云彩与文字动画</title>
<style>
* { margin: 0; padding: 0; }
/* 默认 html 和 body 高度是 0,cover 缩放背景图会失效 */
html { height: 100%; }
body {
height: 100%;
background: url(./images/f1_1.jpg) no-repeat center 0 / cover;
background-color: #8fd0ff; /* 背景图缺失时的兜底色 */
}
/* 云 */
.cloud img {
position: absolute;
left: 50%;
width: 180px;
height: 90px;
}
.cloud img:nth-child(1) {
margin-left: -250px;
top: 20px;
animation: cloud 1s infinite alternate linear;
}
.cloud img:nth-child(2) {
margin-left: 400px;
top: 100px;
animation: cloud 1s infinite alternate linear 0.4s;
}
.cloud img:nth-child(3) {
margin-left: -550px;
top: 200px;
animation: cloud 1s infinite alternate linear 0.6s;
}
/* 只写 100%,等价于 from 保持原状 */
@keyframes cloud {
100% { transform: translate(20px); }
}
/* 文字 */
.text img {
position: absolute;
left: 50%;
top: 50%;
width: 400px;
transform: translate(-50%, -50%);
animation: text 1s;
}
/* 默认 → 小 → 大 → 小 → 默认 */
@keyframes text {
0% { transform: translate(-50%, -50%) scale(1); }
20% { transform: translate(-50%, -50%) scale(0.1); }
40% { transform: translate(-50%, -50%) scale(1.4); }
70% { transform: translate(-50%, -50%) scale(0.8); }
100% { transform: translate(-50%, -50%) scale(1); }
}
</style>
</head>
<body>
<!-- 云 -->
<div class="cloud">
<img src="./images/yun1.png" alt="">
<img src="./images/yun2.png" alt="">
<img src="./images/yun3.png" alt="">
</div>
<!-- 文字 -->
<div class="text">
<img src="./images/font1.png" alt="">
</div>
</body>
</html>要点解释
animation: cloud 1s infinite alternate linear 0.4s:取值不分先后顺序,但出现两个时间值时,第一个是动画时长,第二个是延迟时间。三朵云分别延迟 0s / 0.4s / 0.6s,就错开飘动了。alternate是“反复播放”(去 → 回 → 去 → 回),所以只要写100%一个关键帧就够;如果只写from/to或者只写100%,0%会默认取元素原本的样式。- 文字动画用百分比多关键帧,实现“默认 → 小 → 大 → 小 → 默认”的连续变化。
html { height: 100%; }是为了让body的background-size: cover正常铺满,否则默认高度是 0,背景图缩放失败。
易错点
- 文字动画的每一帧都必须带上
translate(-50%, -50%),只要漏写一帧,元素就瞬间丢失居中,飞到右下角。 animation复合属性里没有animation-play-state,暂停/恢复只能单独写:.box:hover { animation-play-state: paused; }。- 复合写法中间某项不需要设置时,直接跳过、按顺序往下写即可,但不能打乱顺序。
- 播放次数默认是 1 次,写
infinite才无限循环;alternate是“反复来回”,真正的反向是reverse(转写稿补充,了解即可)。 - 元素同时被两组动画控制同一个
transform时,后面的会覆盖前面的,做多组动画要让两组动画操作不同属性(如一组改transform、一组改margin-top)。
常见错误
动画完全不生效 现象:页面元素静止不动,控制台无报错。 原因:
@keyframes名与animation-name大小写/拼写不一致;或只写了animation: 2s;漏掉名称;或给<span>等行内元素加transform位移。 修法:名称逐字对照(建议复制粘贴);名称和时长必须成对出现;行内元素先display: block/inline-block或改用div。走马灯循环到末尾“抽一下/闪一下” 现象:最后一张图刚露头就瞬间跳回第一张,视觉上断裂。 原因:位移距离只够露出 7 张里的前 4 张,一轮结束时最后一帧与第一帧画面不连续,没有做首尾衔接。 修法:把开头的若干张图复制到末尾当“替身”,容器宽度按“真实张数 + 替身张数”重算,位移距离改为“真实张数 × 单张宽度”,让替身顶上去的瞬间正好切回真开头。
精灵动画变成“连续滑动”而不是一格一格 现象:背景图平滑地往左滑,人物糊成一片。 原因:速度曲线用了默认值或
linear,浏览器在关键帧之间自动补帧。 修法:改成steps(N),N等于精灵小图个数(如 12 格就写steps(12)),并保证位移距离等于整张精灵图宽度,否则每帧对不齐格子。两个时间值写反,动画“刚出现就结束” 现象:设了 1s 时长 + 0.4s 延迟,结果动画只跑 0.4s,或者延迟变成了 1s。 原因:复合属性里两个时间值的顺序是“时长在前、延迟在后”,写反后浏览器按位置解析。 修法:牢记“先时长后延迟”,多组云朵错峰时统一写成
animation: cloud 1s infinite alternate linear 0.4s;这种形式,别凭记忆随手写。animation-play-state: paused写了没反应 现象:hover时动画照跑。 原因:一是把play-state塞进了animation简写里(简写不含它,会被重置回running);二是:hover挂在了错误的元素上(挂在被动画的ul上,而鼠标其实在父容器里)。 修法:play-state单独成行声明;:hover写在父容器上,用后代选择器选中运动元素,如.box:hover ul { animation-play-state: paused; }。想停在最后一帧却停不下来 现象:加了
animation-fill-mode: forwards依旧弹回起点。 原因:同时写了infinite,动画永远没有“结束”这一刻,forwards无处生效。 修法:单次播放场景去掉infinite,forwards才有意义;需要循环的动画就别指望定格。整页背景
cover失效,只看到一小块或平铺 现象:大背景图不铺满视口。 原因:html、body默认高度为 0,百分比高度无处参照,background-size: cover按错误尺寸计算。 修法:先给html, body { height: 100%; },再在body上写背景。
练习
正反往复 + 悬停暂停:一个方块在 2s 内从左侧移到右侧,来回往复、无限循环,鼠标移入时暂停、移出继续。要求只用一条
animation简写完成,play-state单独声明。写完把鼠标反复快速进出,观察是否有“卡在中间”的错觉,并解释原因。改错题:下面这段走马灯“能转但末尾会闪”:
css.box ul { display: flex; animation: move 6s infinite linear; } @keyframes move { 0% { transform: translate(0); } 100% { transform: translate(-1920px); } }结构里只有 7 张图。请指出闪的原因,并给出修改后的结构改动 + 宽度数值 + 位移数值(单张宽 480px)。
精灵图改造:给你一张 1680×140 的精灵图,横向 12 帧。先故意用
linear做一版,再改成steps(12)做一版,各截一张图对比。回答:如果错写成steps(6)会看到什么?如果把steps写成step-end呢?云朵错峰:三朵云用同一组
@keyframes做 20px 的左右漂浮,要求彼此节奏错开。写出三种实现思路(不同延迟 / 不同时长 / 不同alternate起点),并说明哪种最省代码、哪种最自然。简写改造:把下面这组拆分写法合并成一条
animation,并说出你跳过了哪几个属性、为什么可以跳过:cssanimation-name: text; animation-duration: 1s; animation-timing-function: ease; animation-iteration-count: 3; animation-direction: alternate;
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 属性-播放次数 | 04:33 |
| 2 | 属性-播放方向alternate | 05:34 |
| 3 | 属性-play-state暂停动画 | 03:41 |
| 4 | 属性-复合写法 | 06:48 |
| 5 | 案例走马灯-1-搭建 | 06:28 |
| 6 | 案例走马灯-2-初始动画 | 07:29 |
| 7 | 案例走马灯-3-完成 | 07:13 |
| 8 | 案例精灵-1 | 10:11 |
小结
animation里只有“名称 + 时长”是硬性要求,其余全有默认值,写不出来就先写这两个,能跑起来再逐项加。- 复合写法按 VS Code 提示的顺序依次填,中间不要的属性直接跳过,靠“省略”而不是靠“空格占位”。
animation-play-state是简写装不下的属性,必须单独一行;暂停几乎永远是配合:hover用的。- 无缝滚动(走马灯)的本质是“障眼法”:用替身顶住露出窗口的瞬间,位移距离 = 真实内容宽度,不是“看起来差不多”的估数值。
- 逐帧动画和补间动画只差一个速度曲线:
steps(N)决定“跳几格”,位移总量决定“一共跨多远”,两者必须与小图个数、精灵图总宽严格对应。 - 大背景铺满的前提是高度链完整——
html/body高度不给,cover就没有计算依据。 - 动画出问题先分清是“没生效”(名称、拼写、元素类型)还是“生效了但不好看”(距离、曲线、衔接),两类排查路径完全不同。
- 调试动画的通用手法:先把
overflow: hidden关掉、把时长调到 10s,慢速看清每一帧到底发生了什么,再回头改数值。