github地址:https://github.com/lishuai336/3D-mf/tree/master/3Dmf
css3强大的功能让人叹为观止,我们工作中接触到的都是皮毛,要想真正提升技术跟进前端的技术发展,靠自学才是出路。不过我倒是觉得学习是一件快乐的事情,在快乐中学习会事半功倍。
最近看到了旋转的魔方小demo,便津津有味的琢磨起来,效果如图。对了,普及一下:在css3D布局中,X轴从左往右为正方向,Y轴从上往下为正方向,Z轴从屏幕里向屏幕外为正方向,另外,我还发现,rotateX(), rotateY()和rotateZ()旋转的方向都是:沿着各轴正方向逆时针旋转,也就是说rotateX(45deg)向X轴正方向看去是逆时针旋转45度,rotateY(45deg)向Y轴正方向看去是逆时针的,同样的,rotateZ(45deg)从屏幕里向屏幕外看是逆时针的。
通过查看源代码,在原来的基础之上进行了一些优化,每个面的9个小块我采用了display:flex弹性布局,而原来的则是全部采用绝对定位,这样代码太过繁琐。
html代码如下:
<body>
<div class="box">
<div class="boxs">
<ul class="front">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
<ul class="after">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
<ul class="left">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
<ul class="right">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
<ul class="top">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
<ul class="bottom">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
</div>
</div>
</body>
在body中定义一个变量,是的,最近才知道css也可以定义变量,定义变量符号就是“--”,而使用“--”是因为$被Sass占用了,@被Less占用了,所以是为了区分它们,由于魔方的6个面我没有采用绝对定位,要想组成一个立方体,所以每个面需要向上移动(300*-n)像素,故意这么布局的,熟悉一下css变量的使用,哈哈:
body {
--boxHeight: 300px; /*用于计算每个面向上移动的距离*/
}
最外层div用来确定位置,在浏览器窗口中心位置显示。
/*最外层盒子*/
.box {
position: absolute;
left: 50%;
top: 50%;
width: 300px;
height: 300px;
transform: translate(-50%, -50%);
}
整个魔方的样式:
.boxs {
width: 100%;
height: 100%;
transform-style: preserve-3d; /*使被转换的子元素保留其 3D 转换:*/
/*transform-origin: 10% 10%;*/ /*定义了观察者的视角相对于显示元素的位置*/
/*perspective: 500px;*/ /*设置用户与元素3d空间Z平面之间的距离*/
backface-visibility: hidden; /*定义当元素不面向屏幕时隐藏*/
}
接下来是每个面的通用样式:
/*六个面通用样式*/
.boxs ul{
height: 100%;
display: flex; /*开启弹性布局*/
flex-wrap: wrap; /*当一行显示不下的时候,允许换行*/
justify-content: space-between; /*块与块之间留有相等间距,与外层容器不留间距*/
}
魔方每个面9个小块的布局样式:
/*每个面9个小块通用样式*/
.boxs ul li{
width: calc(calc(100% / 3) - 1px); /* calc()是css函数,用于动态计算数值*/
height: calc(calc(100% / 3) - 1px);
text-align: center;
font-size: 20px;
line-height: 99px;
border-radius: 5px;
}
前面:由于魔方边长设置的300px,Z轴默认的基点位置是在0处,所以要拼成魔方,前面需向前移动150px:
.boxs .front{
transform: translateZ(150px);
}
.boxs .front li{
background-color: #0f0; /*前面小块背景色*/
}
这样第一个面的布局就完成了,如图:
后面:向Z轴负方向移动150px,由于我没有采用绝对定位,在布局中默认是这样的,所以要往上移动一个面的高度,另外,由于是后面,所以要沿着Y轴旋转180度:
.boxs .after{
transform: translateZ(-150px) translateY(calc(var(--boxHeight) * -1)) rotateY(180deg);
}
.boxs .after li{
background-color: #00f;
}
这时给整个魔方沿着X轴和Y轴旋转45度看下效果,此时前后面布局完成:
.boxs {
width: 100%;
height: 100%;
transform-style: preserve-3d; /*使被转换的子元素保留其 3D 转换:*/
/*transform-origin: 10% 10%;*/ /*定义了观察者的视角相对于显示元素的位置*/
/*perspective: 500px;*/ /*设置用户与元素3d空间Z平面之间的距离*/
backface-visibility: hidden; /*定义当元素不面向屏幕时隐藏*/
transform: rotateY(45deg) rotateX(45deg);
}
剩下4个面的布局同理,每个面都需要往上移动(300 * -n)px,左右两面分别沿X轴移动-150px和150px,沿着Y轴旋转-90deg和90deg,上下两面分别沿着Y轴移动150px和-150px,沿着X轴旋转90deg和-90deg:
/*左*/
.boxs .left{
transform: translateX(-150px) translateY(calc(var(--boxHeight) * -2)) rotateY(-90deg);
}
.boxs .left li{
background-color: #f00;
}
/*右*/
.boxs .right {
transform: translateX(150px) translateY(calc(var(--boxHeight) * -3)) rotateY(90deg);
}
.boxs .right li{
background-color: #ff0;
}
/*上*/
.boxs .top {
transform: translateY(calc(var(--boxHeight) * -4 - 150px)) rotateX(90deg);
}
.boxs .top li {
background-color: #f0f;
}
/*下*/
.boxs .bottom{
transform: translateY(calc(var(--boxHeight) * -5 + 150px)) rotateX(-90deg);
}
.boxs .bottom li{
background-color: #0ff;
}
再看下布局效果,此时就完成魔方3D布局了:
最后让它动起来:
@keyframes change {
0% {
transform: rotateX(0deg) rotateY(0deg);
}
33% {
transform: rotateX(120deg) rotateY(240deg);
}
66% {
transform: rotateX(240deg) rotateY(480deg);
}
100% {
transform: rotateX(360deg) rotateY(720deg);
}
}
.boxs {
width: 100%;
height: 100%;
transform-style: preserve-3d; /*使被转换的子元素保留其 3D 转换:*/
/*transform-origin: 10% 10%;*/ /*定义了观察者的视角相对于显示元素的位置*/
/*perspective: 500px;*/ /*设置用户与元素3d空间Z平面之间的距离*/
animation: change 10s linear infinite;
backface-visibility: hidden;
}
最后添加一个鼠标悬浮,停止旋转,用到的是animation-play-state属性:
.box:hover .boxs{
animation-play-state: paused;
}
这样就完成啦,有点小激动呢,不过好像我做的动态图没有看到鼠标...哈哈: