Radial Explosion Zoom Gallery Effect

This is a “bomb blast” or “explosion zoom” gallery effect — where clicking a thumbnail pushes all other images outward and centers/zooms the selected one, creating a dramatic, explosive layout transition.
Below is a complete working example using HTML, CSS, and JavaScript (vanilla) to recreate this effect.

Features:

  • Grid of images
  • Click any image → it expands to center
  • All other images shrink and scatter around it
  • Click again or outside → reset to grid
  • Smooth animations with CSS transitions
  • Responsive & works on any screen
<div class="overlay" id="overlay"></div>
<div class="gallery" id="gallery"></div>

CSS

* {margin:0;padding:0;box-sizing:border-box;}
  body {background:#000;overflow:hidden;height:100vh;font-family:sans-serif;}
  .gallery {position:relative;width:100vw;height:100vh;}
  .item {
    position:absolute;
    cursor:pointer;
    border-radius:8px;
    overflow:hidden;
    box-shadow:0 4px 12px rgba(0,0,0,.5);
    transition: all .7s cubic-bezier(.2,.8,.2,1);
    transform-origin:center;
  }
  .item img {width:100%;height:100%;object-fit:cover;display:block;}
  .like {position:absolute:absolute;top:6px;right:6px;width:26px;height:26px;
    background:rgba(255,255,255,.2);border-radius:50%;display:flex;
    align-items:center;justify-content:center;font-size:15px;opacity:0;
    transition:.3s;backdrop-filter:blur(4px);}
  .item:hover .like,.item.expanded .like{opacity:1;}

  .caption {
    position:absolute;bottom:0px;left:0;right:0; 
    background:linear-gradient(transparent,rgba(0,0,0,.8));
    color:#fff;padding-bottom:25px;text-align:center;font-size:13px;opacity:0; line-height:25px;
    transition:opacity .4s;pointer-events:none;
  }
  .item.expanded .caption{opacity:1;font-size:16px;}
  .overlay{
    position:fixed;inset:0;background:rgba(0,0,0,.8);
    opacity:0;pointer-events:none;transition:opacity .5s;z-index:999;
  }
  .overlay.active{opacity:0.25;pointer-events:all;}

Javascript

createImages():- Makes all image boxes once
arrangeImages():- Puts them in a circle
expandImage():- Makes one big + pushes others away
closeExpanded():- Returns everything to normal

  /* ============================================================= */
  /*            BOMB BLAST GALLERY - WITH HOVER LIFT EFFECT         */
  /* ============================================================= */

  // === STEP 1: SETTINGS ===
  const TOTAL_IMAGES = 50;
  const EXPANDED_WIDTH = 380;
  const EXPANDED_HEIGHT = 500;
  const MIN_SIZE = 70;
  const MAX_SIZE = 120;

  // === STEP 2: Sample Artworks ===
  const artworks = [
    { url: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Frans_Hals_-_Portrait_of_Tieleman_Roosterman.jpg/800px-Frans_Hals_-_Portrait_of_Tieleman_Roosterman.jpg",
      title: "Portrait of Tieleman Roosterman (1654)", artist: "Frans Hals", views: "213" },
    { url: "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg/800px-Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg",
      title: "Starry Night", artist: "Vincent van Gogh", views: "1.2M" },
    { url: "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/687px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg",
      title: "Mona Lisa", artist: "Leonardo da Vinci", views: "3.5M" },
    { url: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/The_Great_Wave_off_Kanagawa.jpg/800px-The_Great_Wave_off_Kanagawa.jpg",
      title: "The Great Wave", artist: "Hokusai", views: "890K" }
  ];

  // === STEP 3: Get HTML elements ===
  const gallery = document.getElementById('gallery');
  const overlay = document.getElementById('overlay');

  // === STEP 4: Store image boxes and data ===
  let imageBoxes = [];
  let originalData = [];
  let expandedIndex = null;

  // === STEP 5: Create all images ===
  function createImages() {
    for (let i = 0; i < TOTAL_IMAGES; i++) {
      const box = document.createElement('div');
      box.className = 'item';

      const img = document.createElement('img');
      img.loading = 'lazy';

      if (i < artworks.length) {
        img.src = artworks[i].url;
        box.dataset.title = artworks[i].title;
        box.dataset.artist = artworks[i].artist;
        box.dataset.views = artworks[i].views;
      } else {
        img.src = `https://picsum.photos/300/400?random=${i}`;
        box.dataset.title = `Artwork #${i + 1}`;
        box.dataset.artist = `Artist ${i + 1}`;
        box.dataset.views = `${Math.floor(Math.random() * 2000)}K`;
      }

      const like = document.createElement('div');
      like.className = 'like';
      like.textContent = 'Heart';

      const caption = document.createElement('div');
      caption.className = 'caption';
      caption.innerHTML = `
        <strong>${box.dataset.title}</strong><br>
        <em>${box.dataset.artist}</em><br>
        <small>On view in ${box.dataset.views} museums</small>
      `;

      box.appendChild(img);
      box.appendChild(like);
      box.appendChild(caption);
      gallery.appendChild(box);

      imageBoxes.push(box);

      const size = MIN_SIZE + Math.random() * (MAX_SIZE - MIN_SIZE);
      const width = size;
      const height = size * 1.3;
      originalData[i] = { width, height };

      // === HOVER EFFECT: Lift on mouse over ===
      box.addEventListener('mouseenter', () => {
        if (expandedIndex !== null) return; // Don't lift if something is expanded
        box.style.zIndex = 10;
        box.style.transform = 'scale(1.05)'; // Optional: slight grow
      });

      box.addEventListener('mouseleave', () => {
        if (expandedIndex !== null) return;
        box.style.zIndex = 1;
        box.style.transform = 'scale(1)';
      });

      box.onclick = () => toggleImage(i);
    }

    arrangeImages();
  }

  // === STEP 6: Arrange in circle ===
  function arrangeImages() {
    const centerX = window.innerWidth / 2;
    const centerY = window.innerHeight / 2;

    imageBoxes.forEach((box, i) => {
      const data = originalData[i];
      const angle = (i / TOTAL_IMAGES) * 2 * Math.PI;
      const distance = 100 + (i % 4) * 80;

      const x = centerX + Math.cos(angle) * distance - data.width / 2;
      const y = centerY + Math.sin(angle) * distance - data.height / 2;

      data.x = x;
      data.y = y;

      box.style.left = x + 'px';
      box.style.top = y + 'px';
      box.style.width = data.width + 'px';
      box.style.height = data.height + 'px';
      box.style.opacity = 1;
      box.style.transform = 'rotate(0deg) scale(1)';
      box.style.zIndex = 1; // Reset z-index
    });
  }

  // === STEP 7: Toggle expand ===
  function toggleImage(index) {
    if (expandedIndex === index) {
      closeExpanded();
    } else {
      expandImage(index);
    }
  }

  // === STEP 8: Expand image ===
  function expandImage(index) {
    if (expandedIndex !== null) closeExpanded();
    expandedIndex = index;
    overlay.classList.add('active');

    const centerX = window.innerWidth / 2;
    const centerY = window.innerHeight / 2;

    imageBoxes.forEach((box, i) => {
      const data = originalData[i];

      if (i === index) {
        box.classList.add('expanded');
        box.style.left = (centerX - EXPANDED_WIDTH / 2) + 'px';
        box.style.top = (centerY - EXPANDED_HEIGHT / 2) + 'px';
        box.style.width = EXPANDED_WIDTH + 'px';
        box.style.height = EXPANDED_HEIGHT + 'px';
        box.style.zIndex = 1000;
        box.style.transform = 'scale(1)';
      } else {
        const rect = box.getBoundingClientRect();
        const boxCenterX = rect.left + rect.width / 2;
        const boxCenterY = rect.top + rect.height / 2;

        const dx = boxCenterX - centerX;
        const dy = boxCenterY - centerY;
        const distance = Math.sqrt(dx * dx + dy * dy) || 1;
        const angle = Math.atan2(dy, dx);
        const pushDistance = distance * 1.5 + 300;

        const newX = centerX + Math.cos(angle) * pushDistance - data.width / 2;
        const newY = centerY + Math.sin(angle) * pushDistance - data.height / 2;

        box.style.left = newX + 'px';
        box.style.top = newY + 'px';
        box.style.width = data.width * 0.6 + 'px';
        box.style.height = data.height * 0.6 + 'px';
        box.style.opacity = 0.7;
        box.style.transform = `rotate(${angle * 180 / Math.PI + 720}deg) scale(0.6)`;
        box.style.zIndex = 10;
      }
    });
  }

  // === STEP 9: Close expanded ===
  function closeExpanded() {
    overlay.classList.remove('active');
    expandedIndex = null;

    imageBoxes.forEach((box, i) => {
      const data = originalData[i];
      box.classList.remove('expanded');
      box.style.left = data.x + 'px';
      box.style.top = data.y + 'px';
      box.style.width = data.width + 'px';
      box.style.height = data.height + 'px';
      box.style.opacity = 1;
      box.style.transform = 'rotate(0deg) scale(1)';
      box.style.zIndex = 1;
    });
  }

  // === STEP 10: Events ===
  overlay.onclick = closeExpanded;
  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') closeExpanded();
  });

  window.addEventListener('resize', () => {
    if (expandedIndex === null) {
      arrangeImages();
    } else {
      expandImage(expandedIndex);
    }
  });

  // === STEP 11: Start ===
  createImages();

Working Demo

Similar Posts