• css3实现一个3d楼梯动画


    背景

    👏👏通过给出的宽/高+个数,用css3的transform以及transform-style快速的实现一个3d楼梯,速速来Get吧~
    🥇文末分享源代码。记得点赞+关注+收藏!

    1.实现效果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8HrUkV1e-1669741574799)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2f2e8db6e64249a1be8b6c673b08f3aa~tplv-k3u1fbpfcp-watermark.image?)]

    2.实现步骤

    • 定义css变量:宽w、高h、个数count
    /* 楼梯高度 */
    --h: 40px;
    /* 楼梯宽度 */
    --w: 50px;
    /* 楼梯节数 */
    --count: 5;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 写一个容器,宽为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;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 在容器内写count个div,给每个div标签定义css变量c,表示当前位置,从1~count,设置width为w,高为h * c,transform-style为preserve-3d;基于父容器absolute定位,bottom都为0,left从0开始,为w*(c-1);实现效果如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ETj4Frj-1669741574800)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/69fa85ea62de4537b971bb8aed3add2c~tplv-k3u1fbpfcp-watermark.image?)]

    注意:以下圈出来的即为定义的w和h

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ntHzke6a-1669741574801)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a0145bed8725419aa348054a7502158a~tplv-k3u1fbpfcp-watermark.image?)]

    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    .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;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 对父容器进行transform偏移,看看效果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QBiAh3sl-1669741574801)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cc5d39834dad475bae554dbb3c533869~tplv-k3u1fbpfcp-watermark.image?)]

    .container{
     + transform: rotateX(-30deg) rotateY(30deg);
    }
    
    • 1
    • 2
    • 3
    • 为每个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);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 前伪元素设置z轴方向的偏移,偏移量为总高度(count * h)的一半

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PxB3ozZK-1669741574802)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf00f9db459343ebb7e0e7c0314bb562~tplv-k3u1fbpfcp-watermark.image?)]

    .container .step::before {
        /* z轴偏移为高度的2分之一 */
        --z: calc(var(--count) * var(--h) / 2);
        transform: rotateX(90deg) translateZ(var(--z));
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pThI4Sgv-1669741574803)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d386df4cb4024740a940c41b6c13b067~tplv-k3u1fbpfcp-watermark.image?)]

    • 为每个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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 后伪元素设置z轴方向的偏移,偏移量为总高度(count * h)的一半
    .container .step::after {
        /* z轴偏移为高度的2分之一 */
        --z: calc(var(--count) * var(--h) / 2);
        transform: rotateY(90deg) translateZ(calc(-1 * var(--z)));
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LF6Oy9ga-1669741574803)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f326df5c49e04505b91cd316e4f13ae7~tplv-k3u1fbpfcp-watermark.image?)]

    • 为前伪元素添加hover效果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YHZGvzSE-1669741574804)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e5b841c792a04e81b120e6ee76320e92~tplv-k3u1fbpfcp-watermark.image?)]

    .container .step:hover::before {
      cursor: pointer;
      filter: brightness(1.1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 将父容器进行旋转,可以看到已经有大概的轮廓了

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XEDgD4sO-1669741574804)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/059ea8e878134bda9429c2b474469857~tplv-k3u1fbpfcp-watermark.image?)]

    • 在每个div下添加两个span标签,宽度为w,高度为父元素step的高度,做为梯形的左右两侧

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iSbNYExq-1669741574804)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/97b3e09d7ffc455bb5187743e04cda83~tplv-k3u1fbpfcp-watermark.image?)]

    <div class="container">
      <div class="step" style="--c: 1">
        <span></span>
        <span></span>
      </div>
     ... //4个相同的标签
    </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    .container .step span {
        position: absolute;
        display: block;
        width: var(--w);
        height: 100%;
        background: orchid;
        transform-style: preserve-3d;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 设置第一个span的位置,z轴方向的偏移,偏移量为总高度(count * h)的一半

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7pSWZxVg-1669741574805)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8c16ac5d11c34005b4eb2d066857af74~tplv-k3u1fbpfcp-watermark.image?)]

    .container .step span:nth-child(1) {
      /* z轴偏移为高度的2分之一 */
      --z: calc(var(--count) * var(--h) / 2);
      transform: translateZ(var(--z));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 设置第二个span的位置,z轴方向的偏移,偏移量为总高度(count * h)的一半

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mu8gUJCD-1669741574805)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/112ca2e24fb547ceb1fd1ba424fe3da4~tplv-k3u1fbpfcp-watermark.image?)]

    .container .step span:nth-child(2) {
      /* z轴偏移为高度的2分之一 */
      --z: calc(var(--count) * var(--h) / 2);
      transform: translateZ(calc(-1 * var(--z)));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 可以看到,现在还剩两处需要填充

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ujWUuOQJ-1669741574805)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ab9cfcde86c248a89e66faa646ede934~tplv-k3u1fbpfcp-watermark.image?)]

    • 填补第一处内容,将最后一个div标签中的最后一个span为容器,添加一个伪元素,高度100%,宽度为counut * h

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kuohIa8z-1669741574806)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f92d35e0086f4053a1ebf799ebe906d1~tplv-k3u1fbpfcp-watermark.image?)]

    .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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 将该伪元素y轴方向旋转90deg

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w3EyYjZ5-1669741574806)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7b076bbfa5d44ce5a3ef9702b371df98~tplv-k3u1fbpfcp-watermark.image?)]

    • 调整其在x,y,z轴各个方向的偏移量,x轴方向为总高度的一半 即 -1 * (count * h) /2,y轴方向为0,z轴方向为-1 * ((count * h) /2 - w)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4NfeKF8Z-1669741574806)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/48fbe2e2cad64cdca43285e217b6bec3~tplv-k3u1fbpfcp-watermark.image?)]

    .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)));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 填补第二处内容,将第一个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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 将该伪元素X轴方向旋转90deg

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mnGh4tXX-1669741574807)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c70a6c455e52481683c480a67a13797d~tplv-k3u1fbpfcp-watermark.image?)]

    • 调整其在x,y,z轴各个方向的偏移量,x轴方向为0,y轴为总高度的一半 即 (count * h) /2,z轴方向为 ((count * h) /2 - h)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v2HvZUPU-1669741574807)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8ecf10fee9a246b58968956478d7bfd7~tplv-k3u1fbpfcp-watermark.image?)]

    .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));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 到此,我们就是写了一个完整的3d楼梯了,去掉辅助线,将各边的颜色风格统一一致

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WtIcIxNH-1669741574807)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bbeb1937968d4cab875cc3b510a6ed49~tplv-k3u1fbpfcp-watermark.image?)]

    • 为底部添加一个阴影效果,选择最底部的区域,设置scale

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lRHpxo2p-1669741574808)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d2f2ec6bce2404f81ebd848e6482ae5~tplv-k3u1fbpfcp-watermark.image?)]

    .container .step:first-child span:nth-child(2)::after{
        + transform: rotateX(90deg) translate3d(0, var(--z), var(--k)) scale(1.25);
    }
    
    • 1
    • 2
    • 3
    • 设置filter的blur滤镜

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z8UnVb7L-1669741574808)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b924431b90cb405b94a3ccff107146c8~tplv-k3u1fbpfcp-watermark.image?)]

    .container .step:first-child span:nth-child(2)::after{
        +filter: blur(20px);
    }
    
    • 1
    • 2
    • 3
    • 父容器添加animation动画,改变rotateX, rotateY的位置

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gOiaPTcD-1669741574808)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5f444825834e43c1b66d9910ca548092~tplv-k3u1fbpfcp-watermark.image?)]

    .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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 修改w和h,设置不同的count,试试吧

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UoIIkZjn-1669741574808)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3f4030e2d2c64313b5530f1890688a20~tplv-k3u1fbpfcp-watermark.image?)]

     /* 楼梯高度 */
      --h: 10px;
      /* 楼梯宽度 */
      --w: 50px;
      /* 楼梯节数 */
      --count: 6;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148

    4.写在最后🍒

    看完本文如果觉得对你有一丢丢帮助,记得点赞+关注+收藏鸭 🍕
    更多相关内容,关注🍥苏苏的bug,🍡苏苏的github,🍪苏苏的码云~
  • 相关阅读:
    web - 前段三剑客
    redis的持久化机制原理
    vue使用pinia存储数据并保持数据持久化
    容猫科技PHP面试题(!带答案)
    Flutter-自定义画板
    爬虫学习——第一章 初识爬虫
    代码随想录 --- day21 --- 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先
    MATLAB算法实战应用案例精讲-【数模应用】最大似然估计(MLE)(附MATLAB、Python和R语言代码)
    [附源码]Python计算机毕业设计Django基于web的建设科技项目申报管理系统
    pdf也可以制作成可翻页的电子书吗?
  • 原文地址:https://blog.csdn.net/qq_48085286/article/details/128027786