Appearance
CSS 3D
A12 的圆柱。父元素负责「眼睛离画面多远」,被转的那一层负责「子元素真的待在 3D 里」,每张卡片自己转开再沿 Z 推出去。
三层各写什么
text
body perspective: 1200px 眼睛到画面的距离。写在「要呈现 3D 的元素」的父级上
.a3d transform-style: preserve-3d 子元素的 3D 不要被拍扁
animation: rotateY 整圈自己转
.card rotateY + translateZ 第 i 张转到自己的角度,再推到圆柱表面perspective 写在 .a3d 自己身上,近大远小作用在它的子元素上会不稳定。写在 body 或包住它的 .scene 上。
perspective: 1200px 越小,近大远小越夸张。题目没有规定这个数,能看出远近即可。
一张卡片的位置
HTML 已经给了 --n(一共几张)和 --i(这张是第几张,从 0 开始)。不要在 CSS 里写 12 或 30deg。
相邻两张的夹角:
css
--angle: calc(1turn / var(--n));12 张时是 30 度,但这个 30 是算出来的。改成 8 张必须变成 45 度,所以不能写死。
卡片宽 w,中间留一点缝 gap。要让它们边靠边围成正多边形,推出去的半径是:
css
--r: calc((var(--w) + var(--gap)) / 2 / tan(var(--angle) / 2));tan() 要吃一个角度。1turn / var(--n) 是角度,合法。tan() 返回的是没有单位的数,长度除以它仍然是长度。
卡片自己的变换:
css
transform: rotateY(calc(var(--i) * var(--angle))) translateZ(var(--r));先在原处绕 Y 轴转到自己的方向,再沿着自己的前方推 r。顺序写反,卡片会堆在圆心。
12 张、宽 17.5em、缝 0.6em、根字号 16px 时,半径大约是 540px。把 --n 改成 8,半径大约变成 350px。如果还是 540,说明半径写死了。
什么会把 3D 拍扁
下面任何一条出现在 .a3d 上,preserve-3d 失效,圆柱变成一叠平面卡片:
overflow不是visible(最常见的是overflow: hidden)opacity小于 1filter,包括blurtransform-style没写,默认就是flat
藏滚动条写在 html, body 上,不要写在 .a3d 上。圆角裁图片写在 .card 上,那只拍扁这一张卡片内部,圆柱还在。
背面会透出来时,给卡片加:
css
backface-visibility: hidden;转动
css
.a3d { animation: a3d-spin 24s linear infinite; }
@keyframes a3d-spin { to { transform: rotateY(-1turn); } }必须 linear。用 ease 会一快一慢,转完一圈时速度对不上,能看出重置。
转到整一圈(1turn)再循环。转到 359deg 再跳回 0,接缝会闪。
整段可粘贴
css
html, body { height: 100%; margin: 0; overflow: hidden; }
body { display: grid; place-items: center; perspective: 1200px; }
.a3d {
--w: 17.5em;
--gap: 0.6em;
--angle: calc(1turn / var(--n));
--r: calc((var(--w) + var(--gap)) / 2 / tan(var(--angle) / 2));
position: relative;
width: var(--w);
height: calc(var(--w) * 0.66);
transform-style: preserve-3d;
animation: a3d-spin 24s linear infinite;
}
@keyframes a3d-spin { to { transform: rotateY(-1turn); } }
.a3d .card {
position: absolute;
inset: 0;
transform: rotateY(calc(var(--i) * var(--angle))) translateZ(var(--r));
border-radius: 1.5em;
overflow: hidden;
backface-visibility: hidden;
}
.a3d .card img { width: 100%; height: 100%; object-fit: cover; display: block; }.a3d 必须有明确宽高,因为卡片是 position: absolute; inset: 0,父级没有尺寸时卡片面积是 0。