五彩纸屑按钮
五彩纸屑按钮
点击按钮喷出五彩纸屑的动画效果,纯 CSS + JavaScript 实现。
▼ 点击按钮查看效果
点击按钮喷出五彩纸屑的动画效果,纯 CSS + JavaScript 实现。
这是一个极具视觉冲击力的按钮动画效果——点击按钮时,大炮会发射出五彩纸屑,纸屑按照物理轨迹散落。效果使用纯 JavaScript 实现,无需额外依赖。
核心特性
- 五彩纸屑:4种颜色随机发射
- 物理模拟:JavaScript 实现抛物线轨迹
- 3D 悬停效果:鼠标悬停时按钮有 3D 倾斜
- 多种样式:深色、浅色、灰色三种主题
完整代码
以下是完整的单文件代码,你可以直接保存为 .html 文件运行:
HTML
<button class="button">
<div class="icon">
<div class="cannon"></div>
<div class="confetti">
<svg viewBox="0 0 18 16">
<polyline points="1 10 4 7 4 5 6 1" />
<path d="M4,13 C5.33333333,9 7,7 9,7 C11,7 12.3340042,6 13.0020125,4" />
<path d="M6,15 C7.83362334,13.6666667 9.83362334,12.6666667 12,12 C14.1663767,11.3333333 15.8330433,9.66666667 17,7" />
</svg>
<i></i><i></i><i></i><i></i><i></i><i></i>
<div class="emitter"></div>
</div>
</div>
<span>Confirm</span>
</button>
<button class="button white">
<div class="icon">
<div class="cannon"></div>
<div class="confetti">
<svg viewBox="0 0 18 16">
<polyline points="1 10 4 7 4 5 6 1" />
<path d="M4,13 C5.33333333,9 7,7 9,7 C11,7 12.3340042,6 13.0020125,4" />
<path d="M6,15 C7.83362334,13.6666667 9.83362334,12.6666667 12,12 C14.1663767,11.3333333 15.8330433,9.66666667 17,7" />
</svg>
<i></i><i></i><i></i><i></i><i></i><i></i>
<div class="emitter"></div>
</div>
</div>
<span>Confirm</span>
</button>
<button class="button grey">
<div class="icon">
<div class="cannon"></div>
<div class="confetti">
<svg viewBox="0 0 18 16">
<polyline points="1 10 4 7 4 5 6 1" />
<path d="M4,13 C5.33333333,9 7,7 9,7 C11,7 12.3340042,6 13.0020125,4" />
<path d="M6,15 C7.83362334,13.6666667 9.83362334,12.6666667 12,12 C14.1663767,11.3333333 15.8330433,9.66666667 17,7" />
</svg>
<i></i><i></i><i></i><i></i><i></i><i></i>
<div class="emitter"></div>
</div>
</div>
<span>Confirm</span>
</button>CSS
.button {
--background: #1E2235;
--color: #F6F8FF;
--confetti-1: #892AB8;
--confetti-2: #EA4C89;
--confetti-3: #FFFF04;
--confetti-4: #4AF2FD;
--z-before: -6;
display: inline-block;
cursor: pointer;
position: relative;
border: 0;
background: none;
padding: 9px 22px 9px 16px;
line-height: 26px;
font-family: 'Inter', Arial, sans-serif;
font-weight: 600;
font-size: 14px;
color: var(--color);
transform-style: preserve-3d;
transform: perspective(440px) rotateX(calc(var(--rx, 0) * 1deg))
rotateY(calc(var(--ry, 0) * 1deg)) translateZ(0);
}
.button:before {
content: '';
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 12px;
transform: translateZ(calc(var(--z-before) * 1px));
background: var(--background);
box-shadow: 0 4px 8px rgba(0,0,61, .24);
}
.button .icon {
display: inline-block;
width: 24px;
height: 14px;
margin: 8px 16px 0 0;
transform: translate(calc(var(--icon-x, 0) * 1px),
calc(var(--icon-y, 0) * 1px)) translateZ(2px);
position: relative;
z-index: 1;
vertical-align: top;
}
.button .icon .cannon {
position: relative;
width: 24px;
height: 14px;
transform: translate(0, 3px) rotate(-45deg);
}
.button .icon .cannon:before {
background: linear-gradient(#A6ACCD, #F6F8FF 50%, #A6ACCD);
width: 100%;
height: 14px;
-webkit-clip-path: polygon(25px -1px, 0 52%, 25px 15px);
clip-path: polygon(25px -1px, 0 52%, 25px 15px);
}
.button .icon .cannon:after {
width: 6px;
position: absolute;
right: -3px;
top: 0;
height: 14px;
border-radius: 50%;
background: linear-gradient(90deg, #A6ACCD, #F6F8FF);
}
/* 白色按钮 */
.button.white {
--background: #fff;
--color: #1E2235;
}
.button.white:before {
box-shadow: inset 0 0 0 1px #E1E6F9;
}
.button.white .icon .cannon:before {
background: linear-gradient(#103FC5, #275EFE 50%, #103FC5);
}
.button.white .icon .cannon:after {
background: linear-gradient(90deg, #103FC5, #275EFE);
}
/* 灰色按钮 */
.button.grey {
--background: #404660;
}
.button.grey .icon .cannon:before {
background: linear-gradient(#D1D6EE, #FFFFFF 50%, #D1D6EE);
}
.button.grey .icon .cannon:after {
background: linear-gradient(90deg, #D1D6EE, #FFFFFF);
}JavaScript
// 获取所有按钮
document.querySelectorAll('.demo-button').forEach(button => {
// 获取按钮的位置信息
const bounding = button.getBoundingClientRect();
// 鼠标移动时计算倾斜角度
button.addEventListener('mousemove', e => {
let dy = (e.clientY - bounding.top - bounding.height / 2) / -1;
let dx = (e.clientX - bounding.left - bounding.width / 2) / 10;
// 限制倾斜角度范围
dy = Math.max(-10, Math.min(10, dy));
dx = Math.max(-4, Math.min(4, dx));
button.style.setProperty('--rx', dy);
button.style.setProperty('--ry', dx);
});
// 鼠标离开时恢复
button.addEventListener('mouseleave', e => {
button.style.setProperty('--rx', 0);
button.style.setProperty('--ry', 0);
});
// 点击时发射纸屑
button.addEventListener('click', e => {
// 添加成功样式
button.classList.add('success');
// 按钮动画
gsap.to(button, {
'--icon-x': -3,
'--icon-y': 3,
'--z-before': 0,
duration: 0.2,
onComplete() {
// 发射纸屑粒子
particles(button.querySelector('.emitter'), 80, -4, 6, -80, -50);
// 恢复按钮
gsap.to(button, {
'--icon-x': 0,
'--icon-y': 0,
'--z-before': -6,
duration: 1,
ease: 'elastic.out(1, 0.5)',
onComplete() {
button.classList.remove('success');
}
});
}
});
});
});
// 纸屑粒子函数
function particles(parent, quantity, x, y, minAngle, maxAngle) {
const colors = ['#FFFF04', '#EA4C89', '#892AB8', '#4AF2FD'];
for (let i = 0; i < quantity; i++) {
// 创建粒子元素
const particle = document.createElement('div');
particle.className = 'particle';
// 随机颜色
const color = colors[Math.floor(Math.random() * colors.length)];
particle.style.background = color;
// 随机角度和速度
const angle = minAngle + Math.random() * (maxAngle - minAngle);
const velocity = 70 + Math.random() * 70;
// 初始位置
particle.style.left = x + 'px';
particle.style.top = y + 'px';
particle.style.opacity = '1';
parent.appendChild(particle);
// 物理参数
const startTime = performance.now();
const duration = 1500 + Math.random() * 500;
// 动画函数
function animate(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// 抛物线运动
const rad = angle * Math.PI / 180;
const vx = Math.cos(rad) * velocity;
const vy = Math.sin(rad) * velocity;
// 位置计算 (带重力)
const t = progress * 1.5;
const posX = x + vx * t;
const posY = y + vy * t + 0.5 * 200 * t * t;
// 旋转
const rotation = progress * 720 * (Math.random() > 0.5 ? 1 : -1);
particle.style.transform = `translate(${posX}px, ${posY}px) rotate(${rotation}deg)`;
particle.style.opacity = 1 - progress;
if (progress < 1) {
requestAnimationFrame(animate);
} else {
particle.remove();
}
}
requestAnimationFrame(animate);
}
}技术要点
| 技术点 | 说明 |
|---|---|
| requestAnimationFrame | 高性能动画循环 |
| 抛物线物理 | 模拟重力效果 |
| CSS 3D Transform | 实现按钮 3D 倾斜效果 |
| CSS 变量 | 统一管理颜色和尺寸 |
| clip-path | 裁剪大炮形状 |
使用说明
- 将完整代码保存为
.html文件 - 用浏览器打开
- 点击按钮查看五彩纸屑发射效果
评论