五彩纸屑按钮

十二月 19, 2023 / Mr.x / 0阅读 / 0评论/ 分类: 创意
五彩纸屑按钮 — 荣小站

五彩纸屑按钮

点击按钮喷出五彩纸屑的动画效果,纯 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裁剪大炮形状

使用说明

  1. 将完整代码保存为 .html 文件
  2. 用浏览器打开
  3. 点击按钮查看五彩纸屑发射效果

#五彩纸屑按钮(1)

评论