文章目录
- 圣诞节的起源
- 圣诞祝福语
- 用 coding 说圣诞快乐
- Canvas 渲染 圣诞树特效
- 唯美圣诞树
- CSS实现圣诞树
- 简易的圣诞树
- 线性树
- 卡片圣诞树
🎄🎄🎄圣诞节即将到来,今天让我们用编码的方式向你最爱的人表达圣诞节快乐
圣诞节的起源
圣诞节源自古罗马人迎接新年的农神节,与基督教本无关系。在基督教盛行罗马帝国后,教廷将这种民俗节日纳入基督教体系,同时以庆祝耶稣的降生。但在圣诞节这天不是耶稣的生辰,因为《圣经》未记载耶稣具体出生时间,同样没提到过有此种节日,是基督教吸收了古罗马神话的结果。
圣诞节是西方传统节日,也是许多西方国家一年中最重要的节日。每年这一天,欢快的圣诞歌在大街小巷飘扬,商场里流光溢彩,琳琅满目,到处弥漫着温馨欢乐的气息。孩子们在甜美的梦乡中,盼望着圣诞老人从天而降,带来梦寐以求的礼物。
平安夜和圣诞节现在很多人都在过,对于很多人而言,并不是在做一个所谓的洋节,而是在这一天让自己爱的人和爱我们的人开心,正如网络上流行的一句话:“ 世界上本没有圣诞老人,所有的惊喜和礼物都来自于爱你的人。 ”
圣诞祝福语
🎄 Merry Christmas
🎄今年圣诞老人🎅🏻也很忙喔
所以轮到我把圣诞惊喜给你咯!
🎄今天扎了个蝴蝶结,像不像你的圣诞礼物。
圣诞节没有领到礼物的到我这里领个37°的拥抱吧🎅🏻
🎄蟹蟹圣诞老公公,送礼全世界最棒的礼物给我,就是把你放进我心里。
麋鹿不会迷路,圣诞之礼,终将准时送达。🎅🏻
多少人,一夜之间,没穿圣诞装,却成了圣诞老人。🎅🏻
把我的小心思,偷偷塞进礼物盒,在圣诞节那一天,通通送给你
圣诞有我,要开心哦(• . •)
我想和你一起看夜景 一起吃热热的烤火鸡 一起许愿 看着那会发光的圣诞树 一起倒数
你快跳进圣诞老人的背包里 一觉醒来你就是我的礼物
想给每个善良的人一顶圣诞帽 愿这顶帽子成为他们的睡帽 从此每个安睡的日子都叫平安夜
希望圣诞树 和你一起到来🎄
圣诞快乐,喜乐长安。🎄
用 coding 说圣诞快乐
Canvas 渲染 圣诞树特效
index.html
<!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>ChristmasTree</title>
<style>
html,
body {
margin: 0;
width: 100%;
height: 100%
}
body {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: black;
position: relative;
overflow-x: hidden;
overflow-y: hidden;
}
.snow-container {
position: absolute;
width: 400px;
height: 550px;
color: white;
}
@media screen and (max-width: 450px) {
.snow-container {
width: 100%;
}
}
.snow-box {
position: relative;
width: 100%;
height: 100%;
}
.snow {
position: absolute;
animation: 5s snow linear infinite;
}
@keyframes snow {
0% {
left: 0;
top: 0
}
80% {
top: 90%
}
100% {
top: 90%
}
}
.snow2 {
left: 5%;
top: 2%;
position: absolute;
animation: 10s snow2 ease-in infinite;
}
@keyframes snow2 {
0% {
left: 5%;
top: 2%;
}
80% {
top: 90%
}
100% {
top: 90%
}
}
.snow3 {
left: 10%;
top: 8%;
position: absolute;
animation: 8s snow3 ease-out infinite;
}
@keyframes snow3 {
0% {
left: 5%;
top: 2%;
}
80% {
top: 90%
}
100% {
top: 90%
}
}
.snow4 {
left: 18%;
top: 18%;
position: absolute;
animation: 7s snow4 ease-out infinite;
}
@keyframes snow4 {
0% {
left: 18%;
top: 18%;
}
80% {
top: 90%
}
100% {
top: 90%
}
}
.snow5 {
left: 59%;
top: 1%;
position: absolute;
animation: 6s snow4 ease infinite;
}
@keyframes snow5 {
0% {
left: 75%;
top: 18%;
}
80% {
top: 90%
}
100% {
top: 90%
}
}
.snow6 {
left: 65%;
top: 5%;
position: absolute;
animation: 6s snow6 ease-in infinite;
}
@keyframes snow6 {
0% {
left: 75%;
top: 18%;
}
80% {
top: 90%
}
100% {
top: 90%
}
}
.snow7 {
left: 75%;
top: 18%;
position: absolute;
animation: 11s snow5 ease infinite;
}
@keyframes snow7 {
0% {
left: 75%;
top: 18%;
}
80% {
top: 90%
}
100% {
top: 90%
}
}
.snow8 {
left: 90%;
top: 40%;
position: absolute;
animation: 5s snow8 ease-out infinite;
}
@keyframes snow8 {
0% {
left: 90%;
top: 20%;
}
80% {
top: 90%
}
100% {
top: 90%
}
}
.snow9 {
left: 50%;
top: 10%;
position: absolute;
animation: 5s snow9 ease-out infinite;
}
@keyframes snow9 {
0% {
left: 85%;
top: 20%;
}
80% {
left: 50%;
top: 90%
}
100% {
top: 90%
}
}
.snow10 {
left: 100%;
top: 10%;
position: absolute;
animation: 7s snow10 ease infinite;
}
@keyframes snow10 {
0% {
left: 100%;
top: 10%;
}
80% {
left: 50%;
top: 90%
}
100% {
left: 50%;
top: 90%
}
}
.text {
font-size: 40px;
color: #f1ebe5;
text-shadow: 0 8px 9px #c4b59d, 0px -2px 1px #fff;
font-weight: bold;
letter-spacing: 2px;
text-align: center;
position: absolute;
white-space: nowrap;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div class="snow-container">
<div class="snow-box">
<span class="snow">*</span>
<span class="snow2">*</span>
<span class="snow3">*</span>
<span class="snow4">*</span>
<span class="snow5">*</span>
<span class="snow6">*</span>
<span class="snow7">*</span>
<span class="snow8">*</span>
<span class="snow9">*</span>
<span class="snow10">*</span>
</div>
<div class="text">鱼找水的🎄</div>
</div>
<canvas id="canvas" width="375" height="500"></canvas>
<script src="./assets/index.js">
</script>
<script>
new ChristmasTree().renderTree()
</script>
</body>
</html>
index.js
class ChristmasTree {
constructor() {
this.side = 20
this.gap = 6 + this.side
this.init()
this.treeData = []
}
init() {
this.canvas = document.querySelector('#canvas')
this.ctx = this.canvas.getContext('2d')
const { width, height } = this.canvas
this.width = width
this.height = height
this.ctx.fillStyle = 'rgb(0, 0, 0)'
this.ctx.fillRect(0, 0, width, height)
}
createArc(x, y, color) {
this.ctx.beginPath()
this.ctx.fillStyle = color
this.ctx.arc(x, y, this.side / 2, 0, Math.PI * 2, false)
this.ctx.fill()
}
createRect(x, y, color) {
this.ctx.fillStyle = color
this.ctx.fillRect(x, y, this.side, this.side)
}
createPentastar(x, y, color) {
this.ctx.beginPath()
const R = this.gap / 2,
r = this.gap / 5
for (var i = 0; i < 5; i++) {
this.ctx.lineTo(
Math.cos(((18 + i * 72) / 180) * Math.PI) * R + x, -Math.sin(((18 + i * 72) / 180) * Math.PI) * R + y
)
this.ctx.lineTo(
Math.cos(((54 + i * 72) / 180) * Math.PI) * r + x, -Math.sin(((54 + i * 72) / 180) * Math.PI) * r + y
)
}
this.ctx.closePath()
this.ctx.lineWidth = '3'
this.ctx.fillStyle = color
this.ctx.fill()
}
buildTreeCrown(startNodeNum, rowsNum, startHeight) {
const arr = []
const midRect = this.width / 2 - this.side / 2
const midArc = this.width / 2
for (let i = 0; i < rowsNum; i++) {
for (let j = 0; j < startNodeNum; j++) {
if (rowsNum - i === 2 && startNodeNum - j <= 2) {
arr.push({
type: 'start',
x: midArc + (j % 2 === 0 ? (-this.gap * j) / 2 : (+(j + 1) / 2) * this.gap),
y: startHeight + this.gap * i + this.side / 2,
color: rowsNum - i === 1 ? 'red' : 'yellow'
})
} else if (rowsNum - i === 1 && startNodeNum - j <= 2) {
arr.push({
type: 'arc',
x: midArc + (j % 2 === 0 ? (-this.gap * j) / 2 : (+(j + 1) / 2) * this.gap),
y: startHeight + this.gap * i + this.side / 2,
color: 'red'
})
} else {
arr.push({
type: 'rect',
x: midRect + (j % 2 === 0 ? (-this.gap * j) / 2 : (+(j + 1) / 2) * this.gap),
y: startHeight + this.gap * i,
color: i === rowsNum - 1 && startNodeNum - j >= 7 ? 'red' : 'green'
})
}
}
if (i === rowsNum - 3) {
startNodeNum += 4
} else {
startNodeNum += 2
}
}
return arr
}
buildTreeStump(row, col, gapRow) {
const arr = []
const midRect = this.width / 2 - this.side / 2
for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
arr.push({
type: 'rect',
x: midRect + (j % 2 === 0 ? (-this.gap * j) / 2 : (+(j + 1) / 2) * this.gap),
y: (gapRow + i) * this.gap,
color: 'rgb(67, 11, 0)'
})
}
}
return arr
}
setTreeData() {
const _this = this
let gapRow = 1
this.treeData = [{
type: 'start',
x: this.width / 2,
y: this.side / 2 + 2,
color: 'yellow'
},
...setTreeCrownData(3),
...this.buildTreeStump(5, 3, gapRow)
]
function setTreeCrownData(crownNum) {
const arr = []
let indexNode = 1
let rowsNum = 4
for (let i = 0; i < crownNum; i++) {
arr.push(..._this.buildTreeCrown(indexNode, rowsNum, _this.gap * gapRow))
indexNode += 2
gapRow += rowsNum
}
return arr
}
}
renderTree() {
this.setTreeData()
for (const item of this.treeData) {
if (item.type === 'arc') {
const { x, y, color } = item
this.createArc(x, y, color)
} else if (item.type === 'rect') {
const { x, y, color } = item
this.createRect(x, y, color)
} else if (item.type === 'start') {
const { x, y, color } = item
this.createPentastar(x, y, color)
}
}
}
}
唯美圣诞树
在线演示,加载比较慢
里边用到的音乐自己下载,修改变量const files
为对应mp3
的路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Musical Christmas Lights</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: #161616;
color: #c5a880;
font-family: sans-serif;
}
label {
display: inline-block;
background-color: #161616;
padding: 16px;
border-radius: 0.3rem;
cursor: pointer;
margin-top: 1rem;
width: 300px;
border-radius: 10px;
border: 1px solid #c5a880;
text-align: center;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
.btn {
background-color: #161616;
border-radius: 10px;
color: #c5a880;
border: 1px solid #c5a880;
padding: 16px;
width: 300px;
margin-bottom: 16px;
line-height: 1.5;
cursor: pointer;
}
.separator {
font-weight: bold;
text-align: center;
width: 300px;
margin: 16px 0px;
color: #a07676;
}
.title {
color: #a07676;
font-weight: bold;
font-size: 1.25rem;
margin-bottom: 16px;
}
.text-loading {
font-size: 2rem;
}
#tree-text {
position: absolute;
top: 18vh;
width: 100vw;
line-height: 5vh;
text-align: center;
color: #fab1a0;
font-size: x-large;
font-family: "Lucida Console", "Courier New", monospace;
opacity: 1;
font-weight: bold;
color: transparent;
background: linear-gradient(45deg, #fab1a0 35%, #ff7675, #e17055 60%);
background-size: cover;
-webkit-background-clip: text;
-ms-background-clip: text;
-moz-background-clip: text;
-o-background-clip: text;
}
@keyframes gradually-appear {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.show {
display: block;
animation-name: gradually-appear;
animation-duration: 8s;
}
.hide {
display: none;
}
</style>
<script>
window.console = window.console || function (t) { };
</script>
<script>
if (document.location.search.match(/type=embed/gi)) {
window.parent.postMessage("resize", "*");
}
</script>
</head>
<body translate="no">
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/ShaderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/shaders/CopyShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/shaders/LuminosityHighPassShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/UnrealBloomPass.js"></script>
<div id="overlay">
<ul>
<li class="title">宝贝,选一首喜欢的歌吧</li>
<li>
<button class="btn" id="btnA" type="button">
Snowflakes Falling Down by Simon Panrucker
</button>
</li>
<li><button class="btn" id="btnB" type="button">This Christmas by Dott</button></li>
<li><button class="btn" id="btnC" type="button">No room at the inn by TRG Banks</button></li>
<li><button class="btn" id="btnD" type="button">Jingle Bell Swing by Mark Smeby</button></li>
<li style="display: none;" class="separator">或者</li>
<li style="display: none;">
<input type="file" id="upload" hidden />
<label for="upload">Upload File</label>
</li>
</ul>
</div>
<div id="tree-text" class="hide">
祝我最爱的girl圣诞节快乐
<br />
希望能与你度过以后的每一个圣诞节,I ❤️ you~
</div>
<script id="rendered-js">
const { PI, sin, cos } = Math;
const TAU = 2 * PI;
const map = (value, sMin, sMax, dMin, dMax) => {
return dMin + (value - sMin) / (sMax - sMin) * (dMax - dMin);
};
const range = (n, m = 0) =>
Array(n).
fill(m).
map((i, j) => i + j);
const rand = (max, min = 0) => min + Math.random() * (max - min);
const randInt = (max, min = 0) => Math.floor(min + Math.random() * (max - min));
const randChoise = arr => arr[randInt(arr.length)];
const polar = (ang, r = 1) => [r * cos(ang), r * sin(ang)];
let scene, camera, renderer, analyser;
let step = 0;
const uniforms = {
time: { type: "f", value: 0.0 },
step: { type: "f", value: 0.0 }
};
const params = {
exposure: 1,
bloomStrength: 0.9,
bloomThreshold: 0,
bloomRadius: 0.5
};
let composer;
const fftSize = 2048;
const totalPoints = 4000;
const listener = new THREE.AudioListener();
const audio = new THREE.Audio(listener);
document.querySelector("input").addEventListener("change", uploadAudio, false);
const buttons = document.querySelectorAll(".btn");
buttons.forEach((button, index) =>
button.addEventListener("click", () => loadAudio(index)));
function init() {
const overlay = document.getElementById("overlay");
overlay.remove();
document.getElementById("tree-text").className = "show";
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
1,
1000);
camera.position.set(-0.09397456774197047, -2.5597086635726947, 24.420789670889008);
camera.rotation.set(0.10443543723052419, -0.003827152981119352, 0.0004011488708739715);
const format = renderer.capabilities.isWebGL2 ?
THREE.RedFormat :
THREE.LuminanceFormat;
uniforms.tAudioData = {
value: new THREE.DataTexture(analyser.data, fftSize / 2, 1, format)
};
addPlane(scene, uniforms, 3000);
addSnow(scene, uniforms);
range(10).map(i => {
addTree(scene, uniforms, totalPoints, [20, 0, -20 * i]);
addTree(scene, uniforms, totalPoints, [-20, 0, -20 * i]);
});
const renderScene = new THREE.RenderPass(scene, camera);
const bloomPass = new THREE.UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5,
0.4,
0.85);
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;
composer = new THREE.EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
addListners(camera, renderer, composer);
animate();
}
function animate(time) {
analyser.getFrequencyData();
uniforms.tAudioData.value.needsUpdate = true;
step = (step + 1) % 1000;
uniforms.time.value = time;
uniforms.step.value = step;
composer.render();
requestAnimationFrame(animate);
}
function loadAudio(i) {
document.getElementById("overlay").innerHTML =
'<div class="text-loading">正在下载音乐,请稍等...</div>';
// const files = [
// "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/no_curator/Simon_Panrucker/Happy_Christmas_You_Guys/Simon_Panrucker_-_01_-_Snowflakes_Falling_Down.mp3",
// "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/no_curator/Dott/This_Christmas/Dott_-_01_-_This_Christmas.mp3",
// "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/ccCommunity/TRG_Banks/TRG_Banks_Christmas_Album/TRG_Banks_-_12_-_No_room_at_the_inn.mp3",
// "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/ccCommunity/Mark_Smeby/En_attendant_Nol/Mark_Smeby_-_07_-_Jingle_Bell_Swing.mp3"];
const files = ["./music/Simon_Panrucker_-_01_-_Snowflakes_Falling_Down.mp3",
"./music/Dott_-_01_-_This_Christmas.mp3",
"./music/TRG_Banks_-_12_-_No_room_at_the_inn.mp3",
"./music/Mark_Smeby_-_07_-_Jingle_Bell_Swing.mp3"];
const file = files[i];
const loader = new THREE.AudioLoader();
loader.load(file, function (buffer) {
audio.setBuffer(buffer);
audio.play();
analyser = new THREE.AudioAnalyser(audio, fftSize);
init();
});
}
function uploadAudio(event) {
document.getElementById("overlay").innerHTML =
'<div class="text-loading">请稍等...</div>';
const files = event.target.files;
const reader = new FileReader();
reader.onload = function (file) {
var arrayBuffer = file.target.result;
listener.context.decodeAudioData(arrayBuffer, function (audioBuffer) {
audio.setBuffer(audioBuffer);
audio.play();
analyser = new THREE.AudioAnalyser(audio, fftSize);
init();
});
};
reader.readAsArrayBuffer(files[0]);
}
function addTree(scene, uniforms, totalPoints, treePosition) {
const vertexShader = `
attribute float mIndex;
varying vec3 vColor;
varying float opacity;
uniform sampler2D tAudioData;
float norm(float value, float min, float max ){
return (value - min) / (max - min);
}
float lerp(float norm, float min, float max){
return (max - min) * norm + min;
}
float map(float value, float sourceMin, float sourceMax, float destMin, float destMax){
return lerp(norm(value, sourceMin, sourceMax), destMin, destMax);
}
void main() {
vColor = color;
vec3 p = position;
vec4 mvPosition = modelViewMatrix * vec4( p, 1.0 );
float amplitude = texture2D( tAudioData, vec2( mIndex, 0.1 ) ).r;
float amplitudeClamped = clamp(amplitude-0.4,0.0, 0.6 );
float sizeMapped = map(amplitudeClamped, 0.0, 0.6, 1.0, 20.0);
opacity = map(mvPosition.z , -200.0, 15.0, 0.0, 1.0);
gl_PointSize = sizeMapped * ( 100.0 / -mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader = `
varying vec3 vColor;
varying float opacity;
uniform sampler2D pointTexture;
void main() {
gl_FragColor = vec4( vColor, opacity );
gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
}
`;
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
...uniforms,
pointTexture: {
value: new THREE.TextureLoader().load(`https://assets.codepen.io/3685267/spark1.png`)
}
},
vertexShader,
fragmentShader,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true,
vertexColors: true
});
const geometry = new THREE.BufferGeometry();
const positions = [];
const colors = [];
const sizes = [];
const phases = [];
const mIndexs = [];
const color = new THREE.Color();
for (let i = 0; i < totalPoints; i++) {
const t = Math.random();
const y = map(t, 0, 1, -8, 10);
const ang = map(t, 0, 1, 0, 6 * TAU) + TAU / 2 * (i % 2);
const [z, x] = polar(ang, map(t, 0, 1, 5, 0));
const modifier = map(t, 0, 1, 1, 0);
positions.push(x + rand(-0.3 * modifier, 0.3 * modifier));
positions.push(y + rand(-0.3 * modifier, 0.3 * modifier));
positions.push(z + rand(-0.3 * modifier, 0.3 * modifier));
color.setHSL(map(i, 0, totalPoints, 1.0, 0.0), 1.0, 0.5);
colors.push(color.r, color.g, color.b);
phases.push(rand(1000));
sizes.push(1);
const mIndex = map(i, 0, totalPoints, 1.0, 0.0);
mIndexs.push(mIndex);
}
geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3).setUsage(
THREE.DynamicDrawUsage));
geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
geometry.setAttribute("size", new THREE.Float32BufferAttribute(sizes, 1));
geometry.setAttribute("phase", new THREE.Float32BufferAttribute(phases, 1));
geometry.setAttribute("mIndex", new THREE.Float32BufferAttribute(mIndexs, 1));
const tree = new THREE.Points(geometry, shaderMaterial);
const [px, py, pz] = treePosition;
tree.position.x = px;
tree.position.y = py;
tree.position.z = pz;
scene.add(tree);
}
function addSnow(scene, uniforms) {
const vertexShader = `
attribute float size;
attribute float phase;
attribute float phaseSecondary;
varying vec3 vColor;
varying float opacity;
uniform float time;
uniform float step;
float norm(float value, float min, float max ){
return (value - min) / (max - min);
}
float lerp(float norm, float min, float max){
return (max - min) * norm + min;
}
float map(float value, float sourceMin, float sourceMax, float destMin, float destMax){
return lerp(norm(value, sourceMin, sourceMax), destMin, destMax);
}
void main() {
float t = time* 0.0006;
vColor = color;
vec3 p = position;
p.y = map(mod(phase+step, 1000.0), 0.0, 1000.0, 25.0, -8.0);
p.x += sin(t+phase);
p.z += sin(t+phaseSecondary);
opacity = map(p.z, -150.0, 15.0, 0.0, 1.0);
vec4 mvPosition = modelViewMatrix * vec4( p, 1.0 );
gl_PointSize = size * ( 100.0 / -mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader = `
uniform sampler2D pointTexture;
varying vec3 vColor;
varying float opacity;
void main() {
gl_FragColor = vec4( vColor, opacity );
gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
}
`;
function createSnowSet(sprite) {
const totalPoints = 300;
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
...uniforms,
pointTexture: {
value: new THREE.TextureLoader().load(sprite)
}
},
vertexShader,
fragmentShader,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true,
vertexColors: true
});
const geometry = new THREE.BufferGeometry();
const positions = [];
const colors = [];
const sizes = [];
const phases = [];
const phaseSecondaries = [];
const color = new THREE.Color();
for (let i = 0; i < totalPoints; i++) {
const [x, y, z] = [rand(25, -25), 0, rand(15, -150)];
positions.push(x);
positions.push(y);
positions.push(z);
color.set(randChoise(["#f1d4d4", "#f1f6f9", "#eeeeee", "#f1f1e8"]));
colors.push(color.r, color.g, color.b);
phases.push(rand(1000));
phaseSecondaries.push(rand(1000));
sizes.push(rand(4, 2));
}
geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3));
geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
geometry.setAttribute("size", new THREE.Float32BufferAttribute(sizes, 1));
geometry.setAttribute("phase", new THREE.Float32BufferAttribute(phases, 1));
geometry.setAttribute(
"phaseSecondary",
new THREE.Float32BufferAttribute(phaseSecondaries, 1));
const mesh = new THREE.Points(geometry, shaderMaterial);
scene.add(mesh);
}
const sprites = [
"https://assets.codepen.io/3685267/snowflake1.png",
"https://assets.codepen.io/3685267/snowflake2.png",
"https://assets.codepen.io/3685267/snowflake3.png",
"https://assets.codepen.io/3685267/snowflake4.png",
"https://assets.codepen.io/3685267/snowflake5.png"];
sprites.forEach(sprite => {
createSnowSet(sprite);
});
}
function addPlane(scene, uniforms, totalPoints) {
const vertexShader = `
attribute float size;
attribute vec3 customColor;
varying vec3 vColor;
void main() {
vColor = customColor;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( 300.0 / -mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader = `
uniform vec3 color;
uniform sampler2D pointTexture;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( vColor, 1.0 );
gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
}
`;
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
...uniforms,
pointTexture: {
value: new THREE.TextureLoader().load(`https://assets.codepen.io/3685267/spark1.png`)
}
},
vertexShader,
fragmentShader,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true,
vertexColors: true
});
const geometry = new THREE.BufferGeometry();
const positions = [];
const colors = [];
const sizes = [];
const color = new THREE.Color();
for (let i = 0; i < totalPoints; i++) {
const [x, y, z] = [rand(-25, 25), 0, rand(-150, 15)];
positions.push(x);
positions.push(y);
positions.push(z);
color.set(randChoise(["#93abd3", "#f2f4c0", "#9ddfd3"]));
colors.push(color.r, color.g, color.b);
sizes.push(1);
}
geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3).setUsage(
THREE.DynamicDrawUsage));
geometry.setAttribute(
"customColor",
new THREE.Float32BufferAttribute(colors, 3));
geometry.setAttribute("size", new THREE.Float32BufferAttribute(sizes, 1));
const plane = new THREE.Points(geometry, shaderMaterial);
plane.position.y = -8;
scene.add(plane);
}
function addListners(camera, renderer, composer) {
document.addEventListener("keydown", e => {
const { x, y, z } = camera.position;
console.log(`camera.position.set(${x},${y},${z})`);
const { x: a, y: b, z: c } = camera.rotation;
console.log(`camera.rotation.set(${a},${b},${c})`);
});
window.addEventListener(
"resize",
() => {
const width = window.innerWidth;
const height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
composer.setSize(width, height);
},
false);
}
</script>
</body>
</html>
CSS实现圣诞树
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width= , initial-scale=1.0">
<title>圣诞树</title>
<!-- <link rel="stylesheet" href="index.css"> -->
<style>
html,
body {
width: 100%;
height: 100%;
}
* {
margin: 0;
padding: 0;
}
body {
background-color: #020024;
}
.word {
font-size: 22px;
text-align: center;
color: gold;
padding-top: 50px;
letter-spacing: 5px;
text-shadow: 2px 4px 9px rgba(255, 255, 255, 0.7);
}
/* 圣诞树外层div */
.tree {
width: 200px;
height: 300px;
margin: 80px auto 0 auto;
position: relative;
/*相对定位*/
/* border: 1px solid #fff; */
}
.star {
width: 50px;
height: 50px;
position: absolute;
background-color: #fff;
border-radius: 50%;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
-ms-border-radius: 50%;
-o-border-radius: 50%;
top: -25px;
z-index: 1000;
left: 50%;
transform: translate(-50%);
-webkit-transform: translate(-50%);
-moz-transform: translate(-50%);
-ms-transform: translate(-50%);
-o-transform: translate(-50%);
animation: starLight 1.5s ease infinite alternate;
-webkit-animation: starLight 1.5s ease infinite alternate;
}
.star-in {
position: absolute;
left: 50%;
top: 50%;
border-right: 100px solid transparent;
border-bottom: 70px solid gold;
border-left: 100px solid transparent;
transform: translateX(-50%) translateY(-50%) rotate(35deg) scale(0.14);
-webkit-transform: translateX(-50%) translateY(-50%) rotate(35deg) scale(0.14);
-moz-transform: translateX(-50%) translateY(-50%) rotate(35deg) scale(0.14);
-ms-transform: translateX(-50%) translateY(-50%) rotate(35deg) scale(0.14);
-o-transform: translateX(-50%) translateY(-50%) rotate(35deg) scale(0.14);
}
.star-in::before {
border-right: 30px solid transparent;
border-bottom: 80px solid gold;
border-left: 30px solid transparent;
position: absolute;
top: -45px;
left: -65px;
content: '';
transform: rotate(-35deg);
-webkit-transform: rotate(-35deg);
-moz-transform: rotate(-35deg);
-ms-transform: rotate(-35deg);
-o-transform: rotate(-35deg);
}
.star-in::after {
border-right: 100px solid transparent;
border-bottom: 70px solid gold;
border-left: 100px solid transparent;
position: absolute;
top: 3px;
left: -105px;
content: '';
transform: rotate(-70deg);
-webkit-transform: rotate(-70deg);
-moz-transform: rotate(-70deg);
-ms-transform: rotate(-70deg);
-o-transform: rotate(-70deg);
}
@keyframes starLight {
0% {
background: radial-gradient(ellipse at center,
gold 0%,
rgba(255, 240, 158, 0.5)42%,
rgba(255, 242, 173, 0.2)58%,
rgba(255, 255, 255, 0.1)100%);
}
25% {
background: radial-gradient(ellipse at center,
gold 0%,
rgba(255, 240, 158, 0.5)40%,
rgba(255, 242, 173, 0.2)60%,
rgba(255, 255, 255, 0.1)100%);
}
50% {
background: radial-gradient(ellipse at center,
gold 0%,
rgba(255, 240, 158, 0.5)38%,
rgba(255, 242, 173, 0.2)62%,
rgba(255, 255, 255, 0.1)100%);
}
75% {
background: radial-gradient(ellipse at center,
gold 0%,
rgba(255, 240, 158, 0.5)36%,
rgba(255, 242, 173, 0.2)64%,
rgba(255, 255, 255, 0.1)100%);
}
100% {
background: radial-gradient(ellipse at center,
gold 0%,
rgba(255, 240, 158, 0.5)34%,
rgba(255, 242, 173, 0.2)66%,
rgba(255, 255, 255, 0.1)100%);
}
}
.leaf {
position: absolute;
left: 50%;
top: 3%;
margin-left: -30px;
background-color: rgba(14, 110, 14);
width: 60px;
height: 60px;
border-radius: 0 10px 35px 10px;
-webkit-border-radius: 0 10px 35px 10px;
-moz-border-radius: 0 10px 35px 10px;
-ms-border-radius: 0 10px 35px 10px;
-o-border-radius: 0 10px 35px 10px;
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
box-shadow: 2px 7px 2px rgba(43, 43, 43, 0.2);
}
.edge {
position: absolute;
left: 0;
bottom: 0;
background: rgba(14, 110, 14);
width: 25px;
height: 30px;
border-radius: 0 10px 35px 10px;
-webkit-border-radius: 0 10px 35px 10px;
-moz-border-radius: 0 10px 35px 10px;
-ms-border-radius: 0 10px 35px 10px;
-o-border-radius: 0 10px 35px 10px;
transform: translateY(50%) translateX(0);
-webkit-transform: translateY(50%) translateX(0);
-moz-transform: translateY(50%) translateX(0);
-ms-transform: translateY(50%) translateX(0);
-o-transform: translateY(50%) translateX(0);
}
.edge.right {
position: absolute;
left: unset;
bottom: unset;
top: 0;
right: 0;
background: rgba(14, 110, 14);
width: 25px;
height: 30px;
border-radius: 0 10px 35px 10px;
-webkit-border-radius: 0 10px 35px 10px;
-moz-border-radius: 0 10px 35px 10px;
-ms-border-radius: 0 10px 35px 10px;
-o-border-radius: 0 10px 35px 10px;
transform: translateY(0) translateX(50%);
-webkit-transform: translateY(0) translateX(50%);
-moz-transform: translateY(0) translateX(50%);
-ms-transform: translateY(0) translateX(50%);
-o-transform: translateY(0) translateX(50%);
}
/* 双数修改背景颜色 */
.leaf:nth-child(even) {
background-color: #0f880f;
}
.leaf:nth-child(even) .edge {
background-color: #0f880f;
}
/* 最上面 */
.leaf:nth-child(1) {
z-index: 100;
transform: rotate(45deg) scale(0.8);
-webkit-transform: rotate(45deg) scale(0.8);
-moz-transform: rotate(45deg) scale(0.8);
-ms-transform: rotate(45deg) scale(0.8);
-o-transform: rotate(45deg) scale(0.8);
}
/* 第二 */
.leaf:nth-child(2) {
z-index: 99;
top: 15%;
transform: rotate(45deg) scale(1.3);
-webkit-transform: rotate(45deg) scale(1.3);
-moz-transform: rotate(45deg) scale(1.3);
-ms-transform: rotate(45deg) scale(1.3);
-o-transform: rotate(45deg) scale(1.3);
}
.leaf:nth-child(3) {
z-index: 98;
top: 28%;
transform: rotate(45deg) scale(1.6);
-webkit-transform: rotate(45deg) scale(1.6);
-moz-transform: rotate(45deg) scale(1.6);
-ms-transform: rotate(45deg) scale(1.6);
-o-transform: rotate(45deg) scale(1.6);
}
.leaf:nth-child(4) {
z-index: 97;
top: 41%;
transform: rotate(45deg) scale(1.9);
-webkit-transform: rotate(45deg) scale(1.9);
-moz-transform: rotate(45deg) scale(1.9);
-ms-transform: rotate(45deg) scale(1.9);
-o-transform: rotate(45deg) scale(1.9);
}
.leaf:nth-child(5) {
z-index: 96;
top: 54%;
transform: rotate(45deg) scale(2.2);
-webkit-transform: rotate(45deg) scale(2.2);
-moz-transform: rotate(45deg) scale(2.2);
-ms-transform: rotate(45deg) scale(2.2);
-o-transform: rotate(45deg) scale(2.2);
}
.trunk {
width: 25px;
height: 45px;
border-radius: 0 0 3px 3px;
-webkit-border-radius: 0 0 3px 3px;
-moz-border-radius: 0 0 3px 3px;
-ms-border-radius: 0 0 3px 3px;
-o-border-radius: 0 0 3px 3px;
position: absolute;
left: 50%;
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-ms-transform: translateX(-50%);
-o-transform: translateX(-50%);
bottom: 20px;
z-index: 1;
box-shadow: 0 0 10px 5px rgb(19, 19, 19);
background: linear-gradient(0deg, #6d411b 0%, #5a341d 64%);
}
.ball {
width: 20px;
height: 20px;
background: #f00;
box-shadow: -1px -1px 6px inset #600, 1px 1px 8px inset #ffc9c9;
border-radius: 50%;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
-ms-border-radius: 50%;
-o-border-radius: 50%;
z-index: 101;
position: absolute;
}
.b1 {
left: 25%;
top: 30%;
}
.b2 {
left: 35%;
top: 50%;
}
.b3 {
left: 65%;
top: 20%;
}
.b4 {
left: 45%;
top: 22%;
}
.b5 {
left: 40%;
top: 72%;
}
.b6 {
left: 60%;
top: 52%;
}
.b7 {
left: 50%;
top: 62%;
}
.b8 {
left: 80%;
top: 42%;
}
.b9 {
left: 10%;
top: 62%;
}
.b4,
.b5,
.b6 {
background: #ececec;
box-shadow: -1px -1px 6px inset #615f5f, 1px 1px 8px inset #fff;
}
.b7,
.b8,
.b9 {
background: gold;
box-shadow: -1px -1px 6px inset #3a3101, 1px 1px 8px inset #fff;
}
.sparkle span {
display: block;
position: absolute;
font-size: 20px;
z-index: 101;
color: #fff;
animation: lights 1.5s ease infinite alternate;
-webkit-animation: lights 1.5s ease infinite alternate;
}
/* 闪烁动画 */
@keyframes lights {
0%,
100% {
transform: scale(1);
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
}
50% {
transform: scale(1.5);
-webkit-transform: scale(1.5);
-moz-transform: scale(1.5);
-ms-transform: scale(1.5);
-o-transform: scale(1.5);
}
}
.sparkle span:nth-child(1) {
left: 30%;
top: 40%;
}
.sparkle span:nth-child(2) {
left: 40%;
top: 27%;
font-size: 15px;
}
.sparkle span:nth-child(3) {
left: 50%;
top: 57%;
font-size: 12px;
}
.sparkle span:nth-child(4) {
left: 70%;
top: 67%;
font-size: 14px;
}
.sparkle span:nth-child(5) {
left: 74%;
top: 13%;
font-size: 16px;
}
.blink div {
width: 3px;
height: 3px;
background: #fff;
z-index: 101;
position: absolute;
border-radius: 50%;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
-ms-border-radius: 50%;
-o-border-radius: 50%;
animation: blink 1.5s ease infinite alternate;
-webkit-animation: blink 1.5s ease infinite alternate;
}
.blink div:nth-child(2) {
left: 34%;
top: 13%;
transform: scale(1.2);
-webkit-transform: scale(1.2);
-moz-transform: scale(1.2);
-ms-transform: scale(1.2);
-o-transform: scale(1.2);
}
.blink div:nth-child(3) {
left: 54%;
top: 43%;
transform: scale(0.6);
-webkit-transform: scale(0.6);
-moz-transform: scale(0.6);
-ms-transform: scale(0.6);
-o-transform: scale(0.6);
}
.blink div:nth-child(4) {
left: 64%;
top: 33%;
transform: scale(1.4);
-webkit-transform: scale(1.4);
-moz-transform: scale(1.4);
-ms-transform: scale(1.4);
-o-transform: scale(1.4);
}
.blink div:nth-child(5) {
left: 34%;
top: 63%;
transform: scale(1.8);
-webkit-transform: scale(1.8);
-moz-transform: scale(1.8);
-ms-transform: scale(1.8);
-o-transform: scale(1.8);
}
.blink div:nth-child(6) {
left: 14%;
top: 76%;
transform: scale(1.5);
-webkit-transform: scale(1.5);
-moz-transform: scale(1.5);
-ms-transform: scale(1.5);
-o-transform: scale(1.5);
}
@keyframes blink {
0% {
box-shadow: 0 0 0 0 #fff;
}
25% {
box-shadow: 0 0 1px 1px #fff;
}
50% {
box-shadow: 0 0 2px 2px #fff;
}
75% {
box-shadow: 0 0 3px 3px #fff;
}
100% {
box-shadow: 0 0 4px 4px #fff;
}
}
.yy {
position: absolute;
top: 80%;
right: 0%;
}
</style>
</head>
<body>
<p class="word">
圣诞树
</p>
<div class="tree">
<div class="star">
<div class="star-in"></div>
</div>
<!-- 树叶 -->
<div class="leaf-box">
<div class="leaf">
<div class="edge"></div>
<div class="edge right"></div>
</div>
<div class="leaf">
<div class="edge"></div>
<div class="edge right"></div>
</div>
<div class="leaf">
<div class="edge"></div>
<div class="edge right"></div>
</div>
<div class="leaf">
<div class="edge"></div>
<div class="edge right"></div>
</div>
<div class="leaf">
<div class="edge"></div>
<div class="edge right"></div>
</div>
</div>
<!-- 树干 -->
<div class="trunk"></div>
<!-- 彩色的球 -->
<div class="ball-box">
<div class="ball b1"></div>
<div class="ball b2"></div>
<div class="ball b3"></div>
<div class="ball b4"></div>
<div class="ball b5"></div>
<div class="ball b6"></div>
<div class="ball b7"></div>
<div class="ball b8"></div>
<div class="ball b9"></div>
</div>
<!-- 闪烁 -->
<div class="sparkle">
<span>★</span>
<span>★</span>
<span>★</span>
<span>★</span>
<span>★</span>
<span>★</span>
</div>
<div class="blink">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<div class="yy">
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86
src="https://music.163.com/outchain/player?type=2&id=359109&auto=1&height=66"></iframe>
</div>
</body>
</html>
简易的圣诞树
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>鱼找水的圣诞树</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
<style type="text/css">
body{
background-color: #020024;
}
#app{
display:flex;
justify-content:center;
height: 100vh;
}
.shendanshu {
display: flex;
justify-content: center;
width: 1000px;
max-width: 100vw;
flex-direction: column;
align-items: center;
}
.shuceng {
display: flex;
flex-direction: row;
overflow: hidden;
justify-content: center;
}
.shuye {
position: relative;
height: 46px;
}
.ye {
width: 0;
height: 0;
border: 30px solid;
border-color: transparent transparent green;
border-top-width: 6px;
}
.caideng {
position: absolute;
bottom: 0px;
left: 22px;
width: 16px;
height: 16px;
background: red;
border-radius: 40px;
animation: dengguangxiaoguo 1s linear infinite alternate;
}
.caideng1{
animation-delay:-0.25s;
}
.caideng2{
animation-delay:-0.5s;
}
.caideng3{
animation-delay:-0.75s;
}
.shugan {
background-color: #795548;
height: 60px;
width: 100px;
}
.tudi {
background: #FFC107;
height: 20px;
width: 500px;
max-width: 80vw;
border-radius: 20px 20px 0px 0px;
}
@keyframes dengguangxiaoguo {
0% {
background-color: #fff;
}
25% {
background-color: blue;
}
50% {
background-color: red;
}
75% {
background-color: yellow;
}
100% {
background-color: #fff;
}
}
</style>
</head>
<body>
<div id="app">
<!-- 圣诞树 -->
<div class="shendanshu">
<!-- 树叶区域 -->
<div class="shuceng" v-for="arr_shuye in arr_shengdanshu">
<div class="shuye" v-for="shuye in arr_shuye">
<div class="ye"></div>
<div class="caideng" v-bind:class="shuye.caideng"></div>
</div>
</div>
<!-- 树干 -->
<div class="shugan"></div>
<!-- 土地 -->
<div class="tudi">
<a style="width:100%;text-align:center;display: inline-block;" href="https://github.com/mengmeng1009/shengdanshu"></a>
</div>
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
arr_shengdanshu: []
},
created: function () {
for (let i = 0; i < 9; i++) {
let arr_shuye = [];
for (let j = 0; j < i + 1; j++) {
let shuye = { js: j, caideng: "caideng" + Math.ceil(Math.random() * 4) }
arr_shuye.push(shuye)
}
this.arr_shengdanshu.push(arr_shuye)
}
}
})
</script>
</body>
</html>
线性树
<!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>🎄</title>
<script type='text/javascript'>
onload = function() {
var click_cnt = 0;
var $html = document.getElementsByTagName("html")[0];
var $body = document.getElementsByTagName("body")[0];
$html.onclick = function(e) {
var $elem = document.createElement("b");
$elem.style.color = "#E94F06";
$elem.style.zIndex = 9999;
$elem.style.position = "absolute";
$elem.style.select = "none";
var x = e.pageX;
var y = e.pageY;
$elem.style.left = (x - 10) + "px";
$elem.style.top = (y - 20) + "px";
clearInterval(anim);
switch (++click_cnt) {
case 10:
$elem.innerText = "OωO";
break;
case 20:
$elem.innerText = "(๑•́ ∀ •̀๑)";
break;
case 30:
$elem.innerText = "(๑•́ ₃ •̀๑)";
break;
case 40:
$elem.innerText = "(๑•̀_•́๑)";
break;
case 50:
$elem.innerText = "( ̄へ ̄)";
break;
case 60:
$elem.innerText = "(╯°口°)╯(┴—┴";
break;
case 70:
$elem.innerText = "૮( ᵒ̌皿ᵒ̌ )ა";
break;
case 80:
$elem.innerText = "╮(。>口<。)╭";
break;
case 90:
$elem.innerText = "( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃";
break;
case 100:
case 101:
case 102:
case 103:
case 104:
case 105:
$elem.innerText = "(ꐦ°᷄д°᷅)";
break;
default:
$elem.innerText = "❤";
break;
}
$elem.style.fontSize = Math.random() * 10 + 8 + "px";
var increase = 0;
var anim;
setTimeout(function() {
anim = setInterval(function() {
if (++increase == 150) {
clearInterval(anim);
$body.removeChild($elem);
}
$elem.style.top = y - 20 - increase + "px";
$elem.style.opacity = (150 - increase) / 120;
}, 8);
}, 70);
$body.appendChild($elem);
};
};
</script>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
}
body {
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
background-color: rgb(54, 66, 70);
}
.tree {
position: relative;
width: 500px;
height: 700px;
display: flex;
justify-content: center;
}
/*绘制星星*/
.star {
width: 50px;
height: 50px;
position: absolute;
background-color: rgb(236, 234, 167);
z-index: 999;
clip-path: polygon(50% 0, 65% 40%, 100% 40%, 72% 60%,
85% 100%, 50% 75%, 15% 100%, 28% 60%, 0 40%, 35% 40%);
}
.tree li{
position: absolute;
top: 25px;
width: 2px;
/*颜色渐变*/
background: linear-gradient(rgba(46,204,113,0),rgba(46,204,113,.25));
transform-origin: 0 0;
/*按照规定的动画 4秒内播放完毕 低速开始和结束 无限次播放*/
animation: swing 10s ease-in-out infinite;
height: calc(var(--i)*4px);
/*动画开始前的等待时间*/
animation-delay:calc(var(--i)*-0.23s);
}
@keyframes swing{
0%,
100%{
transform: rotate(-30deg);
}
0%{
opacity: 1;
}
5%,45%{
opacity: 0.25;
}
50%,100%{
opacity: 1;
}
50%{
transform: rotate(30deg);
}
}
.tree li::before{
content: '';
font-size: 1px;
position: absolute;
left: -1px;
bottom: 1px;
width: 3px;
height: 3px;
}
.tree li:nth-child(4n)::before{
background-color: #D8334A;
color: #D8334A;
}
.tree li:nth-child(4n+1)::before{
background-color: #FFCE54;
color: #FFCE54
}
.tree li:nth-child(4n+2)::before{
background-color: #2ECC71;
color: #2ECC71
}
.tree li:nth-child(4n+3)::before{
background-color: #5D9CEC;
color: #5D9CEC
}
</style>
</head>
<body>
<ul class="tree">
<div class="star"></div>
</ul>
</body>
<script>
let tree = document.querySelector('.tree')
for (let i = 0; i < 128; i++) {
let li = document.createElement('li')
li.style = "--i:" + i
tree.appendChild(li)
}
</script>
</html>
卡片圣诞树
这个代码文件比较多,就不贴了。有需要的可以评论私聊,以后会上传到资源
到此,本章内容就介绍完啦,如果有帮助到你 欢迎点个赞👍👍吧!!您的鼓励是博主的最大动力! 有问题评论区交流。