实时预览
✨ 星空
生成代码
HTML + CSS + JS · 复制即用
常见问题 & 知识点
CSS 粒子背景是通过纯 CSS(配合少量 JavaScript)在网页背景中生成动态粒子效果的技术。常见应用包括:网站 Hero 区域背景装饰、登录页动态背景、节日主题页面(雪花、樱花)、品牌氛围营造等。相比 Canvas 方案,CSS 粒子更轻量,兼容性好,且对开发者也更友好。
合理使用粒子背景对性能影响很小。建议:粒子数量控制在 30-100 个之间;使用 will-change: transform, opacity 提示浏览器优化;使用 pointer-events: none 让粒子不阻挡用户交互;避免在移动端使用过多粒子(建议≤50个);使用 CSS @keyframes 动画而非 JavaScript 逐帧动画,可利用 GPU 加速。
当然可以!生成的代码是自包含的,包含完整的 CSS 动画定义和 JavaScript 粒子生成逻辑。你只需要在 HTML 中放置一个指定 ID 的容器元素,然后粘贴代码即可。代码不依赖任何第三方库,兼容所有现代浏览器(Chrome、Firefox、Safari、Edge)。建议将 <style> 放入 <head>,将 <script> 放在 </body> 之前。
完全支持移动端。CSS 粒子动画在移动浏览器上同样流畅。建议在移动端减少粒子数量(推荐 20-40 个),并适当降低动画复杂度。本工具生成的代码包含响应式适配建议,你可以根据屏幕宽度动态调整粒子数量。iOS Safari 和 Android Chrome 均经过充分测试。
有几种方法修改粒子形状:1) 使用 border-radius 创建圆形、椭圆或不规则形状;2) 使用 Unicode 字符(如 ★、❤、●)配合 content 属性;3) 使用 CSS clip-path 裁剪出星形、心形等多边形;4) 使用 SVG 或 emoji 作为粒子内容。本工具生成的代码中,粒子使用 border-radius: 50% 创建圆形,你可以自由修改。
CSS 粒子:优点包括代码简洁、易于修改样式、GPU 加速动画流畅、与页面其他元素自然融合;缺点是不适合超大量粒子(>300个)、交互性有限。Canvas 粒子:优点包括可处理海量粒子(数千个)、支持复杂物理模拟、可精确控制每个粒子;缺点是代码复杂度高、样式调整不便、需要 JavaScript 持续运行。对于装饰性背景,CSS 粒子是更优选择。
`;
codeOutput.text(code);
}
function generateKeyframesCSS(cfg, animList) {
let css = '';
if (cfg.animationType === 'twinkle') {
css += `
@keyframes star-twinkle-1 {
0%, 100% { opacity: ${cfg.opacityMin}; transform: scale(0.8); }
40% { opacity: ${cfg.opacityMax}; transform: scale(1.25); }
70% { opacity: ${(cfg.opacityMin + cfg.opacityMax) / 2}; transform: scale(0.9); }
}
@keyframes star-twinkle-2 {
0%, 100% { opacity: ${(cfg.opacityMin + cfg.opacityMax) / 2}; transform: scale(0.9); }
30% { opacity: ${cfg.opacityMax}; transform: scale(1.35); }
60% { opacity: ${cfg.opacityMin}; transform: scale(0.75); }
85% { opacity: ${cfg.opacityMax * 0.8}; transform: scale(1.1); }
}`;
} else if (cfg.animationType === 'rise') {
css += `
@keyframes bubble-rise-1 {
0% { transform: translateY(0) translateX(0) scale(1); opacity: ${cfg.opacityMax}; }
70% { opacity: ${cfg.opacityMin + 0.1}; }
100% { transform: translateY(-110vh) translateX(30px) scale(0.4); opacity: 0; }
}
@keyframes bubble-rise-2 {
0% { transform: translateY(0) translateX(0) scale(0.8); opacity: ${cfg.opacityMax * 0.8}; }
50% { opacity: ${cfg.opacityMin + 0.15}; }
100% { transform: translateY(-110vh) translateX(-40px) scale(0.3); opacity: 0; }
}
@keyframes bubble-rise-3 {
0% { transform: translateY(0) translateX(0) scale(1.1); opacity: ${cfg.opacityMax}; }
60% { transform: translateY(-60vh) translateX(15px) scale(0.6); opacity: ${cfg.opacityMin + 0.2}; }
100% { transform: translateY(-110vh) translateX(-20px) scale(0.2); opacity: 0; }
}`;
} else if (cfg.animationType === 'fall') {
css += `
@keyframes snow-fall-1 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax}; }
100% { transform: translateY(110vh) translateX(60px) rotate(360deg); opacity: ${cfg.opacityMin}; }
}
@keyframes snow-fall-2 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax * 0.9}; }
100% { transform: translateY(110vh) translateX(-50px) rotate(-300deg); opacity: ${cfg.opacityMin}; }
}
@keyframes snow-fall-3 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax}; }
100% { transform: translateY(110vh) translateX(80px) rotate(420deg); opacity: ${cfg.opacityMin * 0.8}; }
}`;
} else if (cfg.animationType === 'float') {
css += `
@keyframes firefly-float-1 {
0% { transform: translate(0,0) scale(1); opacity: ${cfg.opacityMin}; }
25% { transform: translate(35px,-25px) scale(1.4); opacity: ${cfg.opacityMax}; }
50% { transform: translate(-20px,-45px) scale(0.7); opacity: ${cfg.opacityMin + 0.1}; }
75% { transform: translate(-35px,-10px) scale(1.2); opacity: ${cfg.opacityMax * 0.7}; }
100% { transform: translate(0,0) scale(1); opacity: ${cfg.opacityMin}; }
}
@keyframes firefly-float-2 {
0% { transform: translate(0,0) scale(0.9); opacity: ${cfg.opacityMin + 0.1}; }
30% { transform: translate(-30px,-30px) scale(1.5); opacity: ${cfg.opacityMax}; }
60% { transform: translate(25px,-50px) scale(0.6); opacity: ${cfg.opacityMin}; }
85% { transform: translate(20px,-5px) scale(1.1); opacity: ${cfg.opacityMax * 0.6}; }
100% { transform: translate(0,0) scale(0.9); opacity: ${cfg.opacityMin + 0.1}; }
}
@keyframes firefly-float-3 {
0% { transform: translate(0,0) scale(1.1); opacity: ${cfg.opacityMax * 0.5}; }
20% { transform: translate(20px,-15px) scale(1.6); opacity: ${cfg.opacityMax}; }
55% { transform: translate(-40px,-35px) scale(0.8); opacity: ${cfg.opacityMin}; }
80% { transform: translate(-10px,-20px) scale(1.3); opacity: ${cfg.opacityMax * 0.7}; }
100% { transform: translate(0,0) scale(1.1); opacity: ${cfg.opacityMax * 0.5}; }
}`;
} else if (cfg.animationType === 'petal-fall') {
css += `
@keyframes petal-fall-1 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax}; }
100% { transform: translateY(110vh) translateX(70px) rotate(540deg); opacity: ${cfg.opacityMin}; }
}
@keyframes petal-fall-2 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax * 0.85}; }
100% { transform: translateY(110vh) translateX(-60px) rotate(-480deg); opacity: ${cfg.opacityMin}; }
}
@keyframes petal-fall-3 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax}; }
100% { transform: translateY(110vh) translateX(90px) rotate(600deg); opacity: ${cfg.opacityMin * 0.7}; }
}`;
} else if (cfg.animationType === 'confetti-fall') {
css += `
@keyframes confetti-fall-1 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax}; }
100% { transform: translateY(110vh) translateX(50px) rotate(720deg); opacity: ${cfg.opacityMin}; }
}
@keyframes confetti-fall-2 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax * 0.9}; }
100% { transform: translateY(110vh) translateX(-70px) rotate(-600deg); opacity: ${cfg.opacityMin}; }
}
@keyframes confetti-fall-3 {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: ${cfg.opacityMax}; }
100% { transform: translateY(110vh) translateX(100px) rotate(900deg); opacity: ${cfg.opacityMin * 0.6}; }
}`;
}
return css;
}
// 事件绑定
tool.find('.preset-btn').on('click', function() {
const presetKey = $(this).data('preset');
if (presetKey && presets[presetKey]) {
applyPreset(presetKey);
}
});
// 参数变化时更新预览
const debouncedUpdate = debounce(function() {
const cfg = getUIParams();
currentConfig = { ...currentConfig, ...cfg };
updateParamLabels(cfg);
generateParticles();
updateCodeOutput();
}, 300);
tool.find('#pt-count, #pt-min-size, #pt-max-size, #pt-speed, #pt-opacity-min, #pt-opacity-max').on('input', function() {
const cfg = getUIParams();
updateParamLabels(cfg);
debouncedUpdate();
});
tool.find('#pt-bg-color, #pt-particle-color, #pt-particle-color2').on('input', function() {
const cfg = getUIParams();
tool.find('#pt-bg-color-hex').text(cfg.bgColor);
tool.find('#pt-particle-color-hex').text(cfg.particleColor);
preview.css('background', cfg.bgColor);
debouncedUpdate();
});
tool.find('#pt-glow').on('change', function() {
debouncedUpdate();
});
tool.find('#pt-refresh-btn').on('click', function() {
const cfg = getUIParams();
currentConfig = { ...currentConfig, ...cfg };
updateParamLabels(cfg);
generateParticles();
updateCodeOutput();
const btn = $(this);
btn.html('
已刷新');
setTimeout(() => btn.html('
刷新预览'), 1000);
});
// 复制按钮
copyBtn.on('click', function() {
const code = codeOutput.text();
if (navigator.clipboard) {
navigator.clipboard.writeText(code).then(() => {
showCopySuccess();
}).catch(() => {
fallbackCopy(code);
});
} else {
fallbackCopy(code);
}
});
function fallbackCopy(text) {
const ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
try { document.execCommand('copy'); showCopySuccess(); } catch(e) {}
document.body.removeChild(ta);
}
function showCopySuccess() {
copyBtn.addClass('copied');
copyBtn.html('
已复制');
setTimeout(() => {
copyBtn.removeClass('copied');
copyBtn.html('
复制');
}, 1800);
}
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 窗口大小变化时重建粒子
let resizeTimer;
$(window).on('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
generateParticles();
}, 400);
});
// 初始化
function init() {
applyPreset('stars');
generateParticles();
updateCodeOutput();
}
// 页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();