文档章节

如何用CSS3画出懂你的3D魔方?

苏南-首席填坑官
 苏南-首席填坑官
发布于 2018/10/29 08:08
字数 2350
阅读 527
收藏 21

本文由IT·平头哥联盟-首席填坑官(苏南)分享,GZ好:honeyBadger8,梅斌的专栏,首席填坑官∙苏南的专栏

前言

  最近在写《每周动画点点系列》文章,上一期分享了< 手把手教你如何绘制一辆会跑车 >,本期给大家带来是结合CSS3画出来的一个立体3d魔方,结合了js让你随心所欲想怎么转,就怎么转,这里是 @IT·平头哥联盟,我是首席填坑官苏南(South·Su),我们先来看看效果,然后再分解它的实现过程吧

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8,梅斌的专栏,首席填坑官∙苏南的专栏

  • 作者:首席填坑官∙苏南
  • 交流:912594095、GZ好:honeyBadger8,本文原创,著作权归作者所有,转载请注明原链接及出处。

绘制过程:

  好吧,gif图看着好像有点不是很清晰,想在线预览的同学,可点击在线预览 ,废话不多扯了,先来分析一下,看如何实现这个功能吧。

∙ API预热 :
  • 本次示例是一个立体的正方形,既然有立体效果,肯定少不了CSS3中的 -webkit-perspective-透视、preserve-3d-三维空间,这个两个是重点哦,当然还有transform-origintransitiontransform等,先来回故一下 API 怎么是讲的吧:

perspective 取值 :

  • none :不指定透视 ;
  • length :指定观察者与「z=0」平面的距离,使具有三维位置变换的元素产生透视效果。「z>0」的三维元素比正常大,而「z<0」时则比正常小,大小程度由该属性的值决定,不允许负值。

transform-style 取值

  • flat :指定子元素位于此元素所在平面内;
  • preserve-3d :指定子元素定位在三维空间内,当该属性值为 preserve-3d时,元素将会创建局部堆叠上下文;

小结 :决定一个变换元素看起来是处在三维空间还是平面内,需要该元素的父元素上定义 <' transform-style '> 属性,也就是说想某元素有三维效果,需要设定它的父级有 preserve-3d

transform-origin 取值

  • percentage:用百分比指定坐标值。可以为负值;
  • length:用长度值指定坐标值。可以为负值;
  • left:指定原点的横坐标为left;
  • center①:指定原点的横坐标为center;
  • right:指定原点的横坐标为right;
  • top:指定原点的纵坐标为top;
  • center②:指定原点的纵坐标为center;
  • bottom:指定原点的纵坐标为bottom;

transform、transition等,就不介绍了

/* perspective 使用示例:*/
div{
  -webkit-perspective:600px;
  perspective:600px;
}

/*transform-style 使用示例:*/
.preserve{
  transform-style:preserve-3d;
  -webkit-transform-style:preserve-3d;
}

  /*transform-origin 使用示例:*/
.preserve{
  -webkit-transform-origin:50% 50% -100px; or 
  -webkit-transform-origin:bottom; or
  -webkit-transform-origin:top;
  …………
}
  

∙ 绘制6个面 :
  • 是的,我没有说错,就是6个面:上、正面、下、背面、左、右,
  • 上面API讲了这么多,来实践试一下吧,写6个div,结构大概是这样的,也是接下来的魔方需要的结构:

<div class="cube">
    <div class="cube-inner running">
        <p class="single-side s1"><span>最</span></p>
        <p class="single-side s2"><span>懂</span></p>
        <p class="single-side s3"><span>你</span></p>
        <p class="single-side s4"><span>的</span></p>
        <p class="single-side s5"><span>魔</span></p>
        <p class="single-side s6"><span>方</span></p>
    </div>
</div>

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8 本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8

  • !!!发生了什么??是不是很吃惊??说好的值越大,透视效果越强的呢?后面明明藏了个妹子,怎么看没有透视出来?
  • 开始我也是跟你一样吃惊的,但瞬间就悟透了,少了rotate,加个它再来看看效果吧:

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8,首席填坑官∙苏南的专栏,梅斌的专栏


.cube{
    width:200px;
    height:200px;
    margin:10px auto;
    padding:260px;
    position:relative;
    -webkit-perspective:600px;
    perspective:600px;
    transition: .5s ;

}
.cube-inner{
    width:200px;
    height:200px;
    position:relative;
    -webkit-transform-style:preserve-3d;
    transition:.3s; 
    -webkit-transform-origin:50% 50% -100px;
    transform: rotateX(45deg);
}
.cube:hover{
    /*鼠标经过时,把 perspective 过渡到100 */
    -webkit-perspective:100px;
    perspective:100px;
}

  • 既然API有效,那么拉下来我们就画出6个面吧,按:上、正面、下、背面、左、右,这个顺序来设置吧;
  • 首先,我们要指定它们是在三维空间内的preserve-3d,也就是6个面的父级要设置 transform-style 样式;
  • 以上都设置好后,再来看看6个面吧,为了便于区分,给它们每个都设置了不同颜色(用了css3的渐变 radial-gradient)——不想手写的同学推荐一个网站可在线设置你要的效果,复制样式即可,先来一睹风采,为了便于观察,整体角度旋转了10deg:

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8

  • 说到渐变,偶然之间发现了一个有意思的东西hue-rotate,它能在你初始的颜色基础上旋转元素的色调及其内容,从而达到不同的效果。了解更多

hue-rotate : The hue-rotate() CSS function rotates the hue of an element and its contents. Its result is a <filter-function>.

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8,首席填坑官∙苏南的专栏,梅斌的专栏

  • ** 上 ** - "":
.cube-inner .single-side.s1{
    /*s1顶部*/
    left:0;top:-200px;
    background: radial-gradient(circle, rgba(255,255,255,.88), #00adff);
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #00adff);
    transform-origin:bottom;
    -webkit-transform-origin:bottom;
    transform:rotateX(90deg);
    -webkit-transform:rotateX(90deg);
}

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8,首席填坑官∙苏南的专栏,梅斌的专栏

  • ** 正面 ** - "":

    • 下面就是默认的,什么都不用设置,所以就不展示了 ;
  • ** 下面 ** - "":

    • 即底部,底部的设置,正好跟顶部它是相反的,一个origin 以 bottom为基准为坐标,一个以top为基准为坐标;
.cube-inner .single-side.s3{
    /*s3底部*/
    left:0;top:200px;
    background: radial-gradient(circle, rgba(255,255,255,.88), #100067);
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #100067);
    transform-origin:top;
    -webkit-transform-origin:top;
    transform:rotateX(-90deg);
    -webkit-transform:rotateX(-90deg);
}

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8,首席填坑官∙苏南的专栏,梅斌的专栏

  • ** 背面 ** - "":
    • 即正面的后边,整体旋转了 135deg,让背面更直观能看到;
    • translateZ 、rotateX 同时移动,形成透视的关系,让它看起来,在正面面的后面;
    • 下图二,把默认的正面,设置了透明度,可以看出,背面的透视效果;
.cube-inner .single-side.s4{
    /*s4背部*/
    z-index:2;
    left:0;top:0;
    background: radial-gradient(circle, rgba(255,255,255,.88), #F0C);
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #F0C);
    transform:translateZ(-200px) rotateX(180deg) ; 
    -webkit-transform:translateZ(-200px) rotateX(180deg) ; /*rotateZ(-180deg) 左右旋转的时候,Z轴旋转180°,因为字是倒着的*/
}

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8,首席填坑官∙苏南的专栏,梅斌的专栏 本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8

  • ** 左侧面 ** - "":
    • origin以right为基准,left负元素的宽度,rotateY轴旋转90deg;
.cube-inner .single-side.s5{
    /*s5左侧*/
    left:-200px;top:0;
    background: radial-gradient(circle, rgba(255,255,255,.88),rgba(33,33,33,1));
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88),rgba(33,33,33,1));
    transform-origin:right;
    -webkit-transform-origin:right;
    transform:rotateY(-90deg)
    -webkit-transform:rotateY(-90deg)
}

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8,首席填坑官∙苏南的专栏,梅斌的专栏

  • ** 右侧面 ** - "":
    • 同理右侧,与左侧正好相反;
.cube-inner .single-side.s6{
    /*s6右侧*/
    right:-200px;top:0;
    transform-origin:left;
    -webkit-transform-origin:left;
    background: radial-gradient(circle, rgba(255,255,255,.88), #f00);
    background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #f00);
    transform:rotateY(90deg);
    -webkit-transform:rotateY(90deg);
}

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8

小结 : 嗯,以上魔方的6个面的绘制过程,基本已经完成,主要在在于transform-originrotatetranslate等属性的应用,但为了让它更炫酷一些,我们还要给边角加一些光感。

∙ 添加高光 :
  • 细心的宝宝,前面的布局应该已经发现了,每一行布局的p标签里,都多套了一层span,就是为高光光感,埋下的伏笔,一个平面正方形有四个边,after、before只有两,那么肯定要再套一层,当然方法很多,比如直接用border也是可以的,但比较麻烦,我就选择了现在要讲的这种:
  • after、before设置1px的边框,设置一个线性渐变,中间是白色,两断是过渡到透明的,这样高光就有了,来看一组图吧:

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8

∙ CSS 360°旋转 :
  • 上面是一个鼠标经过的过渡动画,可以看出立体效果是已经有了,接下来就写一个CSS animation的动画,让它360度旋转,每个角都能看到,这样会显的很666;
  • animation 配合 keyframes 使用,请看代码示例:
.cube .cube-inner{ 
  /*-webkit-transform:rotateX(180deg) rotateY(0deg) ;*/
  animation: elfCube 10s infinite ease-in-out;
  -webkit-animation: elfCube 10s infinite ease alternate;
}

@keyframes elfCube {
  0% { 
    transform: rotateX(0deg) rotateY(0deg); 
  }
  50% { 
    transform: rotateX(360deg) rotateY(360deg); 
  }
  100% { 
    transform: rotateX(0deg) rotateY(0deg); 
  }
}
@-webkit-keyframes elfCube {
  0% {
   -webkit-transform: rotateX(0deg) rotateY(0deg); 
  }
  50% {
   -webkit-transform: rotateX(360deg) rotateY(360deg); 
  }
  100% { 
    transform: rotateX(0deg) rotateY(0deg); 
  }
}

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8

∙ 跟随鼠标旋转 :
  • 说好的随着鼠标旋转呢??
  • 别慌,接下来就是带你装逼,带你飞的时候,
    • 首先我们要了解,鼠标在容器内所在的位置,X = e.pageX - ele.offsetLeft, Y = e.pageY - ele.offsetTop;
    • 同时要知道元素内的中心点:centerX = width/2,centerY =height/2;
    • 然后得出值:axisX = X - centerX,axisY = Y - centerY;
    • PS : 开始尝试想的是鼠标从哪个方向进入,得到它的角度,但发现旋转效果不明显 ,有兴趣的同学可以尝试一下:(((Math.atan2(Y, X) * (180 / Math.PI)) + 180) / 90),参考司徒大神的JS判断鼠标从什么方向进入一个容器;
    • 最后,给容器绑上事件:mouseovermousemovemouseout,鼠标进入时,暂停css的动画,不然会相互打架哦!

本文由IT·平头哥联盟-首席填坑官∙苏南分享,GZ好:honeyBadger8

 ……
getAxisX(e){
  let left = this.cubeEle.offsetLeft;
  return e.pageX - left - (this.cubeW/2) * (this.cubeW>this.cubeH ? this.cubeH/this.cubeW : 1);
}
getAxisY(e){
  let top = this.cubeEle.offsetTop;
  return e.pageY - top - (this.cubeH/2) * (this.cubeH>this.cubeW ? this.cubeW/this.cubeH : 1);
}
 …………

 …………
run(){
  this.cubeEle.addEventListener('mouseover',(e)=>this.hoverOut(e),false);
  this.cubeEle.addEventListener('mousemove',(e)=>this.move(e),false);
  this.cubeEle.addEventListener('mouseout',(e)=>this.hoverOut(e),false);
}
hoverOut(e){
  //进入/离开
  e.preventDefault();
  this.axisX = this.getAxisX(e),
  this.axisY = this.getAxisY(e);

  if(e.type == 'mouseout'){ //离开
    this.axisX=0;
    this.axisY = 0;
    console.log("离开")
    this.cubeInner.className="cube-inner running";
  }else{
    this.cubeInner.className="cube-inner";
    console.log("进入")
  };
  let rotate = `rotateX(${-this.axisY}deg) rotateY(${-this.axisX}deg)`;
  this.cubeInner.style.WebkitTransform = this.cubeInner.style.transform = rotate;
}
 ……

结尾:

  • -webkit-perspective,
  • -webkit-transform-style,
  • -webkit-transform-origin,
  • radial-gradient、linear-gradient,
  • transform:rotate、translate、scale,
  • transition,
  • animation;
  • 以上就是今天为大家带来的分享,以及使用到的知识点的API,如文章中有不对之处,烦请各位大神斧正,更多资源可下方公Z号哦!
  • 文章源码获取-> blog-resource
  • 想直接在线预览

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,GZ好:honeyBadger8,首席填坑官∙苏南的专栏,梅斌的专栏

作者:苏南 - 首席填坑官

链接:https://blog.csdn.net/weixin_43254766/article/details/83472829

交流:912594095、GZ好:honeyBadger8

本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮,首席填坑官∙苏南的专栏,梅斌的专栏

© 著作权归作者所有

苏南-首席填坑官
粉丝 2
博文 21
码字总数 54603
作品 0
深圳
前端工程师
私信 提问
玩转3D Swiper性感秀之思路分析总结

前言   继一次的3D魔方之后,这次带你一起玩转性感美女秀,正常套路,请先一堵为快,有兴趣继续,没兴趣也可以看看美女养眼哦🤪!想直接在线预览 👈 回顾:   看过上次的的同学对于本...

苏南
2018/11/05
0
0
简单说 用CSS做一个魔方旋转的效果

说明 魔方大家应该是不会陌生的,这次我们来一起用CSS实现一个魔方旋转的特效,先来看看效果图! 解释 我们要做这样的效果,重点在于怎么把6张图片,摆放成魔方的样子,而把它们摆放成魔方的...

FEWY
2017/07/18
0
0
3D魔方 - 藐视 GPL 的 Blender 拷贝

Blender是一套三维绘图及渲染软件。它具有跨平台的特性,支持FreeBSD,IRIX,GNU/Linux,Microsoft Windows,Mac OS X,Solaris,及SkyOS。 3D魔方(3DMofun)软件不仅删除了 Blender 作品的...

oschina
2012/06/26
6.8K
68
在3D处理中遇到的问题

这两天再做一个魔方模拟器,但水平有限,遇到了很多的问题,我用的是OpenGL库来写的3D模拟器,九十在建立3D魔方模型的时候,就出问题了,我把每一个方块都用一个正方形来代替,一共有6各中心...

afsdasdf
2011/07/28
304
3
如何在页面上构建一个正方体,并且可以点击正方体内的内容

我想在网页上弄出一个正方体,然后把5*5*5总共125个点嵌入到其中,这些点默认都是白色,当点击其中的一个点的时候,被点击的点会变成红色,请问这应该如何实现呢?我目前的想法是用canvas来绘...

krait
2013/06/02
93
0

没有更多内容

加载失败,请刷新页面

加载更多

八、Docker Swarm

Docker Swarm有两件事:一个企业级的Docker主机安全集群,另一个是用于协调微服务应用程序的引擎。 在集群方面,它将一个或多个Docker节点组合在一起,并允许你将他们作为一个集群来管理。开...

倪伟伟
49分钟前
1
0
Fragment懒加载其实很简单

前言 记得去年面试的时候, 面了一家小公司, 那个面试官问我, fragment的懒加载做过吗?我说没做过(确实没做过).后来面试快结束了, 又问我, 懒加载没做过是吗?后来可想而知也没收到offer, (ಥ_...

天王盖地虎626
49分钟前
2
0
聊聊dubbo的TimeoutFilter

序 本文主要研究一下dubbo的TimeoutFilter ListenableFilter dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ListenableFilter.java public abstract class Liste......

go4it
56分钟前
6
0
方法与数组

方法 方法就是完成特定功能的代码块;在很多语言里面都有函数的定义,函数在Java中被称为方法 格式: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…) throw 异常{ 函数体;...

凹凸凸
今天
4
0
死磕 java同步系列之StampedLock源码解析

问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWriteLock的对比? 简介 StampedLock是java8中新增的类,...

彤哥读源码
今天
11
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部