超好看的前端特效
1. 粒子组成文字动画特效
文件组成:
base.css
@import url('https://fonts.googleapis.com/css?family=Abril+Fatface|Raleway:300,400,900');
.coidea-header {
position: fixed;
display: block;
width: 96%;
width: calc( 100% - 32px );
height: 40px;
margin: 0 auto;
color: #3498db;
text-align: center;
top: 16px; right: 16px; left: 16px;
z-index: 1000;
}
.coidea-header .coidea-links .coidea-icon-back {
position: absolute;
display: block;
width: 24px;
height: 24px;
padding: 7px;
color: rgba(255, 255, 255,0.75);
font-size: 32px;
line-height: 34px;
font-weight: 900;
font-family: 'Raleway', sans-serif;
text-decoration: none;
outline: 0px none;
outline: 0px;
transition: all .3s ease;
top: 0px;
left: 0px;
z-index: 2;
}
.coidea-header .coidea-links .coidea-icon-back::before {
content: '';
position: absolute;
display: block;
width: 34px;
height: 34px;
top: 7px;
left: 20px;
border-radius: 8px;
background-color: rgba(255, 255, 255,.35);
}
.coidea-header .coidea-links .coidea-icon-back:hover {
color: rgba(255, 255, 255,1);
}
.coidea-header .coidea-links .coidea-icon-github {
position: absolute;
display: block;
width: 24px;
height: 24px;
padding: 7px;
color: rgba(255, 255, 255,0.75);
font-size: 32px;
line-height: 34px;
font-weight: 900;
font-family: 'Raleway', sans-serif;
text-decoration: none;
outline: 0px none;
outline: 0px;
transition: all .3s ease;
top: 0px;
right: 0px;
z-index: 2;
}
.coidea-header .coidea-links .coidea-icon-github::before {
content: '';
position: absolute;
display: block;
width: 34px;
height: 34px;
top: 7px;
right: 18px;
border-radius: 8px;
background-color: rgba(255, 255, 255,.35);
}
.coidea-header .coidea-links .coidea-icon-github:hover {
color: rgba(255, 255, 255,1);
}
.coidea-header .coidea-links .coidea-header {
font-family: 'Raleway', sans-serif;
display: inline-block;
font-size: 14px;
font-weight: 300;
margin: 0;
padding: 17px 0;
z-index: 1;
}
@media screen and (max-width: 360px) {
.coidea-header .coidea-links .coidea-header {
font-size: 12px;
}
}
demo.css
body {
background-color: #000000;
margin: 0;
overflow: hidden;
font-size: 0;
}
body section {
background: url(../img/bcg.jpg) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
width: 100vw;
height: 100vh;
font-weight: 700;
}
body section canvas {
width: 100vw;
height: 100vh;
}
bcg.jpg
demo.js
var canvas = document.querySelector("#canvas"),
ctx = canvas.getContext("2d"),
link = document.createElement('link');
particles = [],
amount = 0,
mouse = { x: -9999, y: -9999 },
radius = 1,
colors = [
"rgba(252,248,254,0.85)",
"rgba(220,203,255,0.75)",
"rgba(154,112,124,0.85)",
"rgba(192,213,255,0.85)",
"rgba(244,223,254,0.75)"
],
headline = document.querySelector("#headline"),
ww = window.innerWidth,
wh = window.innerHeight;
function Particle(x, y) {
this.x = Math.random() * ww;
this.y = Math.random() * wh;
this.dest = { x: x, y: y };
this.r = Math.random() * 2 * Math.PI;
this.vx = (Math.random() - 0.5) * 25;
this.vy = (Math.random() - 0.5) * 25;
this.accX = 0;
this.accY = 0;
this.friction = Math.random() * 0.025 + 0.94;
this.color = colors[Math.floor(Math.random() * 2.75)];
}
Particle.prototype.render = function() {
this.accX = (this.dest.x - this.x) / 1000;
this.accY = (this.dest.y - this.y) / 1000;
this.vx += this.accX;
this.vy += this.accY;
this.vx *= this.friction;
this.vy *= this.friction;
this.x += this.vx;
this.y += this.vy;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, Math.PI * 2, false);
ctx.fill();
var a = this.x - mouse.x;
var b = this.y - mouse.y;
var distance = Math.sqrt(a * a + b * b);
if (distance < (radius * 75)) {
this.accX = (this.x - mouse.x) / 100;
this.accY = (this.y - mouse.y) / 100;
this.vx += this.accX;
this.vy += this.accY;
}
}
function onMouseMove(e) {
mouse.x = e.clientX;
mouse.y = e.clientY;
}
function onTouchMove(e) {
if (e.touches.length > 0) {
mouse.x = e.touches[0].clientX;
mouse.y = e.touches[0].clientY;
}
}
function onTouchEnd(e) {
mouse.x = -9999;
mouse.y = -9999;
}
function initScene() {
ww = canvas.width = window.innerWidth;
wh = canvas.height = window.innerHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'https://fonts.googleapis.com/css?family=Abril+Fatface';
document.getElementsByTagName('head')[0].appendChild(link);
ctx.font = 'bold 16vw "Abril Fatface"';
ctx.textAlign = "center";
ctx.fillText(headline.innerHTML, ww / 2, wh / 1.6);
var data = ctx.getImageData(0, 0, ww, wh).data;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "screen";
particles = [];
for (var i = 0; i < ww; i += Math.round(ww / 200)) {
for (var j = 0; j < wh; j += Math.round(ww / 200)) {
if (data[((i + j * ww) * 4) + 3] > 200) {
particles.push(new Particle(i, j));
}
}
}
amount = particles.length;
}
function render(a) {
requestAnimationFrame(render);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < amount; i++) {
particles[i].render();
}
}
headline.addEventListener("keyup", initScene);
window.addEventListener("resize", initScene);
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("touchmove", onTouchMove);
window.addEventListener("touchend", onTouchEnd);
initScene();
requestAnimationFrame(render);
demo.scss
@import url('https://fonts.googleapis.com/css?family=Abril+Fatface');
body {
background-color: #000000;
margin: 0;
overflow: hidden;
font-size: 0;
section {
background: url(https://images.unsplash.com/photo-1528722828814-77b9b83aafb2?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1650&q=80) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
width: 100vw;
height: 100vh;
canvas {
width: 100vw;
height: 100vh;
}
}
}
index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>粒子组成文字动画特效</title>
<link rel="stylesheet" type="text/css" href="assets/css/base.css" />
<link rel="stylesheet" type="text/css" href="assets/css/demo.css" />
</head>
<body>
<section id="ci-particles">
<canvas id="canvas"></canvas>
<h1 id="headline">神奇的布欧</h1>
</section>
<script src="assets/js/demo.js"></script>
</body>
</html>
2. 爱心表白特效
文件组成:
heart.svg
<svg xmlns="http://www.w3.org/2000/svg" width="473.8px" height="408.6px" viewBox="0 0 473.8 408.6"><path fill="#d32932" d="M404.6,16.6C385.4,6.1,363.5,0,340,0c-41.5,0-78.5,18.9-103,48.5C212.3,18.9,175.3,0,133.8,0 c-23.3,0-45.3,6.1-64.5,16.6C27.9,39.5,0,83.4,0,133.9c0,14.4,2.4,28.3,6.6,41.2C29.6,278.4,237,408.6,237,408.6 s207.2-130.2,230.2-233.5c4.3-12.9,6.6-26.8,6.6-41.2C473.8,83.4,445.9,39.6,404.6,16.6z"/></svg>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>七夕520爱心表白</title>
<style>
*{margin:0; padding:0;}
body{ background-color: #1E1E1E; }
</style>
</head>
<body>
<canvas id="drawHeart"></canvas>
<script>
var hearts = [];
var canvas = document.getElementById('drawHeart');
var wW = window.innerWidth;
var wH = window.innerHeight;
// 创建画布
var ctx = canvas.getContext('2d');
// 创建图片对象
var heartImage = new Image();
heartImage.src = 'img/heart.svg';
var num = 100;
init();
window.addEventListener('resize', function(){
wW = window.innerWidth;
wH = window.innerHeight;
});
// 初始化画布大小
function init(){
canvas.width = wW;
canvas.height = wH;
for(var i = 0; i < num; i++){
hearts.push(new Heart(i%5));
}
requestAnimationFrame(render);
}
function getColor(){
var val = Math.random() * 10;
if(val > 0 && val <= 1){
return '#00f';
} else if(val > 1 && val <= 2){
return '#f00';
} else if(val > 2 && val <= 3){
return '#0f0';
} else if(val > 3 && val <= 4){
return '#368';
} else if(val > 4 && val <= 5){
return '#666';
} else if(val > 5 && val <= 6){
return '#333';
} else if(val > 6 && val <= 7){
return '#f50';
} else if(val > 7 && val <= 8){
return '#e96d5b';
} else if(val > 8 && val <= 9){
return '#5be9e9';
} else {
return '#d41d50';
}
}
function getText(){
var val = Math.random() * 10;
if(val > 1 && val <= 3){
return '爱你一辈子';
} else if(val > 3 && val <= 5){
return '感谢你';
} else if(val > 5 && val <= 8){
return '喜欢你';
} else{
return 'I Love You';
}
}
function Heart(type){
this.type = type;
// 初始化生成范围
this.x = Math.random() * wW;
this.y = Math.random() * wH;
this.opacity = Math.random() * .5 + .5;
// 偏移量
this.vel = {
x: (Math.random() - .5) * 5,
y: (Math.random() - .5) * 5
}
this.initialW = wW * .5;
this.initialH = wH * .5;
// 缩放比例
this.targetScale = Math.random() * .15 + .02; // 最小0.02
this.scale = Math.random() * this.targetScale;
// 文字位置
this.fx = Math.random() * wW;
this.fy = Math.random() * wH;
this.fs = Math.random() * 10;
this.text = getText();
this.fvel = {
x: (Math.random() - .5) * 5,
y: (Math.random() - .5) * 5,
f: (Math.random() - .5) * 2
}
}
Heart.prototype.draw = function(){
ctx.save();
ctx.globalAlpha = this.opacity;
ctx.drawImage(heartImage, this.x, this.y, this.width, this.height);
ctx.scale(this.scale + 1, this.scale + 1);
if(!this.type){
// 设置文字属性
ctx.fillStyle = getColor();
ctx.font = 'italic ' + this.fs + 'px sans-serif';
// 填充字符串
ctx.fillText(this.text, this.fx, this.fy);
}
ctx.restore();
}
Heart.prototype.update = function(){
this.x += this.vel.x;
this.y += this.vel.y;
if(this.x - this.width > wW || this.x + this.width < 0){
// 重新初始化位置
this.scale = 0;
this.x = Math.random() * wW;
this.y = Math.random() * wH;
}
if(this.y - this.height > wH || this.y + this.height < 0){
// 重新初始化位置
this.scale = 0;
this.x = Math.random() * wW;
this.y = Math.random() * wH;
}
// 放大
this.scale += (this.targetScale - this.scale) * .1;
this.height = this.scale * this.initialH;
this.width = this.height * 1.4;
// -----文字-----
this.fx += this.fvel.x;
this.fy += this.fvel.y;
this.fs += this.fvel.f;
if(this.fs > 50){
this.fs = 2;
}
if(this.fx - this.fs > wW || this.fx + this.fs < 0){
// 重新初始化位置
this.fx = Math.random() * wW;
this.fy = Math.random() * wH;
}
if(this.fy - this.fs > wH || this.fy + this.fs < 0){
// 重新初始化位置
this.fx = Math.random() * wW;
this.fy = Math.random() * wH;
}
}
function render(){
ctx.clearRect(0, 0, wW, wH);
for(var i = 0; i < hearts.length; i++){
hearts[i].draw();
hearts[i].update();
}
requestAnimationFrame(render);
}
</script>
</body>
</html>
3. 爱心跟随鼠标
index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>html5情人节爱心背景动画特效</title>
<style>
body{
overflow: hidden;
margin: 0;
}
h1{
position: fixed;
top: 50%;
left: 0;
width: 100%;
text-align: center;
transform:translateY(-50%);
font-family: 'Love Ya Like A Sister', cursive;
font-size: 40px;
color: #c70012;
padding: 0 20px;
}
h2{
position: fixed;
top: 10%;
left: 0;
width: 100%;
text-align: center;
transform:translateY(-50%);
font-family: 'Love Ya Like A Sister', cursive;
font-size: 20px;
color: #c70012;
padding: 0 20px;
}
@media (min-width:1200px){
h1{
font-size: 60px;
}
}
</style>
</head>
<body>
<canvas></canvas>
<h1>情人节快乐!</h1>
<script>
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d");
var ww,wh;
function onResize(){
ww = canvas.width = window.innerWidth;
wh = canvas.height = window.innerHeight;
}
ctx.strokeStyle = "red";
ctx.shadowBlur = 25;
ctx.shadowColor = "hsla(0, 100%, 60%,0.5)";
var precision = 100;
var hearts = [];
var mouseMoved = false;
function onMove(e){
mouseMoved = true;
if(e.type === "touchmove"){
hearts.push(new Heart(e.touches[0].clientX, e.touches[0].clientY));
hearts.push(new Heart(e.touches[0].clientX, e.touches[0].clientY));
}
else{
hearts.push(new Heart(e.clientX, e.clientY));
hearts.push(new Heart(e.clientX, e.clientY));
}
}
var Heart = function(x,y){
this.x = x || Math.random()*ww;
this.y = y || Math.random()*wh;
this.size = Math.random()*2 + 1;
this.shadowBlur = Math.random() * 10;
this.speedX = (Math.random()+0.2-0.6) * 8;
this.speedY = (Math.random()+0.2-0.6) * 8;
this.speedSize = Math.random()*0.05 + 0.01;
this.opacity = 1;
this.vertices = [];
for (var i = 0; i < precision; i++) {
var step = (i / precision - 0.5) * (Math.PI * 2);
var vector = {
x : (15 * Math.pow(Math.sin(step), 3)),
y : -(13 * Math.cos(step) - 5 * Math.cos(2 * step) - 2 * Math.cos(3 * step) - Math.cos(4 * step))
}
this.vertices.push(vector);
}
}
Heart.prototype.draw = function(){
this.size -= this.speedSize;
this.x += this.speedX;
this.y += this.speedY;
ctx.save();
ctx.translate(-1000,this.y);
ctx.scale(this.size, this.size);
ctx.beginPath();
for (var i = 0; i < precision; i++) {
var vector = this.vertices[i];
ctx.lineTo(vector.x, vector.y);
}
ctx.globalAlpha = this.size;
ctx.shadowBlur = Math.round((3 - this.size) * 10);
ctx.shadowColor = "hsla(0, 100%, 60%,0.5)";
ctx.shadowOffsetX = this.x + 1000;
ctx.globalCompositeOperation = "screen"
ctx.closePath();
ctx.fill()
ctx.restore();
};
function render(a){
requestAnimationFrame(render);
hearts.push(new Heart())
ctx.clearRect(0,0,ww,wh);
for (var i = 0; i < hearts.length; i++) {
hearts[i].draw();
if(hearts[i].size <= 0){
hearts.splice(i,1);
i--;
}
}
}
onResize();
window.addEventListener("mousemove", onMove);
window.addEventListener("touchmove", onMove);
window.addEventListener("resize", onResize);
requestAnimationFrame(render);
</script>
</body>
</html>
4. 满屏漂浮爱心
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>实现满屏的漂浮爱心</title>
<style>
html,
body {
margin: 0px;
padding: 0px;
background-color: #312;
font-family: sans-serif;
font-size: 48px;
overflow: hidden;
}
#logo {
position: absolute;
right: 0px;
bottom: 0px;
}
p {
color: #aeb7c0;
}
canvas {
background-color: #312;
}
</style>
</head>
<body>
<div>
<canvas id="testCanvas" width="550" height="500"></canvas>
</div>
<script src="https://code.createjs.com/1.0.0/easeljs.min.js"></script>
<script>
var canvas;
var stage;
var container;
var captureContainers;
var captureIndex;
function init() {
// create a new stage and point it at our canvas:
canvas = document.getElementById("testCanvas");
// 创建stage
stage = new createjs.Stage(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var w = canvas.width;
var h = canvas.height;
container = new createjs.Container();
stage.addChild(container);
captureContainers = [];
captureIndex = 0;
// create a large number of slightly complex vector shapes, and give them random positions and velocities:
for (var i = 0; i < 100; i++) {
var heart = new createjs.Shape();
heart.graphics.beginFill(
createjs.Graphics.getHSL(
Math.random() * 30 - 45,
100,
50 + Math.random() * 30
)
);
heart.graphics
.moveTo(0, -12)
.curveTo(1, -20, 8, -20)
.curveTo(16, -20, 16, -10)
.curveTo(16, 0, 0, 12);
heart.graphics
.curveTo(-16, 0, -16, -10)
.curveTo(-16, -20, -8, -20)
.curveTo(-1, -20, 0, -12);
heart.y = -100;
container.addChild(heart);
}
var text = new createjs.Text(
"the longer I'm with you\nthe more I love you",
"bold 24px Arial",
"#312"
);
text.textAlign = "center";
text.x = w / 2;
text.y = h / 2 - text.getMeasuredLineHeight();
stage.addChild(text);
for (i = 0; i < 100; i++) {
var captureContainer = new createjs.Container();
captureContainer.cache(0, 0, w, h);
captureContainers.push(captureContainer);
}
// start the tick and point it at the window so we can do some work before updating the stage:
createjs.Ticker.timingMode = createjs.Ticker.RAF;
createjs.Ticker.on("tick", tick);
}
function tick(event) {
var w = canvas.width;
var h = canvas.height;
var l = container.numChildren;
captureIndex = (captureIndex + 1) % captureContainers.length;
stage.removeChildAt(0);
var captureContainer = captureContainers[captureIndex];
stage.addChildAt(captureContainer, 0);
captureContainer.addChild(container);
// iterate through all the children and move them according to their velocity:
for (var i = 0; i < l; i++) {
var heart = container.getChildAt(i);
if (heart.y < -50) {
heart._x = Math.random() * w;
heart.y = h * (1 + Math.random()) + 50;
heart.perX = (1 + Math.random() * 2) * h;
heart.offX = Math.random() * h;
heart.ampX = heart.perX * 0.1 * (0.15 + Math.random());
heart.velY = -Math.random() * 2 - 1;
heart.scaleX = heart.scaleY = Math.random() * 2 + 1;
heart._rotation = Math.random() * 40 - 20;
heart.alpha = Math.random() * 0.75 + 0.05;
heart.compositeOperation =
Math.random() < 0.33 ? "lighter" : "source-over";
}
var int = ((heart.offX + heart.y) / heart.perX) * Math.PI * 2;
heart.y += (heart.velY * heart.scaleX) / 2;
heart.x = heart._x + Math.cos(int) * heart.ampX;
heart.rotation = heart._rotation + Math.sin(int) * 30;
}
captureContainer.updateCache("source-over");
// draw the updates to stage:
// 将更新绘制到舞台
stage.update(event);
}
init();
</script>
</body>
</html>
5. 黑客帝国矩阵雨
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>实现黑客帝国矩阵雨效果</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
/*basic reset*/
* {
margin: 0;
padding: 0;
}
/*adding a black bg to the body to make things clearer*/
body {
background: black;
}
canvas {
display: block;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script src="cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
var c = document.getElementById("c");
var ctx = c.getContext("2d");
//making the canvas full screen | 让画布全屏
c.height = window.innerHeight;
c.width = window.innerWidth;
//chinese characters - taken from the unicode charset | 汉字 - 取自unicode字符集
var chinese =
"田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑";
//converting the string into an array of single characters | 将字符串转换为单个字符数组
chinese = chinese.split("");
var font_size = 10;
var columns = c.width / font_size; //number of columns for the rain | 雨水柱数
//an array of drops - one per column | 雨滴的阵列 - 每列一个
var drops = [];
//x below is the x coordinate | 下面的x是x坐标
//1 = y co-ordinate of the drop(same for every drop initially) | 雨滴的y坐标(最初每一滴相同)
for (var x = 0; x < columns; x++) drops[x] = 1;
//drawing the characters | 绘制字符
function draw() {
//Black BG for the canvas | 画布黑色背景
//translucent BG to show trail | 半透明背景显示轨迹
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
ctx.fillRect(0, 0, c.width, c.height);
ctx.fillStyle = "#0F0"; //green text
ctx.font = font_size + "px arial";
//looping over drops | 在雨滴上循环
for (var i = 0; i < drops.length; i++) {
//a random chinese character to print | 要打印的随机汉字
var text = chinese[Math.floor(Math.random() * chinese.length)];
//x = i*font_size, y = value of drops[i]*font_size
ctx.fillText(text, i * font_size, drops[i] * font_size);
//sending the drop back to the top randomly after it has crossed the screen | 在水滴越过屏幕后,将其随机发送回顶部
//adding a randomness to the reset to make the drops scattered on the Y axis | 将随机性添加到重置,以使液滴分散在Y轴上
if (drops[i] * font_size > c.height && Math.random() > 0.975)
drops[i] = 0;
//incrementing Y coordinate | 递增Y坐标
drops[i]++;
}
}
setInterval(draw, 33);
</script>
</body>
</html>
6. 2024新年快乐动画特效
文件目录:
style.css
* {
/* 采用怪异模式下的盒模型:元素的总高度和宽度包含内边距和边框(padding与border) */
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
/* 没有滚动条 */
overflow: hidden;
}
.section {
display: flex;
justify-content: center;
align-items: center;
position: relative;
min-height: 100vh;
background: linear-gradient(135deg, #111, #222, #111);
}
.section::before {
content: "";
position: absolute;
width: 30vw;
height: 30vw;
/* 红色边框 */
border: 5vw solid #ff1062;
/* 圆形边框 */
border-radius: 50%;
/* 为边框添加2个下拉阴影 */
box-shadow: 0 0 0 1vw #222, 0 0 0 1.3vw #fff;
}
.section .section__title {
position: absolute;
transform: skewY(-7deg);
z-index: 10;
color: #fff;
text-align: center;
font-size: 9vw;
line-height: 2em;
text-shadow: 1px 1px 0 #ccc, 2px 2px 0 #ccc, 3px 3px 0 #ccc, 4px 4px 0 #ccc,
5px 5px 0 #ccc, 10px 10px 0 rgba(0, 0, 0, 0.2);
animation: floating 5s ease-in-out infinite;
}
.section .section__title span {
text-shadow: 1px 1px 0 #ccc, 2px 2px 0 #ccc, 3px 3px 0 #ccc, 4px 4px 0 #ccc,
5px 5px 0 #ccc, 6px 6px 0 #ccc, 7px 7px 0 #ccc, 8px 8px 0 #ccc,
9px 9px 0 #ccc, 20px 20px 0 rgba(0, 0, 0, 0.2);
font-weight: 700;
font-size: 3em;
}
.section i {
position: absolute;
background: #fff;
border-radius: 50%;
box-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 40px #fff, 0 0 80px #fff;
animation: animate linear infinite;
}
@keyframes floating {
0%,
100% {
transform: skewY(-7deg) translate(0, -20px);
}
50% {
transform: skewY(-7deg) translate(0, 20px);
}
}
/* 利用透明度设置星星明暗变化的动画效果 */
@keyframes animate {
0% {
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
opacity: 0;
}
}
script.js
const stars = () => {
const count = 200;
const section = document.querySelector('.section');
let i = 0;
while (i < count) {
// 在内存中创建一个新的空元素对象,如i或是div
const star = document.createElement('i');
// 定义变量x和y :通过Math.random()方法随机的使星星出现在不同位置,当然星星的定位要在文档显示区内
const x = Math.floor(Math.random() * window.innerWidth);
const y = Math.floor(Math.random() * window.innerHeight);
const size = Math.random() * 4;
// 让星星始终会在网页最左最顶端出现,通过想x和y的定位,我们要让它出现在页面各个不同的位置
star.style.left = x + 'px';
star.style.top = y + 'px';
// 利用Math.random()这个方法来随机取星星的大小:为每颗星星设置随机的宽高范围为[0,5)
star.style.width = 1 + size + 'px';
star.style.height = 1 + size + 'px';
const duration = Math.random() * 2;
// 设置持续时间
// js中除了减法计算之外,不允许随便写-。因为会混淆。所以,DOM标准规定,所有带-的css属性名,一律去横线变驼峰
// css属性animation-duration,在js中改写为驼峰形式:animationDuration
star.style.animationDuration = 2 + duration + 's';
// 设置延迟
star.style.animationDelay = 2 + duration + 's';
// 将新元素添加到DOM树:把新创建的节点追加到父元素下所有直接子元素的结尾
section.appendChild(star);
i++;
}
}
// 调用函数
stars();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>2024新年快乐动画特效</title>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<section class="section">
<h2 class="section__title">Happy New Year<br /><span>2024</span></h2>
</section>
<script src="js/script.js"></script>
</body>
</html>
7. 表白特效2
代码文件过多可以私我!这里不贴出来了,需要可以私信我!
8. 新年快乐特效
文件目录:
style.css
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: #161929;
position: relative;
overflow: hidden;
user-select: none;
}
audio {
opacity: 0;
}
.message {
position: fixed;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
width: 160px;
background-color: rgba(0, 0, 0, 0.52);
padding: 0px 17px;
top: 25px;
border-radius: 6px;
overflow: hidden;
z-index: 1000;
opacity: 0;
}
/* 消息提示框内容样式 */
.message p {
line-height: 1;
font-size:14px;
color: #ffffff;
}
.spark {
width: 3px;
height: 3px;
border-radius: 50%;
position: absolute;
background-color: rgba(231, 200, 160, 0.8);
box-shadow: 0 0 40px 0 rgba(231, 200, 160, 0.8);
animation: glow 5s infinite;
}
.medium-spark {
width: 7px;
height: 7px;
}
.big-spark {
width: 10px;
height: 10px;
box-shadow: 0 0 40px 0 #e9c9a0, 0 0 20px 0 #FFFFFF, inset 0 0 4px #FFFFFF;
}
.meteor {
width: 6px;
height: 6px;
background-color: rgba(255, 255, 255, 0.6);
box-shadow: 0 0 40px 0 #e9c9a0, 0 0 20px 0 #FFFFFF, inset 0 0 8px rgba(255, 255, 255, 0.6);
top: 0;
left: 80%;
opacity: 0.3;
transform: rotate(-45deg) translate(0, -50px);
animation: meteor 7s infinite;
}
.meteor:after {
content: '';
width: 20vw;
height: 6px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.1);
box-shadow: 0 0 20px rgba(231, 200, 160, 0.4);
position: absolute;
top: 0;
left: 0;
}
@keyframes glow {
0% {
opacity: 0.9;
}
50% {
opacity: 0.2;
}
100% {
opacity: 0.9;
}
}
@keyframes meteor {
0% {
transform: rotate(-45deg) translateX(0);
opacity: 0.3;
}
10% {
opacity: 1;
}
20% {
transform: rotate(-45deg) translateX(-100vw);
opacity: 0;
}
100% {
transform: rotate(-45deg) translateX(-100vw);
opacity: 0;
}
}
main.js
// 初始化内容
var wH = window.innerHeight;
var wW = window.innerWidth;
let backgroundRendering = document.getElementById("backgroundRendering");
var generateStars = function generateStars(f) {
for (var e = 0; e < f; e++) {
var single = document.createElement("div");
single.className = e % 20 == 0 ? "spark big-spark" : e % 9 == 0 ? "spark medium-spark" : "star";
single.setAttribute("style", "top:" + Math.round(Math.random() * wH) + "px;left:" + Math.round(Math.random() * wW) + "px;animation-duration:" + (Math.round(Math.random() * 3000) + 3000) + "ms;animation-delay:" + Math.round(Math.random() * 3000) + "ms;");
backgroundRendering.appendChild(single);
}
};
generateStars(getRandom(140, 240));
// 全局变量 提供内容/对象存储
let fireworksCanvas = document.getElementById("fireworks");
let currentFireworks = document.createElement("canvas");
let currentObject = currentFireworks.getContext("2d");
let fireworksObject = fireworksCanvas.getContext("2d");
currentFireworks.width = fireworksCanvas.width = window.innerWidth;
currentFireworks.height = fireworksCanvas.height = window.innerHeight;
let fireworksExplosion = [];
let autoPlayFlag = false;
// 自动加载烟花动画
window.onload = function () {
drawFireworks();
lastTime = new Date();
animationEffect();
// 背景音乐
let audio = document.getElementById('bgm');
document.querySelector("body").onclick = function () {
if (!autoPlayFlag) {
audio.play();
autoPlayFlag = true;
}
}
for (let i = 0; i <= 10; i++) {
setTimeout(function () {
document.querySelector("body > div.message").style.opacity = i / 10;
}, i * 60 + 2000)
};
for (let i = 0; i <= 10; i++) {
setTimeout(function () {
document.querySelector("body > div.message").style.opacity = 1 - i / 10;
if (i == 10) {
document.querySelector("body > div.message > p").innerHTML = "点击屏幕可快速释放烟花"
}
}, i * 60 + 8000)
};
for (let i = 0; i <= 10; i++) {
setTimeout(function () {
document.querySelector("body > div.message").style.opacity = i / 10;
}, i * 60 + 8600)
};
for (let i = 0; i <= 10; i++) {
setTimeout(function () {
document.querySelector("body > div.message").style.opacity = 1 - i / 10;
}, i * 60 + 16600)
};
};
let lastTime;
// 烟花动画效果
function animationEffect() {
fireworksObject.save();
fireworksObject.fillStyle = "rgba(0,5,25,0.1)";
fireworksObject.fillRect(0, 0, fireworksCanvas.width, fireworksCanvas.height);
fireworksObject.restore();
let newTime = new Date();
if (newTime - lastTime > getRandom(10, 1600) + (window.innerHeight - 767) / 2) {
let random = Math.random() * 100 > 15;
let x = getRandom(0, (fireworksCanvas.width));
let y = getRandom(0, 400);
if (random) {
let bigExplode = new explode(
getRandom(0, fireworksCanvas.width),
getRandom(1, 3),
"#FFF",
{
x: x,
y: y,
}
);
fireworksExplosion.push(bigExplode);
} else {
let x = getRandom(fireworksCanvas.width / 2 - 300, fireworksCanvas.width / 2 + 300);
let y = getRandom(0, 350);
let bigExplode = new explode(
getRandom(0, fireworksCanvas.width),
getRandom(1, 3),
"#FFF",
{
x: x,
y: y,
},
document.querySelectorAll(".shape")[
parseInt(getRandom(0, document.querySelectorAll(".shape").length))
]
);
fireworksExplosion.push(bigExplode);
}
lastTime = newTime;
}
sparks.foreach(function () {
this.paint();
});
fireworksExplosion.foreach(function () {
let that = this;
if (!this.dead) {
this._move();
this._drawLight();
} else {
this.explodes.foreach(function (index) {
if (!this.dead) {
this.moveTo();
} else {
if (index === that.explodes.length - 1) {
fireworksExplosion[fireworksExplosion.indexOf(that)] = null;
}
}
});
}
});
setTimeout(animationEffect, 16);
}
Array.prototype.foreach = function (callback) {
for (let i = 0; i < this.length; i++) {
if (this[i] !== null) {
callback.apply(this[i], [i]);
}
}
};
fireworksCanvas.onclick = function (evt) {
let x = evt.clientX;
let y = evt.clientY;
let explode1 = new explode(
getRandom(fireworksCanvas.width / 3, (fireworksCanvas.width * 2) / 3),
2,
"#FFF",
{
x: x,
y: y,
}
);
fireworksExplosion.push(explode1);
};
let explode = function (x, r, c, explodeArea, shape) {
this.explodes = [];
this.x = x;
this.y = fireworksCanvas.height + r;
this.r = r;
this.c = c;
this.shape = shape || false;
this.explodeArea = explodeArea;
this.dead = false;
this.ba = parseInt(getRandom(80, 200));
};
explode.prototype = {
_paint: function () {
fireworksObject.save();
fireworksObject.beginPath();
fireworksObject.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
fireworksObject.fillStyle = this.c;
fireworksObject.fill();
fireworksObject.restore();
},
_move: function () {
let dx = this.explodeArea.x - this.x,
dy = this.explodeArea.y - this.y;
this.x = this.x + dx * 0.01;
this.y = this.y + dy * 0.01;
if (Math.abs(dx) <= this.ba && Math.abs(dy) <= this.ba) {
if (this.shape) {
this._shapeExplode();
} else {
this._explode();
}
this.dead = true;
} else {
this._paint();
}
},
_drawLight: function () {
fireworksObject.save();
fireworksObject.fillStyle = "rgba(255,228,150,0.3)";
fireworksObject.beginPath();
fireworksObject.arc(this.x, this.y, this.r + 3 * Math.random() + 1, 0, 2 * Math.PI);
fireworksObject.fill();
fireworksObject.restore();
},
_explode: function () {
let embellishmentNum = getRandom(30, 200);
let style = getRandom(0, 10) >= 5 ? 1 : 2;
let color;
if (style === 1) {
color = {
a: parseInt(getRandom(128, 255)),
b: parseInt(getRandom(128, 255)),
c: parseInt(getRandom(128, 255)),
};
}
let fullRange = parseInt(getRandom(300, 400));
for (let i = 0; i < embellishmentNum; i++) {
if (style === 2) {
color = {
a: parseInt(getRandom(128, 255)),
b: parseInt(getRandom(128, 255)),
c: parseInt(getRandom(128, 255)),
};
}
let a = getRandom(-Math.PI, Math.PI);
let x = getRandom(0, fullRange) * Math.cos(a) + this.x;
let y = getRandom(0, fullRange) * Math.sin(a) + this.y;
let radius = getRandom(0, 2);
let embellishment = new newEmbellishment(this.x, this.y, radius, color, x, y);
this.explodes.push(embellishment);
}
},
_shapeExplode: function () {
let that = this;
putValue(currentFireworks, currentObject, this.shape, 5, function (dots) {
let dx = fireworksCanvas.width / 2 - that.x;
let dy = fireworksCanvas.height / 2 - that.y;
let color;
for (let i = 0; i < dots.length; i++) {
color = {
a: dots[i].a,
b: dots[i].b,
c: dots[i].c,
};
let x = dots[i].x;
let y = dots[i].y;
let radius = 1;
let embellishment = new newEmbellishment(that.x, that.y, radius, color, x - dx, y - dy);
that.explodes.push(embellishment);
}
});
},
};
function putValue(fireworks, context, ele, dr, callback) {
context.clearRect(0, 0, fireworksCanvas.width, fireworksCanvas.height);
let img = new Image();
let dots;
if (ele.innerHTML.indexOf("img") >= 0) {
img.src = ele.getElementsByTagName("img")[0].src;
implode(img, function () {
context.drawImage(
img,
fireworksCanvas.width / 2 - img.width / 2,
fireworksCanvas.height / 2 - img.width / 2
);
let dots = gettingData(fireworks, context, dr);
callback(dots);
});
} else {
let text = ele.innerHTML;
context.save();
let fontSize = getRandom(3, 11);
context.font = fontSize + "vw 宋体 bold";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillStyle =
"rgba(" +
parseInt(getRandom(128, 255)) +
"," +
parseInt(getRandom(128, 255)) +
"," +
parseInt(getRandom(128, 255)) +
" , 1)";
context.fillText(text, fireworksCanvas.width / 2, fireworksCanvas.height / 2);
context.restore();
dots = gettingData(fireworks, context, dr);
callback(dots);
}
}
function implode(img, callback) {
if (img.complete) {
callback.call(img);
} else {
img.onload = function () {
callback.call(this);
};
}
}
function gettingData(fireworks, context, dr) {
let imgData = context.getImageData(0, 0, fireworksCanvas.width, fireworksCanvas.height);
context.clearRect(0, 0, fireworksCanvas.width, fireworksCanvas.height);
let dots = [];
for (let x = 0; x < imgData.width; x += dr) {
for (let y = 0; y < imgData.height; y += dr) {
let i = (y * imgData.width + x) * 4;
if (imgData.data[i + 3] > 128) {
let dot = {
x: x,
y: y,
a: imgData.data[i],
b: imgData.data[i + 1],
c: imgData.data[i + 2],
};
dots.push(dot);
}
}
}
return dots;
}
function getRandom(a, b) {
return Math.random() * (b - a) + a;
}
let maxRadius = 1,
sparks = [];
function drawFireworks() {
for (let i = 0; i < 100; i++) {
let spark = new newSpark();
sparks.push(spark);
spark.paint();
}
}
// 新建星火位置
let newSpark = function () {
this.x = Math.random() * fireworksCanvas.width;
this.y = Math.random() * 2 * fireworksCanvas.height - fireworksCanvas.height;
this.r = Math.random() * maxRadius;
};
newSpark.prototype = {
paint: function () {
fireworksObject.save();
fireworksObject.beginPath();
fireworksObject.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
fireworksObject.fillStyle = "rgba(255,255,255," + this.r + ")";
fireworksObject.fill();
fireworksObject.restore();
},
};
// 烟花点缀生成
let newEmbellishment = function (centerX, centerY, radius, color, tx, ty) {
this.tx = tx;
this.ty = ty;
this.x = centerX;
this.y = centerY;
this.dead = false;
this.radius = radius;
this.color = color;
};
newEmbellishment.prototype = {
paint: function () {
fireworksObject.save();
fireworksObject.beginPath();
fireworksObject.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
fireworksObject.fillStyle =
"rgba(" + this.color.a + "," + this.color.b + "," + this.color.c + ",1)";
fireworksObject.fill();
fireworksObject.restore();
},
moveTo: function () {
this.ty = this.ty + 0.3;
let dx = this.tx - this.x,
dy = this.ty - this.y;
this.x = Math.abs(dx) < 0.1 ? this.tx : this.x + dx * 0.1;
this.y = Math.abs(dy) < 0.1 ? this.ty : this.y + dy * 0.1;
if (dx === 0 && Math.abs(dy) <= 80) {
this.dead = true;
}
this.paint();
},
};
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>新年烟花</title>
<link rel="icon" type="image/x-icon" href="https://pic.imgdb.cn/item/61f794ad2ab3f51d91b07a1e.png">
<link rel="stylesheet" href="static/css/style.css">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css" />
</head>
<body onselectstart="return false">
<!-- 消息提示 -->
<div class="message">
<p>请单击屏幕开启背景音乐</p>
</div>
<!-- 流星与星火 -->
<div id="backgroundRendering" style="z-index: 0;"></div>
<!--烟花-->
<canvas id="fireworks" style="z-index: 9999;">
您的浏览器不支持canvas标签。
</canvas>
<!-- 背景音乐 -->
<audio id="bgm" src="static/mp3/bgm.mp3" loop autoplay>
您的浏览器不支持 audio 标签。
</audio>
<!-- 自定义内容弹窗 -->
<div style="display: none">
<div class="shape">🏮2024新年快乐🏮</div>
<div class="shape">🏮恭喜发财🏮</div>
<div class="shape">🏮万事如意🏮</div>
<div class="shape">🏮吉庆有余🏮</div>
<div class="shape">🏮心想事成🏮</div>
<div class="shape">🏮喜气盈门🏮</div>
<div class="shape">🏮阖家欢乐🏮</div>
<div class="shape">🏮财源广进🏮</div>
</div>
<a class="github-fork-ribbon" href="https://github.com/uiuing/NewYearFireworks" data-ribbon="Fork me on GitHub"
title="Fork me on GitHub">Fork me on GitHub</a>
<script src="static/js/main.js"></script>
</body>
</html>