CSS3实战:实现一个旋转的3D金币

如图图片[1]-CSS3实战:实现一个旋转的3D金币-一一网
最近亲爱的产品同学,提了一个需求:在页面某个角落增加一个旋转的金币来吸引用户参加活动~越快上越好~

拿到这个需求,第一反应 gif+a 标签,简单粗暴+便捷。即将实施就碰到一个问题,UI 小姐姐还没有做设计,排期需要在 x 天后~怎么办?没有难做的工作,只有解决困难的打工人!

链接好说,旋转的金币怎么整?旋转的金币 = 旋转 + 金币。旋转通过 css3 的动画属性 animation+ @keyframes 就可以搞定:

.coin {

  transform-style: preserve-3d;

  animation: rotate3d 3s linear infinite;

}



@keyframes rotate3d {

  0% {

    transform: perspective(1000px) rotateY(0deg);

  }



  100% {

    transform: perspective(1000px) rotateY(360deg);

  }

}
复制代码

那么金币怎么办?我们用 div 来 DIY 一下吧~如果把金币的表面图案都擦掉,那金币就是一个特别矮的圆柱体,我们需要一个正面+背面+弯曲的侧面。那么正面+背面很简单

$coin-thickness: 4px;

$coin-front: "https://tosv.byted.org/obj/maat/img/d2FuZ3NoaXpoZW4uNzUzMA/file_178a58ae02711.png";

$coin-back: "https://tosv.byted.org/obj/maat/img/d2FuZ3NoaXpoZW4uNzUzMA/file_178a58ae0276.png";



.coin__front {

  background-image: url($coin-front);

  background-size: cover;

  transform: translateZ($coin-thickness / 2);

}

.coin__back {

  background-image: url($coin-back);

  background-size: cover;

  transform: translateZ(-$coin-thickness / 2) rotateY(180deg);

}
复制代码

侧面怎么画?翻了不少 css 文档,除了 border-radius 还真没有找到一个弯曲的属性,我徒手 DIY 金币的过程就要这么结束了么?

当然不会!!!敬我中华民族智慧一杯~早在数千年前,祖冲之就告诉我们~实现不了完美的圆,那就让它近似圆就好了!数年前端从业经验告诉我,只要能骗过用户的视觉,那什么都是真的!!!就是你了——多棱柱。

方案有了,但麻烦的是,画多少棱面才能骗过用户的视觉?我得手写多少 css+div?不用慌,less 中的 when 来搞定 n 次循环,前端框架中整个 map 来生成 div

const n = 80

<div className={styles.coin__edge}>

  {Array(n).fill(1).map((value, key) => (<div key={key} />))}

</div>
复制代码

对这些 div 使用 translate + rotate 来确定位置~

// 多棱柱体大小(直径)

$coin-diameter: 320px;

// 多棱柱体高度

$coin-thickness: 40px;

// 颜色

$coin-color: rgb(255, 223, 95);

// 多棱柱的棱数

$edge-faces: 100;

// 每个棱的高度 π * 直径 / 棱数

$edge-face-length: 3.14 * $coin-diameter / $edge-faces;



.coin__edge {

  > div {

    position: absolute;

    height: $edge-face-length;

    width: $coin-thickness;

  }

  @for $i from 1 through $edge-faces {

    div:nth-child(#{$i}) {

      background: $coin-color;

      transform:

        // 由于默认绘制div的初始位置在左上角,需要把它移到中心

        translateY($coin-diameter / 2 - $edge-face-length / 2)

        translateX($coin-diameter / 2 - $coin-thickness / 2)

        // 横向旋转

        rotateY(90deg)

        // 调整每片角度

        rotateX(360deg / $edge-faces * $i + 90)

        // 移动至多棱柱边缘

        translateZ($coin-diameter / 2);

    }

  }

}
复制代码

默认绘制的位置移到中心

div:nth-child(#{$i}) {

  transform:

        // 由于默认绘制div的初始位置在左上角,需要把它移到中心

        translateY($coin-diameter / 2 - $edge-face-length / 2)

        translateX($coin-diameter / 2 - $coin-thickness / 2)

}
复制代码

横向旋转

div:nth-child(#{$i}) {

  transform:

        // 由于默认绘制div的初始位置在左上角,需要把它移到中心

        translateY($coin-diameter / 2 - $edge-face-length / 2)

        translateX($coin-diameter / 2 - $coin-thickness / 2)

        // 横向旋转

        rotateY(90deg)

}
复制代码

调整每片角度

div:nth-child(#{$i}) {

  transform:

        // 由于默认绘制div的初始位置在左上角,需要把它移到中心

        translateY($coin-diameter / 2 - $edge-face-length / 2)

        translateX($coin-diameter / 2 - $coin-thickness / 2)

        // 横向旋转

        rotateY(90deg)

        // 调整每片角度

        rotateX(360deg / $edge-faces * $i + 90)

        // 移动至多棱柱边缘

        translateZ($coin-diameter / 2);

}
复制代码

移动至多棱柱边缘

div:nth-child(#{$i}) {

  transform:

        // 由于默认绘制div的初始位置在左上角,需要把它移到中心

        translateY($coin-diameter / 2 - $edge-face-length / 2)

        translateX($coin-diameter / 2 - $coin-thickness / 2)

        // 横向旋转

        rotateY(90deg)

        // 调整每片角度

        rotateX(360deg / $edge-faces * $i + 90)

        // 移动至多棱柱边缘

        translateZ($coin-diameter / 2);

}
复制代码

图片[2]-CSS3实战:实现一个旋转的3D金币-一一网最终效果图:图片[2]-CSS3实战:实现一个旋转的3D金币-一一网
完美解决~

最后附上完整代码

骨架:

const CoinTrans = () => {

  return <div class="coin">

    <div className="coin__front"></div>

    <div className="coin__back"></div>

    <div className="coin__edge">

      {Array(100).fill(1).map((item,key)=> <div key={key} />)}

    </div>

    {/* 阴影 */}

    <div className="coin__shadow"></div>

  </div>

}
复制代码
$coin-diameter: 320px;

$coin-thickness: 40px;

$coin-color: rgb(255, 223, 95);

$coin-front: "https://tosv.byted.org/obj/maat/img/d2FuZ3NoaXpoZW4uNzUzMA/file_178a58ae02711.png";

$coin-back: "https://tosv.byted.org/obj/maat/img/d2FuZ3NoaXpoZW4uNzUzMA/file_178a58ae0276.png";

$edge-faces: 100;

$edge-face-length: 3.14 * $coin-diameter / $edge-faces;

$turn-time: 8s;



.coin {

  position: relative;

  width: $coin-diameter;

  height: $coin-diameter;

  margin: 0 auto;

  transform-style: preserve-3d;

  animation: rotate3d $turn-time linear infinite;

  transition: all 0.3s;

}



.coin__front,

.coin__back {

  position: absolute;

  width: $coin-diameter;

  height: $coin-diameter;

  border-radius: 50%;

  overflow: hidden;

  background-color: $coin-color;

  color: #000;

  font-size: $coin-diameter * 0.6;

  // 金币表面的闪动 buling~buling~~

  &:after {

    content: "";

    position: absolute;

    left: -$coin-diameter / 2;

    bottom: 100%;

    display: block;

    height: $coin-diameter / 1.5;

    width: $coin-diameter * 2;

    background: #fff;

    opacity: 0.3;

    animation: shine linear $turn-time / 2 infinite;

  }

}



.coin__front {

  background-image: url($coin-front);

  background-size: cover;

  transform: translateZ($coin-thickness / 2);

}

.coin__back {

  background-image: url($coin-back);

  background-size: cover;

  transform: translateZ(-$coin-thickness / 2) rotateY(180deg);

}



.coin__edge {

  > div {

    position: absolute;

    height: $edge-face-length;

    width: $coin-thickness;

  }

  @for $i from 1 through $edge-faces {

    div:nth-child(#{$i}) {

      background: $coin-color;

      // 另一种移动逻辑

      // transform: translateY($coin-diameter / 2 - $edge-face-length / 2)

      //   translateX($coin-diameter / 2 - $coin-thickness / 2)

      //   rotateZ(360deg / $edge-faces * $i + 90)

      //   translateX($coin-diameter / 2)

      //   rotateY(90deg);

      // rotateZ(360deg / $edge-faces * $i + 90)

      transform: translateY($coin-diameter / 2 - $edge-face-length / 2)

        translateX($coin-diameter / 2 - $coin-thickness / 2)

        rotateY(90deg)

        rotateX(360deg / $edge-faces * $i + 90)

        translateZ($coin-diameter / 2);

    }

  }

}



// 阴影 css

.coin__shadow {

  position: absolute;

  width: $coin-diameter;

  height: $coin-thickness;

  border-radius: 50%;

  background: #000;

  box-shadow: 0 0 $coin-thickness * 5 $coin-thickness * 5 #000;

  opacity: 0.125;

  transform: rotateX(90deg) translateZ(-$coin-diameter * 1.1) scale(0.5);

}



@keyframes rotate3d {

  0% {

    transform: perspective(1000px) rotateY(0deg);

  }



  100% {

    transform: perspective(1000px) rotateY(360deg);

  }

}



@keyframes shine {

  0%,

  15% {

    transform: translateY($coin-diameter * 2) rotate(-40deg);

  }

  50% {

    transform: translateY(-$coin-diameter) rotate(-40deg);

  }

}
复制代码

数据平台前端团队,在公司内负责风神、TEA、Libra、Dorado 等大数据相关产品的研发。我们在前端技术上保持着非常强的热情,除了数据产品相关的研发外,在数据可视化、海量数据处理优化、web excel、WebIDE、私有化部署、工程工具都方面都有很多的探索和积累,有兴趣可以与我们联系。对产品有任何建议和反馈也可以直接找我们进行反馈 ~

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享