先记住这个答案
perspective 定义了观察者到 z=0 平面的距离,是产生近大远小效果的前提。没有它,rotateX、rotateY 这些 3D 变换看起来只像在做 2D 缩放。perspective-origin 控制消失点的位置,默认在容器正中心,移动它就相当于你换了个角度看同一个场景。两者配合才能做出逼真的卡片翻转、轮播立体感等效果。
perspective越小,透视越强perspective-origin改变观察位置- 父级透视可供多个子元素共享
- 无透视时
rotateY缺少近大远小效果
透视值大小对变形的影响
perspective 的值可以理解为相机镜头到屏幕的距离。值越小,镜头越近,就像把眼睛贴到物体前面看,近处很大远处很小,变形很夸张。值越大,镜头退得越远,物体看起来越「平」,接近正交投影。
一般做卡片翻转效果,perspective 设 800px 到 1200px 比较自然。低于 300px 会有很强的鱼眼效果,高于 2000px 几乎看不出立体感。
perspective 值的对比CSS.container-close {
/* 镜头很近,旋转时变形剧烈 */
perspective: 200px;
}
.container-far {
/* 镜头很远,旋转时几乎看不出透视 */
perspective: 2000px;
}
.card {
transition: transform 0.6s;
}
.card:hover {
transform: rotateY(45deg);
}两个容器里放同样的卡片,hover 时都旋转 45 度。200px 的那个会看到卡片近端很大、远端急剧缩小;2000px 的那个看起来就像是在做一个轻微的倾斜。
写在父元素和写在 transform 里的区别
perspective 有两种写法。一种是写在父元素上作为独立属性,另一种是写在子元素的 transform 里作为函数调用。
写在父元素上时,所有子元素共享同一个消失点。比如一排卡片,每张卡片旋转时透视效果都是从容器中心看过去的,看起来像一组卡片在同一个 3D 空间里。
写在子元素的 transform: perspective(500px) rotateY(30deg) 里时,每个元素有自己独立的消失点,就像每张卡片各自有一个小相机对着它。多张卡片排列时效果会不太统一。
做整组元素的 3D 布局(比如立体轮播)通常用父元素写法。做单个元素的独立翻转效果用 transform 里的函数写法也可以。
容易答错的地方
- 忘了设
transform-style: preserve-3d - 父元素加了
perspective,子元素做了 3D 变换,但如果中间有一层元素没设transform-style: preserve-3d,3D 效果就会被「压平」。浏览器默认值是flat,会把子元素的 3D 变换投影到 2D 平面上再渲染。 - 把
perspective-origin当成transform-origin perspective-origin移动的是观察者的位置,影响消失点。transform-origin移动的是变换的参考点,影响元素绕哪个点旋转。两者的作用对象不同,不能混用。
面试官还会怎么问?
perspective: none 和不写 perspective 一样吗?
一样。none 是 perspective 的默认值,表示不使用透视投影。子元素的 3D 变换在视觉上退化成正交投影,没有近大远小。
backface-visibility 和 perspective 有什么关系?
backface-visibility: hidden 让元素旋转超过 90 度后背面不可见。做卡片翻转时正面和背面各一层,旋转 180 度后正面隐藏、背面显示。这个属性需要配合 perspective 才有意义,没有透视就看不出翻转效果。
为什么加了 perspective 之后 position: fixed 的子元素表现不对了?
设了 perspective 或 transform 的元素会创建新的包含块。fixed 定位的子元素不再相对于视口定位,而是相对于这个新包含块。这是 CSS 规范的行为,常常在做 3D 效果时意外地让弹窗、导航栏等固定元素错位。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。