你会用CSS画一个炫酷的3D旋转柱状体吗?
用 CSS 模拟一些 3D 形状,对前端开发者的 CSS 技术水平有很高的考验。同时也可以提高对 CSS 的掌握和认知。本文将会使用纯粹的 HTML、CSS 来绘制下面这个外观精美的 3D 圆珠图形,而不会使用任何框架。
实现分析
在写代码之前,我们要分析应该如何实现。首先要提供一个 3D 空间的容器用来放置圆柱体,设置倾斜度数。然后在 3D 空间中画一个圆柱体,圆柱体由多个切面组成,每个切面需要计算宽度和倾斜度数,圆柱体还要有循环旋转的动画。简单的实现思路已经有了,下面开始动手吧!
HTML
首先编写 HTML 部分的代码。
<div class="holder">
<div class="cylinder">
<!-- 这里放置很多切面 -->
</div>
</div>
cylinder 中需要有很多切面,这里我们尝试设置 50 个切面,为了方便,我们使用 JS 的循环帮我们生成。
const cylinderEl = document.querySelector('.cylinder')
for(let i = 0; i < 50; i++) {
cylinderEl.innerHTML += `
<div class="face" style="--index: ${i};"></div>`
}
CSS
要实现 3D 圆柱体,需要进行一些计算。所以在开始写代码之前,先定义出一些变量,来帮助我们更好的计算。这是 CSS 变量。
body{
--pi: 3.14159265358979;
--cylinder-width: 100vw;
--face-count: 50;
--face-deg: (360deg / var(--face-count));
--face-width: calc(var(--cylinder-width) / var(--face-count));
--face-shift: calc(var(--cylinder-width) / var(--pi) / 2);
}
我来解释一下它们每一个的作用:
- pi:圆周率,因为我们要计算一个完美的圆
- cylinder-width:圆柱体的宽度
- face-count:切面的总数
- face-deg:每个切面的旋转度数,用 360 度除以切面总数
- face-width:每个切面的宽度,通过圆柱体宽度除掉总数就可以了。
- face-shift:将切面向外面移动,让它们具有更多的 3D 效果
添加 holder 样式,让容器实现倾斜外观。
.holder {
transform-style: preserve-3d;
transform: rotateX(-35deg);
}
设置圆柱体的旋转动画,让它绕 Y 轴 360 度旋转。
@keyframes spin {
to {
transform: rotateY(-360deg);
}
}
我们开始编写圆柱体的样式,它没什么特别之处。
.cylinder {
position: relative;
height: 400px;
width: var(--cylinder-width);
transform-style: preserve-3d;
animation: spin 7s infinite linear;
}
继续编写切面的样式。
.face {
position: absolute;
background-color: #da0060;
opacity: 0.7;
height: 100%;
width: var(--face-width);
top: 50%;
left: 50%;
transform: rotateY(calc(var(--face-deg) * var(--index))) translateZ(
calc(var(--face-shift) - -6px)
);
}
每个侧面都需要计算宽度,其中最具有魔法性的是 transform 属性。我们改变了 Y 轴的旋转角度,将所有切面拼凑起来,最终得到一个完美的圆。第一个切面的偏移度是 7.2,第二个是 14.4,依次递增,第 50 个刚好是 360 度。每个切面的 Z 轴都会向后一些,这样看起来空间会更大。最后给第一个切面做个标记,可以更好的看到它的旋转。
.face:nth-child(1) {
background: repeating-linear-gradient(
-45deg,
transparent,
transparent 25%,
#f55 0,
#f55 50%
),
repeating-linear-gradient(
45deg,
transparent,
transparent 25%,
#55f 0,
#55f 50%
),
#efb;
}
最终完整的代码
<style>
body {
--pi: 3.14159265358979;
--cylinder-width: 100vw;
--face-count: 50;
--face-deg: (360deg / var(--face-count));
--face-width: calc(var(--cylinder-width) / var(--face-count));
--face-shift: calc(var(--cylinder-width) / var(--pi) / 2);
}
@keyframes spin {
to {
transform: rotateY(-360deg);
}
}
.holder {
transform-style: preserve-3d;
transform: rotateX(-35deg);
}
.cylinder {
position: relative;
height: 50vw;
width: var(--cylinder-width);
transform-style: preserve-3d;
animation: spin 5s infinite linear;
}
.face {
position: absolute;
background-color: #487df8;
opacity: 0.7;
height: 100%;
width: var(--face-width);
top: 50%;
left: 50%;
transform: rotateY(calc(var(--face-deg) * var(--index)))
translateZ(calc(var(--face-shift) - -6px));
}
.face:nth-child(1) {
background: repeating-linear-gradient(
-45deg,
transparent,
transparent 25%,
#f55 0,
#f55 50%
),
repeating-linear-gradient(
45deg,
transparent,
transparent 25%,
#55f 0,
#55f 50%
),
#efb;
}
</style>
<div class="holder">
<div class="cylinder">
</div>
</div>
<script>
const cylinderEl = document.querySelector('.cylinder')
for(let i = 0; i < 50; i++) {
cylinderEl.innerHTML += `
<div class="face" style="--index: ${i};"></div>`
}
</script>
这么简单的 CSS 3D 旋转柱状体,你学会了吗?
转载自:https://juejin.cn/post/7130495713196113927