CSS3变形与动画:从入门到精通
目录
1.7 独立属性:translate / scale / rotate(Transforms Level 2)
4. Transform × Transition × Animation 选型与范式
5.1 变换演示场(hover 触发,transition 实现)
5.2 3D 翻牌(preserve-3d + backface-visibility)
5.4 展开/收起:max-height + transform 双保险
1. Transform:几何变换
1.1 什么是 transform(渲染与原理)
transform 是 CSS3 引入的几何变形属性。它可在二维/三维空间里对盒子进行平移、缩放、旋转、倾斜与矩阵变换。不改变文档流:元素的布局占位不变,视觉上被“拿起来”在独立坐标系里变形。
渲染关键点:
-
不触发重排(reflow),通常只触发重绘或直接在合成层上完成(GPU 参与),因此性能优。
-
transform常创建新的层叠上下文,影响z-index、叠放顺序与固定定位的表现。 -
命中测试(点击区域)默认基于变换后图形(大部分浏览器),但滚动容器/溢出剪裁等边界场景要留意(见 1.8)。
1.2 语法与执行顺序
transform: <transform-function> [<transform-function> ...];
-
顺序重要:矩阵乘法是非交换的。
translate → rotate与rotate → translate结果完全不同。 -
示例(先平移再旋转再缩放):
transform: translateX(100px) rotate(30deg) scale(1.2);
思维模型:从右到左看“坐标系的变换”(数学上),但 CSS 直观上按书写顺序逐步应用即可,牢记“写在前面的先执行”。
1.3 变换原点:transform-origin
定义旋转/缩放/倾斜的基准点(对平移无效)。默认 50% 50%(元素中心)。
.box {
transform-origin: center center; /* 默认 */
/* 常见写法 */
transform-origin: top left;
transform-origin: 100% 50%;
transform-origin: 50% 150%; /* 在元素外的延伸点也可 */
}
变换原点可配合
scale或rotate设计“从某角展开/收缩”的动画。
1.4 各类 2D 变换函数
1) 平移 translate
transform: translateX(100px);
transform: translateY(-50px);
transform: translate(100px, -50px); /* 同时设置 x 与 y */
-
%相对自身尺寸(translateX(50%)为自身宽度一半)。 -
不改变文档占位,适合替代
left/top做动效。
2) 缩放 scale
transform: scale(2); /* 等比放大 */
transform: scaleX(1.5); /* 仅 x 方向 */
transform: scaleY(0.8); /* 仅 y 方向 */
transform: scale(1.2, 0.8); /* 非等比 */
-
缩放中心受
transform-origin控制。 -
文本缩放可能出现锯齿/模糊,可视需要用
translateZ(0)/backface-visibility缓解,或避免极端缩放。
3) 旋转 rotate
transform: rotate(45deg); /* 正为顺时针,负为逆时针 */
-
支持
deg、rad、turn(如rotate(0.5turn))。
4) 倾斜 skew
transform: skewX(30deg); /* 沿X轴倾斜30° */
transform: skewY(15deg); /* 沿Y轴倾斜15° */
transform: skew(30deg, 15deg);
-
使坐标轴成非直角关系,适合做斜边卡片等效果。
1.5 3D 变换(核心函数)
transform: translateZ(100px); /* 前后(z轴) */
transform: translate3d(x,y,z);
transform: rotateX(45deg);
transform: rotateY(60deg);
transform: rotateZ(30deg); /* 等价 2D rotate */
transform: rotate3d(x, y, z, angle);
z 轴正方向指向观察者,“数值越大越靠前”。
1.6 透视与 3D 场景
-
透视(景深):可在父元素上设置
.scene { perspective: 800px; perspective-origin: 50% 50%; }或在元素上用函数(影响该元素自身变换链)
.card { transform: perspective(800px) rotateY(45deg); } -
子元素保留 3D:
.parent { transform-style: preserve-3d; }默认
flat会将子元素压扁到 2D 平面。 -
背面可见性:
.face { backface-visibility: hidden; }常用于翻牌,避免背面镜像闪烁。
1.7 独立属性:translate / scale / rotate(Transforms Level 2)
除了 transform: ... 复合写法,现代浏览器支持独立变换属性:
.box {
translate: 20px 0; /* 等价 transform: translate(20px) */
scale: 1.1; /* 等价 transform: scale(1.1) */
rotate: 15deg; /* 等价 transform: rotate(15deg) */
}
优势:
-
更易与其他函数合成与覆盖;
-
与动画/过渡搭配时可独立控制某一维度变换;
-
未来与
motion-path等特性结合更直观。
1.8 参考盒与命中测试:transform-box
决定 % 等相对量参考的几何盒(对 HTML 元素通常是 border-box;对 SVG 非常有用):
transform-box: border-box | fill-box | view-box;
命中测试与滚动要点:
-
变换后元素的可点击区域通常随之改变(以变换后几何为准)。
-
被
overflow: hidden的容器裁剪可能影响交互区域。 -
开启 3D 或大量合成层时,注意层顺序对命中测试的影响。
1.9 叠层与层叠上下文
transform 会创建新的层叠上下文,它影响:
-
z-index的比较范围; -
与
position: fixed、filter、opacity等并用时的绘制顺序; -
可能改变
position: fixed元素的参照(例如位于变换元素内时)。
1.10 性能与优化
-
优先用
transform/opacity做动效,避免top/left/width/height。 -
合理使用:
will-change: transform; /* 或搭配 */ contain: paint; /* 限定绘制范围,避免外溢重绘 */ -
警惕:
-
过多合成层(内存占用、上传纹理成本);
-
极端
scale导致字体/位图模糊; -
反复触发强制同步布局(避免 JS 在动画过程中读取布局)。
-
2. Transition:让“状态变化”平滑可感
2.1 概念与触发机制
transition 不会主动产生动画,它监听属性值的变化(如状态类名切换、伪类 :hover、JS 改样式等),并在给定时间内平滑过渡。
2.2 语法与速查表
transition: <property> <duration> <timing-function> <delay>;
/* 可多条逗号分隔 */
transition: transform .3s ease, opacity .2s linear .1s;
常用:
-
transition-property: 具体属性或all -
transition-duration:ms/s -
transition-timing-function:-
ease | linear | ease-in | ease-out | ease-in-out -
cubic-bezier(x1, y1, x2, y2)(自定义) -
steps(n, start|end)(阶跃)
-
-
transition-delay: 延迟
2.3 可过渡属性与 “auto” 陷阱
-
大部分数值型属性可过渡(含
transform、opacity)。 -
height: auto不可直接过渡。常见替代:-
用
max-height从0 → 某大值; -
或用
scaleY(配transform-origin: top)视觉展开; -
或用
grid-template-rows/clip-path等技巧。
-
2.4 多属性与时间曲线
-
多个属性可分别设置时长/曲线:
transition: transform .35s cubic-bezier(.2,.7,.3,1), opacity .2s ease-out .1s; -
steps(n)适合“打字机”“逐帧跳变”。
2.5 事件:监听过渡生命周期
JS 可监听:
-
transitionrun(过渡已排入队列) -
transitionstart(开始) -
transitionend(结束) -
transitioncancel(被打断)
2.6 实战技巧
-
悬停抬升:
.card { transition: transform .2s ease, box-shadow .2s; } .card:hover { transform: translateY(-6px); box-shadow: 0 12px 24px rgba(0,0,0,.12); } -
手风琴(max-height 技法):
.panel { max-height: 0; overflow: hidden; transition: max-height .35s ease; } .panel.open { max-height: 600px; } /* 600 设为足以容纳内容的值 */ -
禁用首次动画闪烁:初次渲染无动画,增加“就绪”类后才让过渡生效。
3. Animation:时间轴动画与关键帧
3.1 关键帧与速查表
@keyframes spin-move {
0% { transform: translateX(0) rotate(0deg); }
50% { transform: translateX(140px) rotate(180deg) scale(1.1); }
100% { transform: translateX(0) rotate(360deg); }
}
.box {
animation: spin-move 3s ease-in-out .2s infinite alternate both running;
}
animation 简写依次包含:
-
name/duration/timing-function/delay/iteration-count/direction/fill-mode/play-state
3.2 循环、方向、填充模式、暂停
-
循环:
animation-iteration-count: infinite | <number> -
方向:
normal | reverse | alternate | alternate-reverse -
填充:
none | forwards | backwards | both -
暂停/恢复:
animation-play-state: paused | running
3.3 steps() 与逐帧动画
@keyframes type {
from { width: 0ch; }
to { width: 24ch; }
}
.typing {
animation: type 2s steps(24, end) forwards;
overflow: hidden; white-space: nowrap;
}
-
或者用背景图/雪碧图 +
steps()做帧动画。
3.4 与 transform 的组合与拆分
-
复杂动画建议拆分多个关键帧或使用独立属性(
translate/rotate/scale)以减少覆盖冲突。 -
也可将“位移动效”放
transform,“透明/色彩变化”放opacity/filter,分层控制。
3.5 无障碍与系统偏好
尊重用户“减少动画”偏好:
@media (prefers-reduced-motion: reduce) {
* { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: 0s !important; }
}
4. Transform × Transition × Animation 选型与范式
-
一次性、被动的状态切换(如 hover、展开/收起):
transition+transform -
自动播放、循环、多阶段:
animation+transform -
性能优先:尽量只动画
transform与opacity -
可维护性:优先使用独立变换属性(
translate/scale/rotate)或拆分关键帧
5. 实战案例
5.1 变换演示场(hover 触发,transition 实现)
<!DOCTYPE html><html lang="zh-CN"><meta charset="utf-8"><title>Transform 基本演示</title>
<style>
*{box-sizing:border-box} body{font:16px/1.6 system-ui, -apple-system, Segoe UI, Roboto}
.wrap{display:grid;grid-template-columns:repeat(5, 160px);gap:20px;justify-content:center;margin:48px auto;max-width:1000px}
.box{height:100px;border:1px solid #ddd;display:flex;align-items:center;justify-content:center;transition:transform .35s ease;background:#f7f7f7}
.t-translate:hover{transform:translateX(80px)}
.t-scale:hover{transform-origin:left center;transform:scale(1.4)}
.t-rotate:hover{transform:rotate(30deg)}
.t-skew:hover{transform:skew(15deg, 0)}
.t-combo:hover{transform:translate(50px, -12px) rotate(20deg) scale(1.2)}
</style>
<div class="wrap">
<div class="box t-translate">translate</div>
<div class="box t-scale">scale</div>
<div class="box t-rotate">rotate</div>
<div class="box t-skew">skew</div>
<div class="box t-combo">combo</div>
</div>
</html>
5.2 3D 翻牌(preserve-3d + backface-visibility)
<!DOCTYPE html><html lang="zh-CN"><meta charset="utf-8"><title>3D 卡片翻转</title>
<style>
.scene{perspective:900px;display:flex;justify-content:center;margin-top:80px}
.card{width:240px;height:160px;position:relative;transform-style:preserve-3d;transition:transform .8s cubic-bezier(.2,.7,.2,1)}
.card:hover{transform:rotateY(180deg)}
.face{position:absolute;inset:0;display:grid;place-items:center;font:600 18px/1.2 system-ui;border:1px solid #ddd;background:#fff}
.back{transform:rotateY(180deg);backface-visibility:hidden}
.front{backface-visibility:hidden}
</style>
<div class="scene">
<div class="card">
<div class="face front">Front</div>
<div class="face back">Back</div>
</div>
</div>
</html>
5.3 关键帧:旋转移动缩放一体
<!DOCTYPE html><html lang="zh-CN"><meta charset="utf-8"><title>Animation + Transform</title>
<style>
.stage{height:260px;display:grid;place-items:center}
.dot{width:24px;height:24px;border-radius:50%;background:#e86;animation:orbit 3s ease-in-out .2s infinite alternate both}
@keyframes orbit{
0%{ transform:translate(0, 0) rotate(0deg) scale(1) }
50%{ transform:translate(160px, -40px) rotate(180deg) scale(1.25) }
100%{ transform:translate(0, 0) rotate(360deg) scale(1) }
}
</style>
<div class="stage"><div class="dot"></div></div>
</html>
5.4 展开/收起:max-height + transform 双保险
<!DOCTYPE html><html lang="zh-CN"><meta charset="utf-8"><title>手风琴</title>
<style>
.btn{display:inline-block;padding:.5em 1em;border:1px solid #ddd;cursor:pointer;margin:12px 0}
.panel{max-height:0;overflow:hidden;transition:max-height .35s ease;transform-origin:top}
.panel.open{max-height:500px}
.content{padding:.75em 0;border-top:1px dashed #ddd}
</style>
<div class="btn" onclick="p.classList.toggle('open')">切换</div>
<div id="p" class="panel"><div class="content">
这里是内容。现实项目里 max-height 设为足够大的值(如 500/800),避免 auto 过渡问题。
</div></div>
<script>const p=document.getElementById('p')</script>
</html>
6. 常见问题
Q1:为什么我 z-index 失效了?
A:transform 创建了新的层叠上下文。比较 z-index 需在同一上下文内。将相关元素放在同一上下文,或在父级控制 z-index。
Q2:height: auto 为什么不动?
A:auto 不可插值。用 max-height、scaleY 或 grid 技巧替代。
Q3:文字旋转或缩放后发虚?
A:尝试避免极端缩放;可用 backface-visibility: hidden;、translateZ(0) 或字体渲染优化;有时改用 filter: blur(0) 触发优化也能改善,但要评估性能。
Q4:3D 翻转时背面穿帮?
A:确保父级 perspective、自身 transform-style: preserve-3d,正反两面都加 backface-visibility: hidden;。
Q5:动画导致页面滚动卡顿?
A:减小动画区域、减少合成层数量;只动画 transform/opacity;必要时添加 will-change: transform,并避免长时间保留。
Q6:transitionend 没有触发?
A:确认确实有“数值变化”,并且过渡的 duration > 0;同时确保监听的是实际变化的属性名。
Q7:命中测试不准?
A:多数浏览器以变换后几何为准;但注意 overflow 剪裁、层顺序与 pointer-events 设置;复杂 3D 场景中考虑为交互元素单独设更高层或透明命中层。
7. 结语
-
Transform 决定“形态怎么变”;
-
Transition 让“状态切换”变得自然;
-
Animation 则给你完整的“时间轴与循环控制”。
三者并用,可以在纯 CSS(几乎不依赖 JS)的前提下,完成从微交互到立体场景的绝大多数动效需求。
更多推荐
所有评论(0)