Создание простого лайтбокса на Vanilla JS за десять минут
Лайтбокс — это режим просмотра изображения поверх текущей страницы. Посетитель нажимает на миниатюру, после чего фотография открывается в увеличенном виде на затемнённом фоне. Такой интерфейс удобен для галерей, скриншотов, портфолио и страниц с иллюстрациями, а для его создания не обязательно подключать тяжёлые библиотеки.
В этом руководстве разберём создание простого лайтбокса на Vanilla JS с чистыми HTML, CSS и JavaScript. Компонент будет открываться по клику, закрываться по кнопке, клавише Escape и нажатию на затемнённую область, а также корректно работать с несколькими изображениями.
Подготовка Разметки Изображений
Начнём с HTML-кода. Для каждой картинки удобно использовать ссылку, в атрибуте href которой находится путь к большой версии изображения. Миниатюра остаётся внутри этой ссылки и загружается быстрее, чем полноразмерный файл. Атрибут alt описывает содержимое изображения и помогает пользователям, применяющим средства экранного доступа.
<div class="gallery">
<a class="gallery__link" href="images/photo-large-1.jpg">
<img
class="gallery__image"
src="images/photo-small-1.jpg"
alt="Горный пейзаж на закате"
>
</a>
<a class="gallery__link" href="images/photo-large-2.jpg">
<img
class="gallery__image"
src="images/photo-small-2.jpg"
alt="Лесная дорога после дождя"
>
</a>
</div>
<div class="lightbox" id="lightbox" aria-hidden="true">
<button class="lightbox__close" type="button" aria-label="Закрыть изображение">
×
</button>
<img class="lightbox__image" src="" alt="">
</div>
Скрытый элемент .lightbox будет общим контейнером для всех фотографий. JavaScript подставит в него адрес большой картинки и текст из alt. Атрибут aria-hidden="true" сообщает вспомогательным технологиям, что окно сейчас неактивно. При открытии его значение изменится на false.
Ссылки не стоит удалять из разметки даже при наличии JavaScript. Если скрипт не загрузится, пользователь всё равно сможет открыть изображение в отдельной вкладке. Это простой принцип прогрессивного улучшения, который делает интерфейс устойчивее.
Оформление Затемнённого Окна
Теперь зададим внешний вид лайтбокса. Контейнер займёт весь экран, а position: fixed привяжет его к окну браузера, независимо от положения страницы. Свойство display: flex поможет разместить изображение по центру, а полупрозрачный фон визуально отделит его от остального содержимого.
.lightbox {
position: fixed;
inset: 0;
z-index: 1000;
display: none;
align-items: center;
justify-content: center;
padding: 24px;
background: rgb(0 0 0 / 80%);
}
.lightbox.is-open {
display: flex;
}
.lightbox__image {
display: block;
max-width: 100%;
max-height: 90vh;
object-fit: contain;
border-radius: 4px;
box-shadow: 0 8px 30px rgb(0 0 0 / 35%);
}
.lightbox__close {
position: absolute;
top: 16px;
right: 20px;
z-index: 1;
width: 42px;
height: 42px;
border: 0;
border-radius: 50%;
color: #fff;
background: rgb(0 0 0 / 45%);
font-size: 30px;
line-height: 1;
cursor: pointer;
}
.lightbox__close:hover,
.lightbox__close:focus-visible {
background: rgb(255 255 255 / 25%);
}
Класс .is-open отвечает за видимость окна. Ограничения max-width и max-height не позволяют большой фотографии выйти за границы экрана. Значение 90vh оставляет свободное место сверху и снизу, поэтому кнопка закрытия не перекрывается изображением даже на небольшом дисплее.
Перед публикацией полезно проверить, как лайтбокс выглядит на мобильном устройстве. Большие фотографии могут занимать много оперативной памяти, а слишком высокий файл будет долго загружаться через мобильную сеть. Практические рекомендации по производительности и цифровой приватности можно сопоставить с материалами исследовательского ресурса, если сайт содержит пользовательские изображения или чувствительные данные.
Логика Открытия И Закрытия
JavaScript найдёт все ссылки галереи, контейнер лайтбокса, изображение и кнопку закрытия. При клике на миниатюру стандартный переход по ссылке отменяется, адрес большой картинки переносится в src, а описание — в alt. После этого контейнер получает класс .is-open.
const links = document.querySelectorAll('.gallery__link');
const lightbox = document.querySelector('#lightbox');
const lightboxImage = document.querySelector('.lightbox__image');
const closeButton = document.querySelector('.lightbox__close');
function openLightbox(link) {
const image = link.querySelector('img');
lightboxImage.src = link.href;
lightboxImage.alt = image.alt;
lightbox.classList.add('is-open');
lightbox.setAttribute('aria-hidden', 'false');
closeButton.focus();
}
function closeLightbox() {
lightbox.classList.remove('is-open');
lightbox.setAttribute('aria-hidden', 'true');
lightboxImage.src = '';
lightboxImage.alt = '';
}
links.forEach((link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
openLightbox(link);
});
});
closeButton.addEventListener('click', closeLightbox);
После закрытия значение src очищается. Это освобождает ссылку на загруженный ресурс и предотвращает сохранение последнего изображения в открытом окне. Фокус переводится на кнопку закрытия, чтобы управление с клавиатуры оставалось предсказуемым.
Вызов closeButton.focus() особенно важен для доступности. Пользователь должен понимать, где находится активный элемент после открытия всплывающего окна. Для более сложного интерфейса можно дополнительно блокировать переход фокуса за пределы лайтбокса, но для небольшой галереи начальной логики достаточно.
Поддержка Клавиатуры И Фона
Осталось добавить закрытие по Escape и по клику на свободное место вокруг изображения. Проверка event.target === lightbox нужна для того, чтобы нажатие непосредственно на фотографию не закрывало окно. Это привычное поведение для большинства галерей.
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && lightbox.classList.contains('is-open')) {
closeLightbox();
}
});
lightbox.addEventListener('click', (event) => {
if (event.target === lightbox) {
closeLightbox();
}
});
Когда лайтбокс открыт, прокрутка основной страницы всё ещё может работать под затемнённым слоем. Для коротких страниц это почти незаметно, но на длинных материалах создаёт ощущение неаккуратного интерфейса. Состояние прокрутки можно контролировать отдельным классом на элементе body.
function openLightbox(link) {
const image = link.querySelector('img');
lightboxImage.src = link.href;
lightboxImage.alt = image.alt;
lightbox.classList.add('is-open');
lightbox.setAttribute('aria-hidden', 'false');
document.body.classList.add('no-scroll');
closeButton.focus();
}
function closeLightbox() {
lightbox.classList.remove('is-open');
lightbox.setAttribute('aria-hidden', 'true');
lightboxImage.src = '';
lightboxImage.alt = '';
document.body.classList.remove('no-scroll');
}
Добавьте к стилям правило .no-scroll { overflow: hidden; }. Тогда при открытом окне фон не будет прокручиваться. Такой эффект стоит протестировать на смартфонах: некоторые мобильные браузеры по-разному обрабатывают фиксированные элементы и вертикальную прокрутку.
Проверка Безопасности И Производительности
Лайтбокс работает на стороне браузера и не отправляет данные на сторонний сервер, если в коде нет внешних скриптов или аналитических компонентов. Это одна из причин выбрать Vanilla JS для простой галереи: меньше зависимостей, меньше сетевых запросов и понятная поверхность для аудита. Настройки браузера и особенности защиты от отслеживания полезно изучить в материале о защите браузеров от слежки.
Пути к изображениям должны быть корректными, а имена файлов — безопасными для URL. Не вставляйте в innerHTML значения, полученные от пользователей. В приведённом варианте используются свойства src и alt, поэтому содержимое не интерпретируется как HTML-код. Если изображения подгружаются из внешнего источника, проверьте политики Content-Security-Policy, HTTPS и разрешённые домены.
Для ускорения загрузки подготовьте миниатюры заранее, сохраните большие изображения в WebP или AVIF и укажите подходящие размеры. Атрибут loading="lazy" можно добавить к картинкам галереи, если они находятся далеко от верхней части страницы:
<img
class="gallery__image"
src="images/photo-small-1.webp"
alt="Горный пейзаж на закате"
loading="lazy"
>
Проверьте сценарии с отключённым JavaScript, клавиатурой, узким экраном и медленным соединением. Убедитесь, что фотография не выходит за пределы окна, кнопка имеет заметный фокус, а alt действительно описывает изображение. После такой проверки простой компонент можно использовать в WordPress-шаблоне, обычной HTML-странице или записи с пользовательской галереей без подключения готового плагина.
Скопируйте разметку, стили и скрипт в тестовую страницу, замените пути к файлам и проверьте работу каждой миниатюры. Затем оптимизируйте изображения и перенесите готовый лайтбокс в нужный шаблон сайта, сохранив резервную копию исходных файлов.