Ср. Апр 8th, 2026

Как Создать Эффект Взрыва Конфетти с Использованием JavaScript

Как создать эффект взрыва конфетти с помощью JavaScript

Чувствуете, что вашему веб-сайту не хватает чего-то… праздничного? Будь то регистрация пользователя, завершение задачи или просто нажатие кнопки «Праздновать!», взрыв конфетти — это классический способ добавить нотку восторга.

Сегодня мы разработаем легкий и высокопроизводительный эффект взрыва конфетти, используя API HTML5 Canvas. Никаких громоздких внешних библиотек не требуется — только один скрипт и немного желания.

Посмотрите Конфетти в Действии

Как Работает JavaScript Код для Конфетти

Скрипт динамически создает элемент <canvas>, который покрывает весь экран. При клике на элемент с классом .confetti скрипт вычисляет его центр и генерирует 150 уникальных частиц.

Каждая частица имеет свои:

  • Физика: Скорость, гравитация и сопротивление воздуха применяются к каждой частице на каждом кадре.
  • Эстетика: Рандомизированные цвета из подобранной палитры и различные размеры.
  • Движение: Фактор вращения и поворот, чтобы имитировать падение настоящей бумаги.
  • Жизненный цикл: Затухание прозрачности, благодаря которому частицы исчезают до того, как они будут удалены из памяти.

JavaScript Код

Вы можете интегрировать этот скрипт в свой проект.

<script src='confetti.js'></script>

Он обернут в IIFE (Immediately Invoked Function Expression) для поддержания чистоты глобального пространства имен.

(function () {
  const PARTICLE_COUNT = 150;
  const COLORS = [
    '#ff0a54', '#ff477e', '#ff7096', '#ff85a1',
    '#fbb1bd', '#f9bec7', '#3a86ff', '#8338ec',
    '#ffbe0b', '#fb5607', '#06d6a0', '#118ab2',
  ];
  const GRAVITY = 0.12;
  const DRAG = 0.98;
  const SPIN_DRAG = 0.97;

  let canvas, ctx, particles, animId;

  function createCanvas() {
    canvas = document.createElement('canvas');
    // Set styles to cover the viewport and ignore mouse events
    canvas.style.cssText =
      'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:2147483647';
    document.body.appendChild(canvas);
    ctx = canvas.getContext('2d');
    resize();
    window.addEventListener('resize', resize);
  }

  function resize() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
  }

  function randomBetween(a, b) {
    return a + Math.random() * (b - a);
  }

  function createParticle(x, y) {
    const angle = randomBetween(0, 2 * Math.PI);
    const speed = randomBetween(6, 18);
    return {
      x: x,
      y: y,
      vx: Math.cos(angle) * speed,
      vy: Math.sin(angle) * speed - randomBetween(2, 8),
      w: randomBetween(6, 12),
      h: randomBetween(4, 8),
      color: COLORS[Math.floor(Math.random() * COLORS.length)],
      rotation: randomBetween(0, 2 * Math.PI),
      spin: randomBetween(-0.3, 0.3),
      opacity: 1,
      decay: randomBetween(0.006, 0.012),
    };
  }

  function explode(originX, originY) {
    if (!canvas) createCanvas();
    // Restart animation if one is already running
    if (animId) cancelAnimationFrame(animId);

    particles = [];
    for (let i = 0; i < PARTICLE_COUNT; i++) {
      particles.push(createParticle(originX, originY));
    }
    animate();
  }

  function animate() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    for (let i = particles.length - 1; i >= 0; i--) {
      const p = particles[i];

      // Physics logic
      p.vx *= DRAG;
      p.vy *= DRAG;
      p.vy += GRAVITY;
      p.x += p.vx;
      p.y += p.vy;
      p.rotation += p.spin;
      p.spin *= SPIN_DRAG;
      p.opacity -= p.decay;

      if (p.opacity <= 0) {
        particles.splice(i, 1);
        continue;
      }

      // Drawing logic
      ctx.save();
      ctx.translate(p.x, p.y);
      ctx.rotate(p.rotation);
      ctx.globalAlpha = p.opacity;
      ctx.fillStyle = p.color;
      ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
      ctx.restore();
    }

    if (particles.length > 0) {
      animId = requestAnimationFrame(animate);
    } else {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      animId = null;
    }
  }

  // Global Click Listener
  document.addEventListener('click', function (e) {
    const trigger = e.target.closest('.confetti');
    if (!trigger) return;
    
    const rect = trigger.getBoundingClientRect();
    const cx = rect.left + rect.width / 2;
    const cy = rect.top + rect.height / 2;
    explode(cx, cy);
  });
})();

Руководство по Внедрению

  1. Добавьте скрипт: Скопируйте приведенный выше код в файл .js и подключите его в конце <body>, или поместите его непосредственно в ваш HTML внутри тегов <script>.
  2. Пометьте ваш триггер: Вам не нужно писать дополнительный JavaScript для кнопок. Просто добавьте класс confetti к любой кнопке, ссылке или div, который вы хотите использовать: <button class='confetti'>Нажми меня!</button>
  3. Настройте:

    • Хотите больше конфетти? Измените значение PARTICLE_COUNT.
    • Хотите другую атмосферу? Обновите массив COLORS с шестнадцатеричными кодами цветов вашего бренда.
    • Хотите более ‘плавающие’ конфетти? Уменьшите значение GRAVITY.

Удачного празднования! 🥳

By Дмитрий Корсаков

Дмитрий Корсаков - спортивный журналист с 15-летним опытом работы в Екатеринбурге. Специализируется на освещении хоккея и фигурного катания. Начинал карьеру как блогер, сейчас - штатный автор нескольких федеральных спортивных изданий.

Related Post