最近大家都在用代码写圣诞树,我也跟个风吧!
主要技术:
1.CSS3的3D变换
2.DOM动态添加节点
开发环境:vscode
目录
一.引入
二、基本知识
?1.CSS3的3D变换
(1).空间直角坐标系
(2).transform详解
(3).transform-style
2.DOM节点操作
三、 实现
1.HTML
2.CSS
3.js
4.成果
一.引入
我们是来写圣诞树的,首先必须弄到一张设计稿:
这里,我第一时间就想到了MC的云杉,因为它和圣诞树长得很像(误):这里介绍了云杉树的详细结构
?
树叶贴图:?
?
?树干贴图:
?
二、基本知识
?1.CSS3的3D变换
(1).空间直角坐标系
CSS3的空间直角坐标系如图,和数学上的不太一样:y轴正方向是竖直向下的。
?
transform是CSS3的新特性,它可以接受的参数有:translate,rotate,scale等。多个参数之间用空格隔开。
translate可以沿坐标轴平移元素且会保留原来所占的位置(类似相对定位),分为三种,分别为translateX(),translateY(),translateZ()。它们都只接受一个参数,参数必须写明单位。
这三种translate可以简化为translate3d()。以下两种写法是等价的:
.d1{
transform: translateX(200px) translateY(300px) translateZ(100px);
}
.d2{
transform: translate3d(200px,300px,100px);
}
translateZ()只有设置了perspective属性才起作用,它主要用于产生一种“近大远小”的感觉。
perspective表示视距,即观察者和屏幕的距离。而translateZ()表示物体到屏幕的距离。人的视线经过物体的边界,投射到屏幕上,形成我们所看到的像。
以下是解释透视现象的经典图片:这里的d就是perspective,z就是translateZ()。
?
?
rotate也分为三种:rotateX(),rotateY(),rotateZ()。它们也只接收一个参数,常用单位为deg(°)。还有一种rotate(),它与rotateZ()等价,即在二维平面上进行旋转。
不要使用rotate3d(),它使用前三个参数构造一个空间向量,再以这个向量为轴,按照第四个参数进行旋转。如下:
.d3 {
transform: rotate3d(1,0,0,45deg);
}
3D旋转总会碰到一个问题:角度到底是正是负?有一个“左手定则”可以解决这个问题。(大家凑合着这张图看看吧)左手握住坐标轴,大拇指指向坐标轴正方向,四指弯曲方向就是旋转角的正方向。
?
?当我们在一个transform中同时写translate和rotate属性时,建议的写法是先写translate,再写rotate,因为rotate过程中会改变坐标轴的指向,导致translate不能按预期的那样平移。
这个属性作用于父元素上,需要手动设置为preserve-3d。否则,在父元素作3D变换的过程中,子元素就会失去3D效果。
2.DOM节点操作
三、 实现
1.HTML
由于使用了动态创建节点,所以,除了引入css和js之外,无需写任何其他代码~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
<script src="tree.js"></script>
</head>
<body>
</body>
</html>
2.CSS
透视perspective定义在body中,数值越大,视角越小;
定义了一个发光动画light,用于dec的闪烁效果;
三种方块:完整大小(64*64*64)的leaves和wood,不完整(64*64*8)的snow,最小的(8*8*8)的dec;
六个面的绘制使用3d变换完成;
定义了“层”layer,因为需要分8层绘制。
* {
padding: 0;
margin: 0;
}
@keyframes light {
0% {
box-shadow: 0px 0px 4px rgb(255, 230, 0);
}
100% {
box-shadow: 0px 0px 16px rgb(255, 230, 0);
}
}
body {
position: relative;
perspective: 1500px;
background: url(bg2.jpg) no-repeat;
background-size: cover;
}
.box {
position: absolute;
height: 500px;
width: 500px;
left: 500px;
top: 600px;
}
.layer {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 200px;
transform: translateY(0);
}
.cube {
position: absolute;
display: none;
width: 100%;
height: 100%;
backface-visibility: visible;
transform-style: preserve-3d;
transform: rotateX(-30deg) rotateY(-45deg);
}
.snow {
position: absolute;
display: none;
width: 100%;
height: 100%;
backface-visibility: visible;
transform-style: preserve-3d;
transform: translateY(-8px) rotateX(-30deg) rotateY(-45deg);
}
.dec {
position: absolute;
display: none;
width: 100%;
height: 100%;
backface-visibility: visible;
transform-style: preserve-3d;
transform: translateY(-16px) rotateX(-30deg) rotateY(-45deg);
}
.face {
display: block;
position: absolute;
border: 1px solid #000;
}
.leaves .face,
.wood .face {
width: 64px;
height: 64px;
background-repeat: no-repeat;
}
.leaves .face {
background-image: url(leaf.png);
}
.wood .face {
background-image: url(wood.png);
}
.snow .face {
background-color: #eee;
height: 8px;
width: 64px;
border: none;
}
.dec .face {
background-color: orange;
height: 16px;
width: 16px;
border: none;
animation: light 2s ease-in-out infinite alternate;
}
/* Define each face based on direction */
.leaves .front,
.wood .front {
transform: translate3d(0, 0, 32px);
}
.leaves .back,
.wood .back {
transform: translate3d(0, 0, -32px) rotateY(180deg);
}
.leaves .right,
.wood .right {
transform: translate3d(32px, 0, 0) rotateY(90deg);
}
.leaves .left,
.wood .left {
transform: translate3d(-32px, 0, 0) rotateY(-90deg);
}
.leaves .top,
.wood .top {
transform: translate3d(0, -32px, 0) rotateX(90deg);
}
.leaves .bottom,
.wood .bottom {
transform: translate3d(0, 32px, 0) rotateX(-90deg);
}
/*snow faces*/
.snow .front {
transform: translate3d(0, 0, 32px);
}
.snow .back {
transform: translate3d(0, 0, -32px) rotateY(180deg);
}
.snow .right {
transform: translate3d(32px, 0, 0) rotateY(90deg);
}
.snow .left {
transform: translate3d(-32px, 0, 0) rotateY(-90deg);
}
.snow .top {
height: 64px;
transform: translate3d(0, -32px, 0) rotateX(90deg);
}
.snow .bottom {
height: 64px;
transform: translate3d(0, -24px, 0) rotateX(-90deg);
}
/*dec faces*/
.dec .front {
transform: translate3d(0, 0, 8px);
}
.dec .back {
transform: translate3d(0, 0, -8px) rotateY(180deg);
}
.dec .right {
transform: translate3d(8px, 0, 0) rotateY(90deg);
}
.dec .left {
transform: translate3d(-8px, 0, 0) rotateY(-90deg);
}
.dec .top {
transform: translate3d(0, -8px, 0) rotateX(90deg);
}
.dec .bottom {
transform: translate3d(0, 8px, 0) rotateX(-90deg);
}
3.js
设想:一层绘制完成再绘制另一层,每层绘制过程中,各个方块依次下落到待定的位置上。
由于js没有sleep这样的函数,只能用setTimeout实现,导致代码变得很难看(可是没有办法)
//prepare animate
function move(object, len, callback) {
console.log(object.offsetTop);
if (object['timer']) return;
object['timer'] = window.setInterval(function() {
//step
var velo = (len - (object.offsetTop)) / 50;
velo = velo > 0 ? Math.ceil(velo) : Math.floor(velo);
//stop
if (object.offsetTop == len) {
clearInterval(object['timer']);
object['timer'] = undefined;
if (callback) callback();
}
//move
object.style.top = object.offsetTop + velo + 'px';
console.log(object.offsetTop);
}, 5)
}
window.addEventListener('load', function() {
//initialize
var box = this.document.createElement('div');
box.className = 'box';
this.document.body.appendChild(box);
var seeds = ['face front', 'face back', 'face right', 'face left', 'face top', 'face bottom'];
//leaves
var leaves = this.document.createElement('div');
for (var i = 0; i < 6; i++) {
var temp = this.document.createElement('div');
temp.className = seeds[i];
leaves.appendChild(temp);
}
leaves.className = 'cube leaves';
//wood
var wood = this.document.createElement('div');
for (var i = 0; i < 6; i++) {
var temp = this.document.createElement('div');
temp.className = seeds[i];
wood.appendChild(temp);
}
wood.className = 'cube wood';
//snow
var snow = this.document.createElement('div');
for (var i = 0; i < 6; i++) {
var temp = this.document.createElement('div');
temp.className = seeds[i];
snow.appendChild(temp);
}
snow.className = 'snow';
//decs
var dec = document.createElement('div');
for (var i = 0; i < 6; i++) {
var temp = this.document.createElement('div');
temp.className = seeds[i];
dec.appendChild(temp);
}
dec.className = 'dec';
window.addEventListener('click', function() {
//layer 1
var layer1 = this.document.createElement('div');
layer1.className = 'layer';
layer1.appendChild(wood.cloneNode(true));
box.appendChild(layer1);
layer1.children[0].style.display = 'block';
move(layer1.children[0], 200);
setTimeout(function() {
//layer 2
var layer2 = this.document.createElement('div');
layer2.className = 'layer';
layer2.style.transform = 'translateY(-64px)'
for (var i = -192; i <= 192; i += 64) {
for (var j = -192; j <= 192; j += 64) {
var temp;
if (i == 0 && j == 0) {
temp = wood.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer2.appendChild(temp);
} else if ((Math.abs(i) == 192 && Math.abs(j) != 192) || (Math.abs(i) != 192 && Math.abs(j) == 192)) {
//leave
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px)';
layer2.appendChild(temp);
//snow
temp = snow.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) translateY(-8px) ';
layer2.appendChild(temp);
} else if (Math.abs(i) <= 128 && Math.abs(j) <= 128) {
//leaves
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer2.appendChild(temp);
if (Math.abs(i) == 128 && Math.abs(j) == 128) {
//snow
temp = snow.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) translateY(-8px) ';
layer2.appendChild(temp);
}
}
}
}
box.appendChild(layer2);
var index2 = 0;
setTimeout(function rec() {
if (index2 == layer2.children.length) {
return;
}
layer2.children[index2].style.display = 'block';
move(layer2.children[index2], 200);
index2++;
setTimeout(rec, 100);
}, 50);
setTimeout(function() {
//layer 3
var layer3 = this.document.createElement('div');
layer3.className = 'layer';
layer3.style.transform = 'translateY(-128px)'
for (var i = -128; i <= 128; i += 64) {
for (var j = -128; j <= 128; j += 64) {
var temp;
if (i == 0 && j == 0) {
temp = wood.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer3.appendChild(temp);
} else if ((Math.abs(i) == 128 && Math.abs(j) != 128) || (Math.abs(i) != 128 && Math.abs(j) == 128)) {
//leave
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px)';
layer3.appendChild(temp);
//snow
temp = snow.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) translateY(-8px) ';
layer3.appendChild(temp);
} else if (Math.abs(i) <= 64 && Math.abs(j) <= 64) {
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer3.appendChild(temp);
}
}
}
box.appendChild(layer3);
var index3 = 0;
setTimeout(function rec() {
if (index3 == layer3.children.length) {
return;
}
layer3.children[index3].style.display = 'block';
move(layer3.children[index3], 200);
index3++;
setTimeout(rec, 100);
}, 50);
setTimeout(function() {
//layer 4
var layer4 = this.document.createElement('div');
layer4.className = 'layer';
layer4.style.transform = 'translateY(-192px)'
for (var i = -64; i <= 64; i += 64) {
for (var j = -64; j <= 64; j += 64) {
var temp;
if (i == 0 && j == 0) {
temp = wood.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer4.appendChild(temp);
} else if ((Math.abs(i) == 64 && Math.abs(j) != 64) || (Math.abs(i) != 64 && Math.abs(j) == 64)) {
//leave
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px)';
layer4.appendChild(temp);
}
}
}
box.appendChild(layer4);
var index4 = 0;
setTimeout(function rec() {
if (index4 == layer4.children.length) {
return;
}
layer4.children[index4].style.display = 'block';
move(layer4.children[index4], 200);
index4++;
setTimeout(rec, 100);
}, 50);
setTimeout(function() {
//layer 5
var layer5 = this.document.createElement('div');
layer5.className = 'layer';
layer5.style.transform = 'translateY(-256px)'
for (var i = -128; i <= 128; i += 64) {
for (var j = -128; j <= 128; j += 64) {
var temp;
if (i == 0 && j == 0) {
temp = wood.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer5.appendChild(temp);
} else if ((Math.abs(i) == 128 && Math.abs(j) != 128) || (Math.abs(i) != 128 && Math.abs(j) == 128)) {
//leave
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px)';
layer5.appendChild(temp);
//snow
temp = snow.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) translateY(-8px) ';
layer5.appendChild(temp);
} else if (Math.abs(i) <= 64 && Math.abs(j) <= 64) {
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer5.appendChild(temp);
if (Math.abs(i) == 64 && Math.abs(j) == 64) {
//snow
temp = snow.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) translateY(-8px) ';
layer5.appendChild(temp);
}
}
}
}
box.appendChild(layer5);
var index5 = 0;
setTimeout(function rec() {
if (index5 == layer5.children.length) {
return;
}
layer5.children[index5].style.display = 'block';
move(layer5.children[index5], 200);
index5++;
setTimeout(rec, 100);
}, 50);
setTimeout(function() {
//layer 6
var layer6 = this.document.createElement('div');
layer6.className = 'layer';
layer6.style.transform = 'translateY(-320px)'
for (var i = -64; i <= 64; i += 64) {
for (var j = -64; j <= 64; j += 64) {
var temp;
if (i == 0 && j == 0) {
temp = wood.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer6.appendChild(temp);
} else if ((Math.abs(i) == 64 && Math.abs(j) != 64) || (Math.abs(i) != 64 && Math.abs(j) == 64)) {
//leave
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px)';
layer6.appendChild(temp);
}
}
}
box.appendChild(layer6);
var index6 = 0;
setTimeout(function rec() {
if (index6 == layer6.children.length) {
return;
}
layer6.children[index6].style.display = 'block';
move(layer6.children[index6], 200);
index6++;
setTimeout(rec, 100);
}, 50);
setTimeout(function() {
//layer 7
var layer7 = this.document.createElement('div');
layer7.className = 'layer';
layer7.style.transform = 'translateY(-384px)'
var temp7 = wood.cloneNode(true);
temp7.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(0) translateZ(0) ';
layer7.appendChild(temp7);
box.appendChild(layer7);
layer7.children[0].style.display = 'block';
move(layer7.children[0], 200);
setTimeout(function() {
//layer 8
var layer8 = this.document.createElement('div');
layer8.className = 'layer';
layer8.style.transform = 'translateY(-448px)'
for (var i = -64; i <= 64; i += 64) {
for (var j = -64; j <= 64; j += 64) {
var temp;
if (i == 0 && j == 0) {
//leave
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) ';
layer8.appendChild(temp);
//snow
temp = snow.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) translateY(-8px) ';
layer8.appendChild(temp);
} else if ((Math.abs(i) == 64 && Math.abs(j) != 64) || (Math.abs(i) != 64 && Math.abs(j) == 64)) {
//leave
temp = leaves.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px)';
layer8.appendChild(temp);
//snow
temp = snow.cloneNode(true);
temp.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(' + i + 'px) translateZ(' + j + 'px) translateY(-8px) ';
layer8.appendChild(temp);
}
}
}
box.appendChild(layer8);
var index8 = 0;
setTimeout(function rec() {
if (index8 == layer8.children.length) {
return;
}
layer8.children[index8].style.display = 'block';
move(layer8.children[index8], 200);
index8++;
setTimeout(rec, 100);
}, 50);
setTimeout(function() {
//decoration
var arr;
var dec1 = dec.cloneNode(true);
dec1.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(400px) translateZ(400px) translateY(-16px)';
layer2.appendChild(dec1);
var dec1_1 = dec.cloneNode(true);
dec1_1.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(234px) translateZ(424px) translateY(-16px)';
layer2.appendChild(dec1_1);
var dec2 = dec.cloneNode(true);
dec2.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(178px) translateZ(356px) translateY(-16px)';
layer3.appendChild(dec2);
var dec2_1 = dec.cloneNode(true);
dec2_1.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(419px) translateZ(378px) translateY(-54px)';
layer3.appendChild(dec2_1);
var dec2_2 = dec.cloneNode(true);
dec2_2.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(435px) translateZ(161px) translateY(-54px)';
layer3.appendChild(dec2_2);
var dec3 = dec.cloneNode(true);
dec3.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(327px) translateZ(384px) translateY(-16px)';
layer5.appendChild(dec3);
var dec4 = dec.cloneNode(true);
dec4.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(236px) translateZ(295px) translateY(-16px)';
layer6.appendChild(dec4);
var dec5 = dec.cloneNode(true);
dec5.style.transform = 'rotateX(-30deg) rotateY(-45deg) translateX(406px) translateZ(282px) translateY(-16px)';
layer7.appendChild(dec5);
var arr = [];
arr.push(dec1);
arr.push(dec1_1);
arr.push(dec2);
arr.push(dec2_1);
arr.push(dec2_2);
arr.push(dec3);
arr.push(dec4);
arr.push(dec5);
var index9 = 0;
setTimeout(function rec() {
if (index9 == arr.length) {
return;
}
console.log(index9);
arr[index9].style.display = 'block';
index9++;
setTimeout(rec, 200);
}, 50)
}, 2000)
}, 20)
}, 500)
}, 3000)
}, 600)
}, 3000)
}, 5000)
}, 50)
})
})
4.成果
单击浏览器窗口,运行程序:
?
?最后,祝所有与CSDN同行的代码人们:节日快乐哦!
|