Галерея PhotoSwipe 5 та GLightbox: лайтбокс для React/Vue

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

Розробка та обслуговування будь-яких видів сайтів:

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

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

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

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

Часті запитання

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1467
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1317
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1014
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1276
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1019
  • Розробка веб-сайту для компанії ФІКСПЕР
    Розробка веб-сайту для компанії ФІКСПЕР
    1019

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