🎯 从 .face 到动画 —— 用 HTML + CSS 构建可复用的表情动画系统
📚 引言
在本次分享中,我们将通过一个“飞吻动画”案例,了解了 CSS 高级动画、结构化 HTML/CSS 编码、面向对象的 CSS(OOCSS)思想 以及 DRY 原则 的应用。
- 先看效果图
🧱 第一步:HTML 结构设计
我们始终遵循“先写结构,再写样式”的原则。清晰的 HTML 是良好前端工程的基础。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>CSS 表情动画</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<!-- 左边小球 -->
<div class="ball" id="l-ball">
<div class="face face-l"></div>
</div>
<!-- 右边小球 -->
<div class="ball" id="r-ball">
<div class="face face-r"></div>
<div class="kiss-m">
<div class="kiss"></div>
</div>
</div>
</div>
</body>
</html>
✅ 设计思路说明:
- 使用
.container作为整体容器,负责水平垂直居中。 - 每个
.ball是一个独立的表情球,内部包含.face面部组件。 .face-l和.face-r是.face的多态扩展类,表示不同状态或位置的面部。.kiss-m是一个动画元素,用于实现“飞吻”效果。
🎨 第二步:CSS 布局与样式
🔑 关键技巧:绝对定位 + transform 居中和display: inline-block
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 238px;
}
.ball{
border: 8px solid;
width: 100px;
height: 100px;
border-radius: 50%;
background-color: white;
display: inline-block;
position: relative;
}
✅ 为什么用
transform: translate(-50%, -50%)?
它不依赖元素尺寸,适用于任何大小的容器,是最通用的居中方案之一。
✅display: inline-block的作用?它让元素在同一行内水平排列,不会像块级元素一样独占一行
面部组件设计(面向对象的css)
我们采用 面向对象的 CSS ,将 .face 定义为“基类”,.face-l 和 .face-r 为其“子类”(多态)。
.face {
width: 70px;
height: 30px;
position: absolute;
top: 30px;
}
🌱 多态实现:.face-l 与 .face-r
.face-l {
right: 0;
animation: face 4s ease infinite;
}
.face-r {
left: 0;
top: 37px;
}
💡 核心思想:
将样式拆分为可复用的“对象”,如.face是面部的通用样式,.face-l是其具体实现,便于扩展和维护。
伪元素绘制“腮绿”
.face::before,
.face::after {
content: "";
position: absolute;
background-color: #badc58;
width: 18px;
height: 8px;
border-radius: 50%;
top: 20px;
}
.face::before { right: -8px; }
.face::after { left: -5px; }
⚠️ 伪元素要点:
- 必须写
content: "",否则不会渲染。
🎞️ 第三步:CSS 动画实现
1. 左球摆动动画
#l-ball {
animation: close 4s ease infinite;
z-index: 100;
position: relative;
}
@keyframes close {
0% { transform: translate(0px); }
20% { transform: translate(20px); }
35% { transform: translate(20px); }
55% { transform: translate(0px); }
100% { transform: translate(0px); }
}
2. 面部晃动(.face-l)
.face-l {
animation: face 4s ease infinite;
}
@keyframes face {
0%,10% { transform: translate(0) rotate(0); }
20%,35% { transform: translate(5px) rotate(-2deg); }
28%,50%,100% { transform: translate(0) rotate(0); }
}
3. 右球飞吻动画
#r-ball {
animation: kiss 4s ease infinite;
z-index: 10;
}
@keyframes kiss {
40% { transform: translate(0); }
50% { transform: translate(30px) rotate(20deg); }
60% { transform: translate(-33px); }
67% { transform: translate(-33px); }
77% { transform: translate(0); }
100% { transform: translate(0); }
}
4. 嘴巴隐藏 + 飞吻出现(状态切换)
.mouth-r {
animation: mouth-m 4s ease infinite;
}
.kiss-m {
position: absolute;
left: 20px;
top: 22px;
opacity: 0;
animation: kiss-m 4s ease infinite;
}
@keyframes mouth-m {
0% to 54.9% { opacity: 1; }
55% to 66% { opacity: 0; }
66.1% { opacity: 1; }
}
@keyframes kiss-m {
0% to 55% { opacity: 0; }
66% { opacity: 1; }
66.1% { opacity: 0; }
}
✅ 动画同步技巧:通过精确控制
opacity和transform的关键帧,实现“嘴巴消失 → 飞吻出现 → 恢复”的流畅交互。
animation:动画名称 动画周期 动画曲线 重复次数
每个动画名称对应一个@keyframes规则,而@keyframes则用来定义动画的关键帧
📌 总结与延伸
通过这个小项目,我们实践了:
- ✅ HTML 结构先行:清晰的 DOM 是一切的基础。
- ✅ CSS 模块化设计:使用 OOCSS 和 DRY 原则组织样式。
- ✅ 动画精细控制:通过
@keyframes实现复杂交互。 - ✅ 布局技巧:
transform: translate(-50%, -50%)实现完美居中。