Розробка галереї зображень товару із зумом для інтернет-магазину

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка галереї зображень товару із зумом для інтернет-магазину
Середня
~2-3 робочих дні
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка галереї зображень товару з зумом для інтернет-магазину

Галерея зображень — основний інструмент вивчення товару. Покупець не може потрогнути продукт, тому якість та функціональність галереї напрямки впливають на довіру та конверсію. Технічно галерея — це більше, ніж набір зображень: це управління великими зображеннями, оптимізація завантаження, зум без втрати якості та бездоганне відчуття на тачскрині.

Формати та обробка зображень

Зберігаємо максимальну роздільну здатність (2000–4000px по довгій стороні), віддаємо потрібний розмір. Не подаємо 5MB оригіналу на кожну сторінку.

Pipeline обробки при завантаженні нового зображення:

Завантаження оригіналу → S3 (originals/, приватний)
  ↓ Worker (libvips)
Генерація варіантів:
  - thumbnail: 100×100, JPEG 80%
  - small: 400×400, JPEG 85%
  - medium: 800×800, JPEG 90%
  - large: 1600×1600, JPEG 95%
  - webp: кожен варіант у WebP (30-50% менше)
  ↓
CDN (публічний бакет або Cloudflare Images)

libvips швидше ImageMagick в 4–8 разів. Для PHP — intervention/image з libvips-драйвером, для Node.js — sharp.

Сучасний <picture> з WebP:

<picture>
  <source srcset="product-800.webp" type="image/webp">
  <img src="product-800.jpg" alt="Nike Air Max 90 — вид сбоку"
       width="800" height="800" loading="lazy">
</picture>

Структура компонента галереї

Типова розмітка карточки: основний слот (велике зображення) + смуга тумбнейлів знизу або зліва. На десктопе — горизонтальний або вертикальний strip, на мобайле — свайп за основним слотом.

function ProductGallery({ images, activeVariantImages }: Props) {
  const [activeIndex, setActiveIndex] = useState(0);
  const [isZoomed, setIsZoomed] = useState(false);

  // При зміні варіанту — скид на перше зображення варіанту
  useEffect(() => {
    setActiveIndex(0);
  }, [activeVariantImages]);

  const allImages = [...activeVariantImages, ...images.filter(
    img => !activeVariantImages.find(v => v.id === img.id)
  )];

  return (
    <div className="gallery">
      <MainSlot image={allImages[activeIndex]} onZoom={() => setIsZoomed(true)} />
      <Thumbnails images={allImages} activeIndex={activeIndex} onSelect={setActiveIndex} />
      {isZoomed && <LightboxOverlay images={allImages} startIndex={activeIndex} />}
    </div>
  );
}

Зум при наведенні (hover zoom)

Класичний паттерн для десктопа: при наведенні курсора на зображення, рядом (або поверх) з'являється збільшена область. Техніка реалізації:

function useHoverZoom(containerRef: RefObject<HTMLDivElement>, scale = 2.5) {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseMove = (e: MouseEvent) => {
    const rect = containerRef.current!.getBoundingClientRect();
    const x = ((e.clientX - rect.left) / rect.width) * 100;
    const y = ((e.clientY - rect.top) / rect.height) * 100;
    setPosition({ x, y });
  };

  return { position, handlers: { onMouseMove: handleMouseMove } };
}

Зображення для зуму в 2–3 рази більше контейнера. Альтернатива: lens zoom — невеликий лінза на оригіналі показує область в збільшеному вікні рядом.

Pinch-to-zoom для мобайлу

react-zoom-pan-pinch — бібліотека для цього:

import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch';

<TransformWrapper minScale={1} maxScale={4} doubleClick={{ mode: 'zoomIn' }}>
  <TransformComponent>
    <img src={largeImageUrl} alt={alt} />
  </TransformComponent>
</TransformWrapper>

Коли зум активний горизонтальний свайп відключен, при scale=1 дозволен.

Lightbox / повноекранний перегляд

При клику на зображення (десктоп) або кнопку «Повний екран» — відкривається modal/lightbox з зображенням на весь екран. Вимоги:

  • Закриття по Escape та клику за межами
  • Переключення стрілками клавіатури (Left/Right)
  • Swipe на мобайле
  • Кнопки превью внизу
  • URL не змінюється (або хеш: #image-3)

yet-another-react-lightbox або PhotoSwipe (5kb gzip, відмінна мобільна підтримка).

Послідовна загрузка зображень

Неможливо грузити всі зображення галереї одразу. Стратегія:

  1. Перше зображенняloading="eager", fetchpriority="high", preload в <head>
  2. Тумбнейли — маленькі файли, грузим все (вони невеликі)
  3. Решта large зображеньloading="lazy" або завантажуємо при клику на тумбнейл
function loadImageOnDemand(index: number, images: GalleryImage[]) {
  if (loadedIndexes.has(index)) return;
  const img = new Image();
  img.src = images[index].largeUrl;
  img.onload = () => setLoadedIndexes(prev => new Set([...prev, index]));
}

При переході до N — предзагружаємо N+1 та N-1.

Підтримка відео в галереї

Багато магазинів додають відео-огляд прямо в галереї — між зображеннями. Тумбнейл відео — стоп-кадр з іконкою play. При виборі — відео завантажується lazily (<video preload="none">).

Формати: MP4/H.264 (максимальна сумісність) + WebM/VP9 (менший розмір). Автопроигрывание — тільки muted.

<video controls preload="none" poster="poster.jpg">
  <source src="review.webm" type="video/webm">
  <source src="review.mp4" type="video/mp4">
</video>

Зображення по варіантам

Кожен варіант товару (колір) має свій набір зображень. При виборі варіанту:

  • Галерея переключається на зображення цього варіанту
  • Плавна анімація переходу (crossfade або slide)
  • Тумбнейл вибраного варіанту підсвічується

У БД: product_images (id, product_id, variant_id, url, sort_order). При variant_id IS NULL — спільні зображення, показуються для всіх варіантів.

Терміни

  • Базова галерея (слайдер + тумбнейли + lazy load): 3–5 робочих днів
  • З hover-zoom та lightbox: 1–1.5 тижні
  • З pinch-to-zoom, відео та по-варіантними зображеннями: 2–3 тижні
  • Pipeline генерації превю (libvips + S3 + CDN): +1 тиждень