Настройка галереи изображений товара (swiper/slider) 1С-Битрикс
Стандартный шаблон catalog.element в Битриксе рендерит дополнительные изображения товара (MORE_PHOTO) как набор тегов <img> без какой-либо галерейной логики. Магазин подключает Swiper, галерея работает на главной странице, но в карточке товара слайдер инициализируется до того, как компонент отдал HTML — и получает пустой контейнер. Это классическая проблема порядка выполнения скриптов в Битриксе.
Данные изображений в компоненте catalog.element
Компонент собирает все изображения товара в $arResult['MORE_PHOTO'] — массив путей к уже ресайзенным картинкам. Оригиналы хранятся в b_iblock_element.DETAIL_PICTURE и свойстве MORE_PHOTO (тип F, множественное). Для слайдера обычно нужны два размера: миниатюра для превью-полоски и полноразмерная для основного слайда.
В шаблоне template.php компонента:
<?php
$slides = [];
foreach ($arResult['PROPERTIES']['MORE_PHOTO']['FILE_VALUE'] as $fileArr) {
$thumb = \CFile::ResizeImageGet($fileArr['ID'], ['width' => 80, 'height' => 80], BX_RESIZE_IMAGE_PROPORTIONAL);
$full = \CFile::ResizeImageGet($fileArr['ID'], ['width' => 800, 'height' => 800], BX_RESIZE_IMAGE_PROPORTIONAL);
$slides[] = [
'thumb' => $thumb['src'],
'full' => $full['src'],
'alt' => htmlspecialcharsEx($fileArr['DESCRIPTION'] ?: $arResult['NAME']),
];
}
?>
Разметка для Swiper
Swiper ожидает строгую структуру .swiper > .swiper-wrapper > .swiper-slide. Любое отклонение — и библиотека не найдёт слайды. Основной слайдер и слайдер миниатюр — два отдельных экземпляра Swiper, связанных через параметр thumbs.swiper:
<div class="swiper product-main-swiper" id="productMainSwiper">
<div class="swiper-wrapper">
<?php foreach ($slides as $slide): ?>
<div class="swiper-slide">
<img src="<?= $slide['full'] ?>" alt="<?= $slide['alt'] ?>" loading="lazy">
</div>
<?php endforeach; ?>
</div>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
<div class="swiper product-thumbs-swiper" id="productThumbsSwiper">
<div class="swiper-wrapper">
<?php foreach ($slides as $slide): ?>
<div class="swiper-slide">
<img src="<?= $slide['thumb'] ?>" alt="" loading="lazy">
</div>
<?php endforeach; ?>
</div>
</div>
Инициализация и порядок скриптов
Ключевая проблема Битрикса: $APPLICATION->AddHeadScript() добавляет скрипты в <head>, а компонент рендерится позже в <body>. Swiper подключён в head, но new Swiper() вызывается в inline-скрипте шаблона — DOM ещё не готов.
Правильное решение — отложенная инициализация через DOMContentLoaded или через пролог/эпилог. В шаблоне компонента:
document.addEventListener('DOMContentLoaded', function () {
const thumbsSwiper = new Swiper('#productThumbsSwiper', {
slidesPerView: 4,
spaceBetween: 8,
watchSlidesProgress: true,
});
new Swiper('#productMainSwiper', {
spaceBetween: 0,
thumbs: { swiper: thumbsSwiper },
keyboard: { enabled: true },
});
});
Lazy loading и LCP
loading="lazy" на первом слайде убивает LCP — браузер откладывает загрузку главного изображения товара. Первый слайд должен грузиться без lazy:
foreach ($slides as $i => $slide):
$loading = $i === 0 ? 'eager' : 'lazy';
Также стоит добавить fetchpriority="high" на первый слайд — это подсказка браузеру повысить приоритет запроса.
Смена изображений при выборе SKU
Когда пользователь выбирает торговое предложение, Битрикс через AJAX обновляет блок цены и наличия. Галерея при этом не меняется — она привязана к родительскому элементу. Чтобы синхронизировать: слушать событие onSaleComponentOfferSelect (стандартное событие Битрикса), получать offerId, запрашивать фото предложения через кастомный AJAX-экшн и пересоздавать слайдер с новыми данными через swiper.destroy() + реинициализацию.







