Skip to content

空间转换与动画(二) ​

本页对应 空间转换与动画,共 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 复合属性:一张表记住“谁必须、谁可选” ​

为什么需要:动画属性很多,分开写清楚但代码长;复合写法能一行写完,适合真实项目。

怎么想:先记必须项,再记常用项。笔记提示:动画名称和动画时长必须赋值,其余有默认值。

怎么做:复合属性表如下。

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;复合写法中没写的属性用默认值,不要硬塞空格占位。

课件图示 ​

课件第15页:l 过渡:实现两个状态间的变化过程 l 动画:实现多个状态间的变化过程,动画过程

课件第17页:提示: l 动画名称和动画时长必须赋值 l 取值不分先后顺序 l 如果有两个时间

课件第18页:动画 - animation 属性 作用 取值 animation-name 动

课件第19页:案例 走马灯效果 l 列表添加动画效果 l 鼠标移入区域,列表动画暂停

课件第20页:案例 – 走马灯效果 l 无缝动画原理:复制开头图片到结尾位置(图片累加宽度 =

课件第21页:动画 – 逐帧动画 属性 作用 取值 animation-timing-func

课件第23页:动画 – 多组动画 animation: run 1s steps(12) in

代码示例 ​

示例一:走马灯(无缝循环 + 悬停暂停) ​

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)。

常见错误 ​

  1. 动画完全不生效 现象:页面元素静止不动,控制台无报错。 原因:@keyframes 名与 animation-name 大小写/拼写不一致;或只写了 animation: 2s; 漏掉名称;或给 <span> 等行内元素加 transform 位移。 修法:名称逐字对照(建议复制粘贴);名称和时长必须成对出现;行内元素先 display: block/inline-block 或改用 div。

  2. 走马灯循环到末尾“抽一下/闪一下” 现象:最后一张图刚露头就瞬间跳回第一张,视觉上断裂。 原因:位移距离只够露出 7 张里的前 4 张,一轮结束时最后一帧与第一帧画面不连续,没有做首尾衔接。 修法:把开头的若干张图复制到末尾当“替身”,容器宽度按“真实张数 + 替身张数”重算,位移距离改为“真实张数 × 单张宽度”,让替身顶上去的瞬间正好切回真开头。

  3. 精灵动画变成“连续滑动”而不是一格一格 现象:背景图平滑地往左滑,人物糊成一片。 原因:速度曲线用了默认值或 linear,浏览器在关键帧之间自动补帧。 修法:改成 steps(N),N 等于精灵小图个数(如 12 格就写 steps(12)),并保证位移距离等于整张精灵图宽度,否则每帧对不齐格子。

  4. 两个时间值写反,动画“刚出现就结束” 现象:设了 1s 时长 + 0.4s 延迟,结果动画只跑 0.4s,或者延迟变成了 1s。 原因:复合属性里两个时间值的顺序是“时长在前、延迟在后”,写反后浏览器按位置解析。 修法:牢记“先时长后延迟”,多组云朵错峰时统一写成 animation: cloud 1s infinite alternate linear 0.4s; 这种形式,别凭记忆随手写。

  5. animation-play-state: paused 写了没反应 现象:hover 时动画照跑。 原因:一是把 play-state 塞进了 animation 简写里(简写不含它,会被重置回 running);二是 :hover 挂在了错误的元素上(挂在被动画的 ul 上,而鼠标其实在父容器里)。 修法:play-state 单独成行声明;:hover 写在父容器上,用后代选择器选中运动元素,如 .box:hover ul { animation-play-state: paused; }。

  6. 想停在最后一帧却停不下来 现象:加了 animation-fill-mode: forwards 依旧弹回起点。 原因:同时写了 infinite,动画永远没有“结束”这一刻,forwards 无处生效。 修法:单次播放场景去掉 infinite,forwards 才有意义;需要循环的动画就别指望定格。

  7. 整页背景 cover 失效,只看到一小块或平铺 现象:大背景图不铺满视口。 原因:html、body 默认高度为 0,百分比高度无处参照,background-size: cover 按错误尺寸计算。 修法:先给 html, body { height: 100%; },再在 body 上写背景。

练习 ​

  1. 正反往复 + 悬停暂停:一个方块在 2s 内从左侧移到右侧,来回往复、无限循环,鼠标移入时暂停、移出继续。要求只用一条 animation 简写完成,play-state 单独声明。写完把鼠标反复快速进出,观察是否有“卡在中间”的错觉,并解释原因。

  2. 改错题:下面这段走马灯“能转但末尾会闪”:

    css
    .box ul { display: flex; animation: move 6s infinite linear; }
    @keyframes move { 0% { transform: translate(0); } 100% { transform: translate(-1920px); } }

    结构里只有 7 张图。请指出闪的原因,并给出修改后的结构改动 + 宽度数值 + 位移数值(单张宽 480px)。

  3. 精灵图改造:给你一张 1680×140 的精灵图,横向 12 帧。先故意用 linear 做一版,再改成 steps(12) 做一版,各截一张图对比。回答:如果错写成 steps(6) 会看到什么?如果把 steps 写成 step-end 呢?

  4. 云朵错峰:三朵云用同一组 @keyframes 做 20px 的左右漂浮,要求彼此节奏错开。写出三种实现思路(不同延迟 / 不同时长 / 不同 alternate 起点),并说明哪种最省代码、哪种最自然。

  5. 简写改造:把下面这组拆分写法合并成一条 animation,并说出你跳过了哪几个属性、为什么可以跳过:

    css
    animation-name: text;
    animation-duration: 1s;
    animation-timing-function: ease;
    animation-iteration-count: 3;
    animation-direction: alternate;

原视频对照 ​

#视频时长
1属性-播放次数04:33
2属性-播放方向alternate05:34
3属性-play-state暂停动画03:41
4属性-复合写法06:48
5案例走马灯-1-搭建06:28
6案例走马灯-2-初始动画07:29
7案例走马灯-3-完成07:13
8案例精灵-110:11

小结 ​

  1. animation 里只有“名称 + 时长”是硬性要求,其余全有默认值,写不出来就先写这两个,能跑起来再逐项加。
  2. 复合写法按 VS Code 提示的顺序依次填,中间不要的属性直接跳过,靠“省略”而不是靠“空格占位”。
  3. animation-play-state 是简写装不下的属性,必须单独一行;暂停几乎永远是配合 :hover 用的。
  4. 无缝滚动(走马灯)的本质是“障眼法”:用替身顶住露出窗口的瞬间,位移距离 = 真实内容宽度,不是“看起来差不多”的估数值。
  5. 逐帧动画和补间动画只差一个速度曲线:steps(N) 决定“跳几格”,位移总量决定“一共跨多远”,两者必须与小图个数、精灵图总宽严格对应。
  6. 大背景铺满的前提是高度链完整——html/body 高度不给,cover 就没有计算依据。
  7. 动画出问题先分清是“没生效”(名称、拼写、元素类型)还是“生效了但不好看”(距离、曲线、衔接),两类排查路径完全不同。
  8. 调试动画的通用手法:先把 overflow: hidden 关掉、把时长调到 10s,慢速看清每一帧到底发生了什么,再回头改数值。