Галерея с лайтбоксом на WordPress без плагинов

Галерея с лайтбоксом на WordPress позволяет показывать изображения в компактной сетке, а при клике открывать выбранную фотографию поверх страницы. Посетителю не приходится переходить на отдельную запись или загружать полноразмерный файл в новой вкладке: затемнённое окно отображает картинку, а стрелки помогают листать остальные изображения.

Плагин для такой задачи не обязателен. Достаточно подготовить разметку, добавить несколько правил CSS и подключить небольшой JavaScript-скрипт через тему. Такой подход даёт полный контроль над внешним видом, не создаёт лишних пунктов в панели управления и помогает избежать зависимости от редко обновляемого расширения.

Подход Преимущества Ограничения
Готовый плагин Быстрая настройка, дополнительные эффекты, управление из админки Лишний код, возможные конфликты и зависимость от обновлений
Чистые HTML, CSS и JavaScript Полный контроль, высокая скорость, минимум зависимостей Разметку и настройки нужно поддерживать самостоятельно
Блок галереи WordPress Удобное добавление изображений в редакторе Возможности лайтбокса зависят от темы и версии WordPress
Внешняя библиотека Красивые анимации, готовая навигация и поддержка жестов Нужно отдельно подключать файлы и следить за совместимостью

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

Сначала загрузите фотографии в медиабиблиотеку WordPress. Для миниатюры используйте уменьшенную версию изображения, а для лайтбокса укажите оригинал или заранее подготовленный файл среднего размера. Не стоит открывать снимок размером 6000×4000 пикселей, если посетителю достаточно ширины 1600 пикселей.

Удобная HTML-структура состоит из контейнера галереи и отдельных ссылок. Ссылка нужна для доступности, возможности открыть изображение без JavaScript и корректной работы клавиатуры. Атрибут href содержит большую картинку, data-caption — подпись, а элемент img показывает превью.

<div class="simple-gallery">
  <a class="simple-gallery__item"
     href="/wp-content/uploads/2025/03/photo-large.jpg"
     data-caption="Горный пейзаж">
    <img src="/wp-content/uploads/2025/03/photo-thumb.jpg"
         alt="Горный пейзаж"
         loading="lazy"
         width="480"
         height="320">
  </a>
</div>

Для нескольких изображений повторите блок a, меняя адреса и альтернативные описания. Атрибуты width и height помогают браузеру заранее зарезервировать место, поэтому страница меньше прыгает во время загрузки. Путь к файлам лучше получать средствами WordPress, если галерея формируется в шаблоне или шорткоде.

Разметка окна просмотра

Лайтбокс можно разместить один раз внизу шаблона страницы, сразу перед закрывающим тегом body. JavaScript будет подставлять в него выбранную фотографию. В окне понадобятся затемняющий фон, кнопка закрытия, изображение, подпись и две кнопки навигации.

<div class="lightbox" id="lightbox" aria-hidden="true">
  <div class="lightbox__backdrop" data-close></div>
  <div class="lightbox__dialog" role="dialog"
       aria-modal="true" aria-label="Просмотр изображения">
    <button class="lightbox__close" type="button"
            aria-label="Закрыть">×</button>
    <button class="lightbox__prev" type="button"
            aria-label="Предыдущее изображение">‹</button>
    <img class="lightbox__image" src="" alt="">
    <button class="lightbox__next" type="button"
            aria-label="Следующее изображение">›</button>
    <p class="lightbox__caption"></p>
  </div>
</div>

Кнопки получают понятные подписи для программ чтения с экрана. Атрибут aria-hidden="true" сообщает, что закрытое окно сейчас неактивно. При открытии его значение меняется на false, а фокус переводится на кнопку закрытия. Это делает интерфейс удобнее для пользователей, которые не применяют мышь.

Оформление сетки и лайтбокса

Сетку удобно создать с помощью CSS Grid. Свойство minmax() позволяет автоматически подбирать число колонок в зависимости от ширины экрана. object-fit: cover выравнивает карточки, даже если исходные фотографии имеют разные пропорции.

.simple-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
}

.simple-gallery__item {
  display: block;
  overflow: hidden;
  border-radius: 8px;
}

.simple-gallery__item img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform .2s ease, opacity .2s ease;
}

.simple-gallery__item:hover img,
.simple-gallery__item:focus img {
  opacity: .86;
  transform: scale(1.03);
}

Само окно просмотра должно занимать весь экран и располагаться поверх остальных элементов. Свойства position: fixed, inset: 0 и высокий z-index решают эту задачу. Ограничьте размеры изображения через max-width и max-height, чтобы оно не выходило за границы небольшого дисплея.

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;
  place-items: center;
  padding: 24px;
}

.lightbox.is-open {
  display: grid;
}

.lightbox__backdrop {
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 80%);
}

.lightbox__dialog {
  position: relative;
  z-index: 1;
  max-width: 1100px;
  max-height: 90vh;
  text-align: center;
}

.lightbox__image {
  display: block;
  max-width: 100%;
  max-height: 78vh;
  margin: auto;
}

.lightbox__close,
.lightbox__prev,
.lightbox__next {
  position: absolute;
  border: 0;
  color: #fff;
  background: rgb(0 0 0 / 55%);
  cursor: pointer;
  font-size: 30px;
}

.lightbox__close {
  top: -44px;
  right: 0;
}

.lightbox__prev,
.lightbox__next {
  top: 50%;
  padding: 4px 12px;
  transform: translateY(-50%);
}

.lightbox__prev { left: 12px; }
.lightbox__next { right: 12px; }

.lightbox__caption {
  margin: 10px 0 0;
  color: #fff;
}

Логика открытия на JavaScript

Скрипт собирает все ссылки внутри текущей галереи, запоминает индекс выбранного элемента и обновляет содержимое окна. При клике отменяется переход по href, после чего показывается полноразмерное изображение. Для вставки подписи безопаснее использовать textContent, а не innerHTML: текст из атрибута не сможет превратиться в исполняемую разметку.

document.querySelectorAll('.simple-gallery').forEach((gallery) => {
  const items = [...gallery.querySelectorAll('.simple-gallery__item')];
  const lightbox = document.querySelector('#lightbox');
  const image = lightbox.querySelector('.lightbox__image');
  const caption = lightbox.querySelector('.lightbox__caption');
  const closeButton = lightbox.querySelector('.lightbox__close');
  let current = 0;
  let previousFocus;

  function show(index) {
    current = (index + items.length) % items.length;
    const item = items[current];
    image.src = item.href;
    image.alt = item.querySelector('img').alt;
    caption.textContent = item.dataset.caption || '';
  }

  function open(index) {
    previousFocus = document.activeElement;
    show(index);
    lightbox.classList.add('is-open');
    lightbox.setAttribute('aria-hidden', 'false');
    document.body.classList.add('lightbox-lock');
    closeButton.focus();
  }

  function close() {
    lightbox.classList.remove('is-open');
    lightbox.setAttribute('aria-hidden', 'true');
    document.body.classList.remove('lightbox-lock');
    image.removeAttribute('src');
    if (previousFocus) previousFocus.focus();
  }

  items.forEach((item, index) => {
    item.addEventListener('click', (event) => {
      event.preventDefault();
      open(index);
    });
  });

  lightbox.querySelector('.lightbox__prev')
    .addEventListener('click', () => show(current - 1));
  lightbox.querySelector('.lightbox__next')
    .addEventListener('click', () => show(current + 1));
  closeButton.addEventListener('click', close);
  lightbox.querySelector('[data-close]')
    .addEventListener('click', close);

  document.addEventListener('keydown', (event) => {
    if (!lightbox.classList.contains('is-open')) return;
    if (event.key === 'Escape') close();
    if (event.key === 'ArrowLeft') show(current - 1);
    if (event.key === 'ArrowRight') show(current + 1);
  });
});

Добавьте правило блокировки прокрутки:

body.lightbox-lock {
  overflow: hidden;
}

В полном проекте стоит предусмотреть обработчик ошибки загрузки изображения, сенсорные свайпы и ограничение фокуса внутри диалогового окна. Для небольшой персональной галереи приведённой логики обычно достаточно, а код легко расширить без замены всей реализации. Идеи по аккуратному разделению компонентов можно почерпнуть из материалов о домашнем Kubernetes-кластере, где также важны независимость частей и понятная структура.

Подключение файлов в WordPress

Не вставляйте большой скрипт непосредственно в каждую запись. Создайте, например, файлы gallery.css и gallery.js в дочерней теме, а затем подключите их в functions.php. Функция wp_enqueue_scripts предотвращает дублирование ресурсов и позволяет WordPress правильно сформировать ссылки на файлы.

function site_gallery_assets() {
    wp_enqueue_style(
        'site-gallery',
        get_stylesheet_directory_uri() . '/assets/gallery.css',
        array(),
        '1.0'
    );

    wp_enqueue_script(
        'site-gallery',
        get_stylesheet_directory_uri() . '/assets/gallery.js',
        array(),
        '1.0',
        true
    );
}
add_action('wp_enqueue_scripts', 'site_gallery_assets');

Если стили и скрипт нужны только на отдельных страницах, загрузку можно ограничить условием is_page() или проверкой наличия шорткода в содержимом. При работе с родительской темой используйте дочернюю тему, иначе изменения исчезнут после обновления. Для проекта, где много собственных технических решений, полезно вести отдельные заметки в технологическом блоге, чтобы не терять настройки и фрагменты кода.

Добавление галереи через шорткод

Чтобы не редактировать HTML вручную, можно создать простой шорткод. В записи он будет выглядеть так: [simple_gallery ids="12,15,18"]. Функция получает идентификаторы изображений, формирует миниатюры и связывает их с полноразмерными файлами. Все значения, выводимые в HTML, необходимо экранировать.

function simple_gallery_shortcode($atts) {
    $atts = shortcode_atts(
        array('ids' => ''),
        $atts,
        'simple_gallery'
    );

    $ids = array_filter(array_map('absint', explode(',', $atts['ids'])));
    if (!$ids) {
        return '';
    }

    $html = '<div class="simple-gallery">';

    foreach ($ids as $id) {
        $thumb = wp_get_attachment_image_url($id, 'medium');
        $full = wp_get_attachment_image_url($id, 'large');
        $alt = get_post_meta($id, '_wp_attachment_image_alt', true);
        $caption = wp_get_attachment_caption($id);

        if (!$thumb || !$full) {
            continue;
        }

        $html .= sprintf(
            '<a class="simple-gallery__item" href="%s" data-caption="%s">
            <img src="%s" alt="%s" loading="lazy"></a>',
            esc_url($full),
            esc_attr($caption),
            esc_url($thumb),
            esc_attr($alt)
        );
    }

    return $html . '</div>';
}
add_shortcode('simple_gallery', 'simple_gallery_shortcode');

Размер large зависит от настроек WordPress и обычно подходит для просмотра на экране. Если фотографии публикуются регулярно, настройте собственный размер через add_image_size(), чтобы не отдавать посетителям слишком тяжёлые файлы. Перед публикацией проверьте, что у каждого изображения есть осмысленный alt, а пустые или удалённые вложения не создают битых ссылок.

Проверка скорости и доступности

Откройте страницу на компьютере, планшете и телефоне. Проверьте, не выходит ли изображение за границы окна, видны ли кнопки на тёмном фоне и не появляется ли горизонтальная прокрутка. Отдельно протестируйте клавиши Tab, Enter, Esc и стрелки: галерея должна оставаться управляемой без мыши.

Для ускорения используйте WebP или AVIF, сжимайте оригиналы перед загрузкой и оставляйте loading="lazy" у превью. Большую картинку можно загружать только после клика, как в приведённом примере. Если на странице несколько галерей, лучше искать лайтбокс внутри соответствующего контейнера или создавать отдельное окно для каждой группы, чтобы индексы изображений не смешивались.

Проверьте HTML через инструменты разработчика и убедитесь, что в консоли нет ошибок. После установки кеширующего плагина или минификации JavaScript повторите тестирование: иногда объединение файлов меняет порядок выполнения скриптов. На странице обратной связи можно сообщить о проблемах совместимости через форму связи, если реализация используется в публичном проекте.

Соберите галерею из нескольких оптимизированных изображений, добавьте шорткод в тестовую запись и проверьте её на реальном мобильном устройстве. Такой вариант лайтбокса сохраняет контроль над кодом, не перегружает WordPress и даёт основу для дальнейшего добавления свайпов, анимаций и фильтрации по категориям.

Иконка пользователя в серых тонах

Настройка Windows

Доступ к скрытым параметрам конфигурации, отключение телеметрии, работа с диспетчером задач и тонкая настройка меню «Пуск» в стиле Windows XP для Windows 7.

Иконка браузера в серо-синих тонах

Веб-браузеры

Скрытые страницы конфигурации в Firefox, Chrome и Opera, быстрый текстовый редактор прямо в браузере, эффект Lightbox JS для изображений и настройка внешнего вида Firefox.

Иконка папки в нейтральных серых тонах

WordPress и блоги

Выполнение PHP-кода в текстовых виджетах, диагностика времени загрузки разделов страницы, правильная очистка блога и условная загрузка виджетов социальных сетей.

Изометрический 3D-рендер: светлый веб-сайт с серо-голубым заголовком, парящий над чистой белой поверхностью Изометрический 3D-рендер: тёмно-серая иконка социального букмаркинга на светлом фоне

Обратная связь

Есть вопрос или предложение по темам блога? Напишите — автор на связи.