目录

  1. 引言:为什么使用 CSS 动画?
  2. 第一部分:CSS 过渡 - 基础入门
    • 什么是过渡?
    • transition 属性详解
    • 实战案例:按钮悬停效果
    • 实战案例:卡片悬停效果
  3. 第二部分:CSS 关键帧动画 - 进阶核心
    • 什么是关键帧动画?
    • @keyframes 规则
    • animation 属性详解
    • 实战案例:加载动画
    • 实战案例:文字打字机效果
    • 实战案例:无限循环的滚动背景
  4. 第三部分:高级技巧与最佳实践
    • 性能优化:transformopacity 的优势
    • 动画状态控制:animation-play-state
    • 动画事件:animationstart, animationend
    • 响应式动画与 prefers-reduced-motion
  5. 第四部分:综合案例:创建一个动态产品展示卡片
  6. 总结与资源推荐

引言:为什么使用 CSS 动画?

在 CSS3 出现之前,网页动画主要依赖于 JavaScript 或 Flash,它们通常更复杂、性能开销更大,且不易维护。

html5 css3 动画教程
(图片来源网络,侵删)

CSS 动画带来了革命性的变化:

  • 简单易用:直接在 CSS 中定义,无需编写复杂的 JavaScript 逻辑。
  • 性能卓越:现代浏览器对 CSS 动画进行了深度优化,可以利用 GPU 加速,使其运行流畅。
  • 声明式:你只需描述动画的“起始”和“结束”状态(或几个关键状态),浏览器会自动计算中间过程。
  • 节省资源:将动画逻辑从 JavaScript 中解放出来,减少了主线程的负担。

CSS 动画主要分为两大类:过渡关键帧动画


第一部分:CSS 过渡 - 基础入门

什么是过渡?

过渡是一种状态变化的动画,当元素的 CSS 属性值发生变化时(通过 hover 伪类或 JavaScript 改变样式),过渡可以让这个变化过程在一段时间内平滑地完成,而不是瞬间跳变。

transition 属性详解

transition 是一个简写属性,通常包含四个子属性:

html5 css3 动画教程
(图片来源网络,侵删)
.element {
  /* property | duration | timing-function | delay */
  transition: all 0.3s ease-in-out 0.1s;
}
  1. transition-property: 指定哪个属性需要过渡效果。

    • 可以是具体属性名,如 width, background-color
    • 使用 all(默认)表示所有可过渡的属性都会发生变化。
    • 使用 none 表示没有属性过渡。
  2. transition-duration: 指定过渡效果持续的时间。

    • 单位是秒或毫秒,5s500ms
    • 如果值为 0,则表示没有过渡效果。
  3. transition-timing-function: 指定过渡的速度曲线,即动画的节奏。

    • ease: 默认值,慢速开始,然后变快,最后慢速结束。
    • linear: 匀速运动。
    • ease-in: 慢速开始。
    • ease-out: 慢速结束。
    • ease-in-out: 慢速开始和结束。
    • cubic-bezier(): 自定义贝塞尔曲线,可以实现更复杂的动画节奏。
    • steps(): 分步执行,常用于帧动画。
  4. transition-delay: 指定过渡效果开始前的等待时间。

    html5 css3 动画教程
    (图片来源网络,侵删)

    单位同样是秒或毫秒,可以为负值,表示动画立即开始,但会从动画过程的某个时间点开始。

实战案例:按钮悬停效果

这是最经典的过渡应用。

HTML:

<button class="btn-hover">悬停我</button>

CSS:

.btn-hover {
  padding: 12px 24px;
  font-size: 16px;
  background-color: #3498db;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  /* 关键:设置默认的过渡属性 */
  transition: background-color 0.3s ease, transform 0.3s ease;
}
.btn-hover:hover {
  background-color: #2980b9;
  transform: scale(1.05); /* 轻微放大 */
}
.btn-hover:active {
  transform: scale(0.98); /* 点击时缩小 */
}

效果: 鼠标移入时,按钮背景色平滑变化,并轻微放大;鼠标移出时,效果平滑恢复,点击时也有一个反馈。


第二部分:CSS 关键帧动画 - 进阶核心

什么是关键帧动画?

关键帧动画用于实现更复杂的、不依赖于状态变化的动画,你可以定义一个动画在不同时间点的状态(关键帧),浏览器会根据这些关键帧生成完整的动画序列。

@keyframes 规则

@keyframes 用于定义动画的关键帧。

@keyframes animationName {
  0% {
    /* 动画开始时的样式 */
    transform: translateX(0);
  }
  50% {
    /* 动画进行到一半时的样式 */
    transform: translateX(100px);
  }
  100% {
    /* 动画结束时的样式 */
    transform: translateX(0);
  }
}
  • animationName: 给你的动画起一个名字。
  • 0%, 50%, 100%: 是动画的进度百分比,也叫关键帧。
  • 你也可以使用 from (等同于 0%) 和 to (等同于 100%)。

animation 属性详解

animation 是一个简写属性,用于控制关键帧动画的播放。

.element {
  /* name | duration | timing-function | delay | iteration-count | direction | fill-mode | play-state */
  animation: slideIn 2s ease-in-out 0.5s infinite alternate;
}
  1. animation-name: 指定要使用的 @keyframes 的名字。

  2. animation-duration: 指定动画完成一次循环所需的时间。

  3. animation-timing-function: 同过渡,定义动画的速度曲线。

  4. animation-delay: 指定动画开始前的等待时间。

  5. animation-iteration-count: 定义动画播放的次数。

    • infinite: 无限循环。
  6. animation-direction: 定义动画的播放方向。

    • normal: 默认,从 0% 到 100% 正常播放。
    • reverse: 从 100% 到 0% 反向播放。
    • alternate: 动画交替播放,第一次正常,第二次反向,如此反复。
    • alternate-reverse: 第一次反向,第二次正常,交替播放。
  7. animation-fill-mode: 定义动画在执行前和执行后如何应用样式。

    • none: 默认,动画执行前后不应用任何样式。
    • forwards: 动画结束后,元素会保留最后一帧(100%)的样式。
    • backwards: 动画开始前,元素会应用第一帧(0%)的样式(在 delay 期间生效)。
    • both: 同时应用 forwardsbackwards 的效果。

实战案例:加载动画

创建一个经典的旋转加载图标。

HTML:

<div class="loader"></div>

CSS:

.loader {
  width: 50px;
  height: 50px;
  border: 5px solid #f3f3f3; /* 灰色背景 */
  border-top: 5px solid #3498db; /* 蓝色顶部 */
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

效果: 一个圆形的加载图标会不停地旋转。

实战案例:文字打字机效果

模拟打字机逐字显示文字的效果。

HTML:

<p class="typewriter">Hello, CSS Animation!</p>

CSS:

.typewriter {
  overflow: hidden; /* 隐藏超出部分 */
  border-right: 2px solid orange; /* 光标效果 */
  white-space: nowrap; /* 保持文本在一行 */
  animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
}
/* 打字动画 */
@keyframes typing {
  from { width: 0 }
  to { width: 100% }
}
/* 光标闪烁动画 */
@keyframes blink-caret {
  from, to { border-color: transparent }
  50% { border-color: orange; }
}

效果: 文字会像打字一样逐个出现,光标会不断闪烁。

实战案例:无限循环的滚动背景

创建一个无缝滚动的背景图,常用于展示横幅或装饰。

HTML:

<div class="scrolling-background"></div>

CSS:

.scrolling-background {
  width: 100%;
  height: 200px;
  background-image: url('your-image.jpg');
  background-repeat: repeat-x; /* 水平平铺 */
  animation: scroll 10s linear infinite;
}
@keyframes scroll {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 100% 0; /* 移动一个完整的背景宽度 */
  }
}

效果: 背景图片会无限向左滚动。


第三部分:高级技巧与最佳实践

性能优化:transformopacity 的优势

并非所有 CSS 属性都适合做动画,改变 width, height, margin, top, left 等属性会触发浏览器的重排,非常消耗性能。

应优先使用以下属性,它们可以利用 GPU 加速,触发重绘,性能更好:

  • transform: 用于移动、缩放、旋转、倾斜。
  • opacity: 用于改变透明度。
  • filter: 用于模糊、调整亮度等。

优化前:

.box {
  width: 100px;
  height: 100px;
  background: red;
  transition: width 0.5s, height 0.5s; /* 性能较差 */
}
.box:hover {
  width: 150px;
  height: 150px;
}

优化后:

.box {
  width: 100px;
  height: 100px;
  background: red;
  transition: transform 0.5s; /* 性能极佳 */
}
.box:hover {
  transform: scale(1.5);
}

动画状态控制:animation-play-state

这个属性可以让你在动画运行时暂停或恢复它,通常与 JavaScript 配合使用。

  • running: 动画正在运行(默认)。
  • paused: 动画已暂停。

CSS:

.paused-element {
  animation: spin 2s linear infinite;
  animation-play-state: paused; /* 默认暂停 */
}

JavaScript:

const element = document.querySelector('.paused-element');
element.addEventListener('click', () => {
  // 切换播放状态
  element.style.animationPlayState = 
    element.style.animationPlayState === 'paused' ? 'running' : 'paused';
});

动画事件

JavaScript 可以监听动画的生命周期事件。

  • animationstart: 动画开始时触发。
  • animationend: 动画结束时触发。
  • animationiteration: 每次动画循环一次时触发(仅在 iteration-count 大于 1 时有效)。

JavaScript 示例:

const element = document.querySelector('.loader');
element.addEventListener('animationend', () => {
  alert('动画播放完成!');
});

响应式动画与 prefers-reduced-motion

这是一个重要的可访问性特性,有些用户(如前庭障碍患者)不希望看到剧烈的动画,我们可以通过媒体查询来检测用户的偏好,并相应地禁用或简化动画。

/* 默认情况下,应用动画 */
.animated-element {
  animation: spin 2s linear infinite;
}
/* 如果用户在系统设置中选择了“减少动画”,则禁用动画 */
@media (prefers-reduced-motion: reduce) {
  .animated-element {
    animation: none; /* 或者替换为一个非常简单的动画 */
  }
}

这是一个非常专业且贴心的做法,强烈推荐使用。


第四部分:综合案例:创建一个动态产品展示卡片

我们将结合过渡和关键帧动画,创建一个引人注目的产品卡片。

目标效果:

  1. 卡片有轻微的阴影和悬停放大效果(过渡)。
  2. 卡片内部有一个“热卖”标签,有闪烁动画(关键帧)。
  3. 卡片被加入购物车时,有一个飞入购物车的动画(关键帧 + JS)。

HTML:

<div class="product-card">
  <div class="badge">热卖</div>
  <img src="https://via.placeholder.com/200" alt="产品图片">
  <h3>超酷产品</h3>
  <p>¥99.00</p>
  <button class="add-to-cart">加入购物车</button>
</div>
<div class="cart-icon">🛒</div>

CSS:

/* 基础样式 */
body {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background-color: #f0f0f0;
  font-family: sans-serif;
}
.product-card {
  width: 250px;
  background: white;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
  padding: 20px;
  text-align: center;
  position: relative;
  transition: transform 0.3s ease, box-shadow 0.3s ease; /* 卡片悬停过渡 */
}
.product-card:hover {
  transform: translateY(-10px) scale(1.02);
  box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
/* 热卖标签 */
.badge {
  position: absolute;
  top: 10px;
  right: -30px;
  background: #ff4757;
  color: white;
  padding: 5px 30px;
  border-radius: 20px;
  font-size: 12px;
  animation: pulse 1.5s infinite; /* 关键帧动画 */
}
@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(255, 71, 87, 0.7);
  }
  70% {
    box-shadow: 0 0 0 10px rgba(255, 71, 87, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(255, 71, 87, 0);
  }
}
/* 购物车图标 */
.cart-icon {
  position: fixed;
  top: 20px;
  right: 20px;
  font-size: 30px;
  cursor: pointer;
}
/* 飞入动画的初始状态 */
.flying-item {
  position: fixed;
  width: 50px;
  height: 50px;
  pointer-events: none;
  z-index: 1000;
  opacity: 0;
}
@keyframes flyToCart {
  0% {
    opacity: 1;
    transform: translate(0, 0) scale(1);
  }
  100% {
    opacity: 0;
    transform: translate(var(--end-x), var(--end-y)) scale(0.2);
  }
}

JavaScript:

document.querySelector('.add-to-cart').addEventListener('click', function(e) {
  // 1. 克隆产品图片
  const productCard = document.querySelector('.product-card');
  const img = productCard.querySelector('img');
  const flyingImg = img.cloneNode(true);
  // 2. 设置克隆图片的初始位置和样式
  const rect = img.getBoundingClientRect();
  flyingImg.style.position = 'fixed';
  flyingImg.style.left = rect.left + 'px';
  flyingImg.style.top = rect.top + 'px';
  flyingImg.style.width = rect.width + 'px';
  flyingImg.style.height = rect.height + 'px';
  flyingImg.classList.add('flying-item');
  // 3. 添加到页面
  document.body.appendChild(flyingImg);
  // 4. 获取购物车图标的位置
  const cartIcon = document.querySelector('.cart-icon');
  const cartRect = cartIcon.getBoundingClientRect();
  // 5. 计算动画的终点
  const endX = cartRect.left - rect.left;
  const endY = cartRect.top - rect.top;
  flyingImg.style.setProperty('--end-x', `${endX}px`);
  flyingImg.style.setProperty('--end-y', `${endY}px`);
  // 6. 应用飞行动画
  flyingImg.style.animation = 'flyToCart 0.8s ease-in-out forwards';
  // 7. 动画结束后移除元素
  flyingImg.addEventListener('animationend', () => {
    flyingImg.remove();
    // 可以在这里添加其他逻辑,比如更新购物车数量
    alert('已添加到购物车!');
  });
});

这个案例展示了如何将过渡、关键帧动画和 JavaScript 事件结合,创造出流畅且有趣的交互体验。


总结与资源推荐

  • CSS 过渡:适合简单的状态变化,如 hover,语法简单,性能好。
  • CSS 关键帧动画:适合复杂的、多步骤的动画,如加载、无限循环等。
  • 性能是王道:优先使用 transformopacity 来创建动画。
  • 可访问性很重要:使用 prefers-reduced-motion 尊重用户的偏好。
  • 组合使用:将 CSS 动画与 JavaScript 结合,可以实现更强大的交互控制。

资源推荐

希望这份详尽的教程能帮助你从入门到精通 HTML5 & CSS3 动画!动手实践是最好的学习方式,祝你玩得开心!