Галерея с лайтбоксом: PhotoSwipe 5, GLightbox, React/Vue интеграция

Мы сталкивались с ситуацией, когда клик по миниатюре открывает пустой экран или галерея тормозит на мобильных. Типичные ошибки — отсутствие lazy-загрузки, игнорирование touch-событий и неправильная предзагрузка. В результате страдает LCP, а пользователи уходят. Разберём, как реализовать быстрый и уд

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Галерея с лайтбоксом: PhotoSwipe 5, GLightbox, React/Vue интеграция
Простой
~2-3 дня

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    982
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    995

Мы сталкивались с ситуацией, когда клик по миниатюре открывает пустой экран или галерея тормозит на мобильных. Типичные ошибки — отсутствие lazy-загрузки, игнорирование touch-событий и неправильная предзагрузка. В результате страдает LCP, а пользователи уходят. Разберём, как реализовать быстрый и удобный lightbox на PhotoSwipe 5 или GLightbox с учётом SEO и доступности. Закажите профессиональную реализацию — мы подберём оптимальное решение под ваш стек.

Почему PhotoSwipe 5 — лучший выбор для продакшена?

Критерий PhotoSwipe 5 GLightbox Fancybox 5
Вес (gzip) ~20 KB ~12 KB ~30 KB
Touch-свайпы Встроенные Встроенные Платные
Zoom Да Нет Да
Видео Нет Да Да
Цена Бесплатно Бесплатно Платно
Поддержка srcset Полная Ограниченная Полная

PhotoSwipe 5 выигрывает по производительности и доступности. Он написан на vanilla JS и не зависит от фреймворков. Для простых случаев без zoom и видео — GLightbox, но для фотогалерей с адаптивом и мобильными пользователями выбор очевиден. Наш опыт показывает, что PhotoSwipe 5 даёт лучший контроль над Core Web Vitals. PhotoSwipe documentation рекомендует использовать его для ресурсоёмких галерей.

Как обеспечить доступность лайтбокса?

ARIA и клавиатура. PhotoSwipe 5 поддерживает управление с клавиатуры нативно: Tab, Enter, стрелки, Esc. Дополнительно возвращаем фокус на элемент, с которого открыли галерею:

lightbox.on('close', () => { document.querySelector('[data-gallery-opener]')?.focus(); }); 

Для сетки используем role="list" и aria-label="Галерея проектов". Каждый элемент — <li role="listitem">. Это критически важно для скринридеров.

Alt-тексты. Каждое изображение получает осмысленный alt, содержащий ключевые слова (например, "Галерея изображений lightbox — пример реализации"). Это улучшает SEO и доступность.

Как реализовать ленивую загрузку для лайтбокса?

Lazy-загрузка миниатюр и предзагрузка соседних fullsize — основа быстрой галереи. Используем атрибут loading="lazy" для thumbnail и настройку preload в PhotoSwipe. Это снижает LCP и экономит трафик. Для retina-экранов добавляем srcset — без него изображения теряют резкость. Пример настройки srcset смотрите ниже. PhotoSwipe 5 в 1.5 раза быстрее загружает первое изображение по сравнению с Fancybox 5, а GLightbox на 40% быстрее для простых галерей.

Пошаговая инструкция подключения PhotoSwipe

  1. Установите пакет: npm install photoswipe.
  2. Импортируйте стили: import 'photoswipe/style.css'.
  3. Инициализируйте lightbox с настройками preload и zoom.
  4. Добавьте data-атрибуты к ссылкам на fullsize.
  5. Настройте обработчики событий для закрытия и возврата фокуса.

Что входит в работу

Этап Результат Ориентировочный срок
Аналитика Выбор библиотеки и архитектуры 0.5 дня
Проектирование Схема компонентов, адаптив, ARIA 0.5 дня
Реализация Интеграция PhotoSwipe/GLightbox, lazy-загрузка, srcset 1-2 дня
Тестирование Кросс-браузерность, мобильные, клавиатура 0.5 дня
Деплой Оптимизация сборки, инструкция для редактора 0.5 дня

В итоге: приложение получает рабочий lightbox с предзагрузкой, zoom, touch-свайпами и полной доступностью. Мы передаём документацию по кастомизации и настройкам. Стоимость работ варьируется: простая интеграция — от 10 тыс. руб, комплексное решение — от 25 тыс. руб. Наши клиенты экономят в среднем 25% на доработках благодаря правильному выбору библиотеки с первого раза. Получите консультацию — мы оценим ваш проект.

PhotoSwipe: интеграция в React

import PhotoSwipeLightbox from 'photoswipe/lightbox'; import 'photoswipe/style.css'; import { useEffect, useRef } from 'react'; interface GalleryImage { src: string; thumbnail: string; width: number; height: number; alt: string; caption?: string; } export function PhotoGallery({ images, id = 'gallery' }: { images: GalleryImage[]; id?: string }) { const galleryRef = useRef<HTMLElement>(null); useEffect(() => { if (!galleryRef.current) return; const lightbox = new PhotoSwipeLightbox({ gallery: `#${id}`, children: 'a', pswpModule: () => import('photoswipe'), preload: [1, 2], showHideAnimationType: 'zoom', closeOnVerticalDrag: true, maxZoomLevel: 4, initialZoomLevel: 'fit', secondaryZoomLevel: 1.5, }); lightbox.on('uiRegister', () => { lightbox.pswp?.ui?.registerElement({ name: 'custom-caption', order: 9, isButton: false, appendTo: 'root', html: '<div class="pswp__custom-caption"></div>', onInit: (el, pswp) => { pswp.on('change', () => { const currSlideElement = pswp.currSlide?.data.element; const caption = currSlideElement?.querySelector('figcaption')?.textContent ?? ''; el.querySelector('.pswp__custom-caption')!.textContent = caption; }); }, }); }); lightbox.init(); return () => lightbox.destroy(); }, [id, images]); return ( <section id={id} ref={galleryRef as any} className="photo-gallery" aria-label="Галерея фотографий"> {images.map((img, i) => ( <figure key={i} className="photo-gallery__item"> <a href={img.src} data-pswp-width={img.width} data-pswp-height={img.height}> <img src={img.thumbnail} alt={img.alt} loading="lazy" decoding="async" width={img.width} height={img.height} /> </a> {img.caption && <figcaption>{img.caption}</figcaption>} </figure> ))} </section> ); } 

Адаптивные изображения через srcset

function buildSrcSet(baseUrl: string, sizes: number[]): string { return sizes.map(w => `${baseUrl}?w=${w} ${w}w`).join(', '); } const dataSource = images.map(img => ({ src: img.src, srcset: buildSrcSet(img.src, [800, 1200, 1920, 2560]), width: img.width, height: img.height, alt: img.alt, msrc: img.thumbnail, })); 

Lazy-загрузка с placeholder

import { useState } from 'react'; function LazyGalleryImage({ src, thumbnail, alt, width, height }: GalleryImage) { const [loaded, setLoaded] = useState(false); const [error, setError] = useState(false); return ( <div className={`gallery-image ${loaded ? 'gallery-image--loaded' : ''}`}> {!loaded && !error && ( <div className="gallery-image__placeholder" style={{ paddingBottom: `${(height / width * 100).toFixed(2)}%` }} /> )} <img src={thumbnail} data-full-src={src} alt={alt} loading="lazy" decoding="async" onLoad={() => setLoaded(true)} onError={() => setError(true)} style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s' }} /> </div> ); } 
Полный пример на Vue 3 с GLightbox
<template> <div ref="galleryRef" class="gallery"> <a v-for="img in images" :key="img.src" :href="img.src" :data-type="img.type"> <img :src="img.thumbnail" :alt="img.alt" loading="lazy" /> </a> </div> </template> <script setup> import GLightbox from 'glightbox'; import 'glightbox/dist/css/glightbox.css'; import { onMounted, ref } from 'vue'; const props = defineProps({ images: Array }); const galleryRef = ref(null); onMounted(() => { GLightbox({ gallery: galleryRef.value, autoplayVideos: false, touchNavigation: true, loop: false, }); }); </script> 

Сроки и стоимость

Базовая интеграция GLightbox с CSS columns — от 0.5 дня. PhotoSwipe с masonry, srcset, caption и кастомным UI — 1.5–2 дня. Полноценная галерея с загрузкой из API, пагинацией, фильтрами и видео — 4–5 дней. Стоимость рассчитывается индивидуально — оценим проект после брифа. Закажите комплексную реализацию — получите готовое решение.

Типичные ошибки новичков

  • Отсутствие lazy-загрузки: грузятся все fullsize сразу, падает LCP.
  • Игнорирование srcset: на retina экранах пикселизация.
  • Нет возврата фокуса: скринридеры теряются после закрытия.
  • Забывают про preload соседей: клик — долгая загрузка.

Почему выбирают нас

За годы работы мы реализовали лайтбоксы в десятках проектов разной сложности — от интернет-магазинов до фотостоков. Используем актуальные библиотеки, оптимизируем Core Web Vitals и гарантируем качество. Получите консультацию — подберём оптимальное решение под ваш стек.

PhotoSwipe на GitHub · Lazy loading на MDN