背景
👏👏通过给出的宽/高+个数,用css3的transform以及transform-style快速的实现一个3d楼梯,速速来Get吧~
🥇文末分享源代码。记得点赞+关注+收藏!
1.实现效果
2.实现步骤
- 定义css变量:宽w、高h、个数count
/* 楼梯高度 */
--h: 40px;
/* 楼梯宽度 */
--w: 50px;
/* 楼梯节数 */
--count: 5;
- 写一个容器,宽为count * w; 高为count * h;设置transform-style: preserve-3d,让转换的子元素保留3D转换。
.container {
position: relative;
width: calc(var(--count) * var(--w));
height: calc(var(--count) * var(--h));
transform-style: preserve-3d;
}
- 在容器内写count个div,给每个div标签定义css变量c,表示当前位置,从1~count,设置width为w,高为h * c,transform-style为preserve-3d;基于父容器absolute定位,bottom都为0,left从0开始,为w*(c-1);实现效果如下:
注意:以下圈出来的即为定义的w和h
<div class="container">
<div class="step" style="--c: 1">
</div>
<div class="step" style="--c: 2">
</div>
<div class="step" style="--c: 3">
</div>
<div class="step" style="--c: 4">
</div>
<div class="step" style="--c: 5">
</div>
</div>
.container .step {
position: absolute;
--i: calc(var(--c) - 1);
left: calc(var(--w) * var(--i));
bottom: 0;
width: var(--w);
height: calc(var(--h) * var(--c));
border: 1px solid orange;
}
- 对父容器进行transform偏移,看看效果
.container{
+ transform: rotateX(-30deg) rotateY(30deg);
}
- 为每个div设置前伪元素,宽度为w,高度为count * h,设置X轴方向旋转从0-90deg,效果如下:
.container .step::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: var(--w);
height: calc(var(--count) * var(--h));
background: orange;
transform: rotateX(90deg);
}
- 前伪元素设置z轴方向的偏移,偏移量为总高度(count * h)的正一半
.container .step::before {
/* z轴偏移为高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
transform: rotateX(90deg) translateZ(var(--z));
}
- 为每个div设置后伪元素,高度为h,宽度为count* h(这个值与前伪元素的高度对应),设置Y轴方向旋转从0-90deg,效果如下:
.container .step::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: calc(var(--count) * var(--h));
height: var(--h);
background: orangered;
transform: rotateY(90deg);
}
- 后伪元素设置z轴方向的偏移,偏移量为总高度(count * h)的负一半
.container .step::after {
/* z轴偏移为高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
transform: rotateY(90deg) translateZ(calc(-1 * var(--z)));
}
- 为前伪元素添加hover效果
.container .step:hover::before {
cursor: pointer;
filter: brightness(1.1);
}
- 将父容器进行旋转,可以看到已经有大概的轮廓了
- 在每个div下添加两个span标签,宽度为w,高度为父元素step的高度,做为梯形的左右两侧
<div class="container">
<div class="step" style="--c: 1">
<span></span>
<span></span>
</div>
... //4个相同的标签
</div>
.container .step span {
position: absolute;
display: block;
width: var(--w);
height: 100%;
background: orchid;
transform-style: preserve-3d;
}
- 设置第一个span的位置,z轴方向的偏移,偏移量为总高度(count * h)正的一半
.container .step span:nth-child(1) {
/* z轴偏移为高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
transform: translateZ(var(--z));
}
- 设置第二个span的位置,z轴方向的偏移,偏移量为总高度(count * h)负的一半
.container .step span:nth-child(2) {
/* z轴偏移为高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
transform: translateZ(calc(-1 * var(--z)));
}
- 可以看到,现在还剩两处需要填充
- 填补第一处内容,将最后一个div标签中的最后一个span为容器,添加一个伪元素,高度100%,宽度为counut * h
.container .step:last-child span:nth-child(2)::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: calc(var(--counut) * var(--h));
height: 100%;
background: #222;
}
- 将该伪元素y轴方向旋转90deg
- 调整其在x,y,z轴各个方向的偏移量,x轴方向为总高度的负一半 即 -1 * (count * h) /2,y轴方向为0,z轴方向为-1 * ((count * h) /2 - w)
.container .step:last-child span:nth-child(2)::before {
/* z轴偏移为总高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
/* 总高度的2分之一 - 宽度*/
--k: calc(var(--z) - var(--w));
transform: rotateY(90deg)
translate3d(calc(-1 * var(--z)), 0, calc(-1 * var(--k)));
}
- 填补第二处内容,将第一个div标签中的第二个span为容器,添加一个伪元素,高度counut * h,宽度为span元素的高度* count
.container .step:first-child span:nth-child(2)::after {
content: "";
position: absolute;
left: 0;
top: 0;
background: #222;
width: calc(100% * var(--count));
height: calc(calc(var(--count) * var(--h)));
transform: rotateX(90deg);
}
- 将该伪元素X轴方向旋转90deg
- 调整其在x,y,z轴各个方向的偏移量,x轴方向为0,y轴为总高度的正一半 即 (count * h) /2,z轴方向为 ((count * h) /2 - h)
.container .step:first-child span:nth-child(2)::after {
/* z轴偏移为总高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
/* 总高度的2分之一 - 高度*/
--k: calc(var(--z) - var(--h));
transform: rotateX(90deg) translate3d(0, var(--z), var(--k));
}
- 到此,我们就是写了一个完整的3d楼梯了,去掉辅助线,将各边的颜色风格统一一致
- 为底部添加一个阴影效果,选择最底部的区域,设置scale
.container .step:first-child span:nth-child(2)::after{
+ transform: rotateX(90deg) translate3d(0, var(--z), var(--k)) scale(1.25);
}
- 设置filter的blur滤镜
.container .step:first-child span:nth-child(2)::after{
+filter: blur(20px);
}
- 父容器添加animation动画,改变rotateX, rotateY的位置
.container {
+ transform: rotateX(-30deg) rotateY(30deg);
+ animation: animate 10s linear infinite;
}
@keyframes animate {
0% {
transform: rotateX(-30deg) rotateY(0deg);
}
100% {
transform: rotateX(-30deg) rotateY(1turn);
}
}
- 修改w和h,设置不同的count,试试吧
/* 楼梯高度 */
--h: 10px;
/* 楼梯宽度 */
--w: 50px;
/* 楼梯节数 */
--count: 6;
3.实现代码
<style>
:root {
--bg: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%);
--c1: #6ec5e7;
--c3: #c2e9fb;
--c2: skyblue;
/* 楼梯高度 */
--h: 10px;
/* 楼梯宽度 */
--w: 50px;
/* 楼梯节数 */
--count: 6;
}
body {
background: var(--bg);
}
.container {
position: relative;
width: calc(var(--count) * var(--w));
height: calc(var(--count) * var(--h));
transform-style: preserve-3d;
transform: rotateX(-30deg) rotateY(30deg);
animation: animate 10s linear infinite;
}
@keyframes animate {
0% {
transform: rotateX(-30deg) rotateY(0deg);
}
100% {
transform: rotateX(-30deg) rotateY(1turn);
}
}
.container .step {
position: absolute;
--i: calc(var(--c) - 1);
left: calc(var(--w) * var(--i));
bottom: 0;
width: var(--w);
height: calc(var(--h) * var(--c));
transform-style: preserve-3d;
}
.container .step::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: var(--w);
height: calc(var(--count) * var(--h));
background: var(--c3);
/* z轴偏移为总高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
transform: rotateX(90deg) translateZ(var(--z));
}
.container .step:hover::before {
cursor: pointer;
filter: brightness(1.1);
}
.container .step::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: calc(var(--count) * var(--h));
height: var(--h);
background: var(--c2);
/* z轴偏移为总高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
transform: rotateY(90deg) translateZ(calc(-1 * var(--z)));
}
.container .step span {
position: absolute;
display: block;
width: var(--w);
height: 100%;
background: var(--c1);
transform-style: preserve-3d;
}
.container .step span:nth-child(1) {
/* z轴偏移为总高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
transform: translateZ(var(--z));
}
.container .step span:nth-child(2) {
/* z轴偏移为总高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
transform: translateZ(calc(-1 * var(--z)));
}
.container .step:last-child span:nth-child(2)::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: calc(var(--count) * var(--h));
height: 100%;
background: var(--c2);
/* z轴偏移为总高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
/* 总高度的2分之一 - 宽度*/
--k: calc(var(--z) - var(--w));
transform: rotateY(90deg)
translate3d(calc(-1 * var(--z)), 0, calc(-1 * var(--k)));
}
.container .step:first-child span:nth-child(2)::after {
content: "";
position: absolute;
left: 0;
top: 0;
background: var(--c1);
width: calc(100% * var(--count));
height: calc(calc(var(--count) * var(--h)));
/* z轴偏移为总高度的2分之一 */
--z: calc(var(--count) * var(--h) / 2);
/* 总高度的2分之一 - 高度*/
--k: calc(var(--z) - var(--h));
transform: rotateX(90deg) translate3d(0, var(--z), var(--k)) scale(1.25);
filter: blur(20px);
}
</style>
<body>
<div class="container">
<div class="step" style="--c: 1">
<span></span>
<span></span>
</div>
<div class="step" style="--c: 2">
<span></span>
<span></span>
</div>
<div class="step" style="--c: 3">
<span></span>
<span></span>
</div>
<div class="step" style="--c: 4">
<span></span>
<span></span>
</div>
<div class="step" style="--c: 5">
<span></span>
<span></span>
</div>
<div class="step" style="--c: 6">
<span></span>
<span></span>
</div>
</div>
</body>