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

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, 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

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

Галерея изображений — основной инструмент изучения товара. Покупатель не может потрогать продукт, поэтому качество и функциональность галереи напрямую влияют на доверие и конверсию. Технически галерея — это больше, чем набор <img>. Это управление большими изображениями, оптимизация загрузки, зум без потери резкости и seamless опыт на тачскрине.

Форматы и подготовка изображений

Магазин должен хранить изображение в максимальном разрешении (2000–4000px по длинной стороне) и раздавать нужный размер под контекст. Раздавать оригинал 5MB на каждую страницу — грубая ошибка.

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

Загрузка оригинала → S3 (originals/, приватный)
  ↓ Worker (imagemagick / 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% меньше JPEG)
  ↓
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)}
        isZoomed={isZoomed}
      />
      <Thumbnails
        images={allImages}
        activeIndex={activeIndex}
        onSelect={setActiveIndex}
      />
      {isZoomed && (
        <LightboxOverlay
          images={allImages}
          startIndex={activeIndex}
          onClose={() => setIsZoomed(false)}
        />
      )}
    </div>
  );
}

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

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

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

  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, isHovering, handlers: { onMouseMove: handleMouseMove, ... } };
}

Отображение зума через CSS transform: scale() с transform-origin в точке курсора. Изображение для зума должно быть в 2–3 раза больше контейнера — иначе зум будет размытым.

Альтернатива: lens zoom — небольшая линза на оригинальном изображении показывает область в увеличенном окне рядом. Реализуется через абсолютно позиционированный div с background-image и background-size: {scale*100}%.

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

На тачскрине hover-зум не работает. Нужен pinch-to-zoom и/или двойной тап для увеличения.

React-zoom-pan-pinch — библиотека для этого. Поддерживает pinch, double tap, wheel zoom, panning:

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 — только pan, при scale === 1 — разрешаем свайп.

Lightbox / полноэкранный просмотр

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

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

Для lightbox: yet-another-react-lightbox или PhotoSwipe (5kb gzip, отличная мобильная поддержка). PhotoSwipe работает нативно с touch events, имеет progressive loading (показывает thumb, пока грузится large).

Последовательная загрузка изображений

Нельзя грузить все изображения галереи сразу — это замедляет LCP. Стратегия:

  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 (neighbour prefetch).

Поддержка видео в галерее

Многие магазины добавляют видео-обзор прямо в галерею — между изображениями. Тумбнейл видео — стоп-кадр с иконкой 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 неделя если с нуля