Как реализовать смену изображений в карточках товаров
Подробное руководство по реализации смены изображений в карточках товаров с поддержкой hover на десктопе и свайпов на мобильных устройствах.
Как реализовать смену изображений в карточках товаров в каталоге?
В каталоге товаров каждая карточка содержит несколько изображений. При наведении курсора на определенную область карточки происходит смена изображения. На мобильных устройствах функционал работает через свайпы, а на десктопных версиях — только через наведение курсора.
Подскажите, как реализовать такую функциональность? Какие плагины или решения существуют для этого?
Для реализации смены изображений в карточках товаров с поддержкой наведения на десктопе и свайпов на мобильных устройствах можно использовать комбинацию CSS для hover‑эффектов и JavaScript для обработки touch‑событий. Существуют различные решения от простых CSS‑зон до полноценных библиотек вроде SwiperJS.
- Основные подходы реализации
- CSS‑решения для hover‑эффектов
- JavaScript touch‑события для мобильных
- Библиотеки и плагины
- Реализация адаптивного дизайна
- Примеры кода
- Рекомендации по выбору решения
Основные подходы реализации
Существует несколько основных подходов к реализации смены изображений в карточках товаров:
CSS‑зоны для наведения
Использование CSS‑классов для создания зон в карточке товаров, при наведении на которые происходит смена изображения. Этот метод прост в реализации и хорошо работает на десктопе.
Touch‑события для мобильных устройств
Обработка событий touchstart, touchmove и touchend для реализации свайпов на мобильных устройствах.
Комбинированный подход
Сочетание CSS hover‑эффектов для десктопа и JavaScript touch‑обработки для мобильных устройств, с определением устройства через медиа‑запросы или детекцию возможностей браузера.
CSS‑решения для hover‑эффектов
Наиболее популярным CSS‑подходом является создание зон в карточке товаров, при наведении на которые происходит смена изображения. Вот пример реализации:
.product-images {
position: relative;
height: 260px;
overflow: hidden;
cursor: pointer;
}
.product-images img {
position: absolute;
width: 100%;
height: 100%;
}
/* Невидимые горизонтальные зоны для наведения */
.hover-zone {
position: absolute;
top: 0;
bottom: 0;
width: 25%;
z-index: 10;
border-bottom: 2px solid white;
}
.zone1 { left: 0; }
.zone2 { left: 25%; }
.zone3 { left: 50%; }
.zone4 { left: 75%; }
.hover-zone:hover ~ img {
opacity: 0;
visibility: hidden;
}
.hover-zone:hover + img {
opacity: 1;
visibility: visible;
}
.hover-zone:hover {
border-bottom-color: blue;
}
Этот подход позволяет создать интерактивную карточку с несколькими зонами наведения. Каждая зона отвечает за показ определенного изображения.
Альтернативные CSS‑методы
Эффект масштабирования при наведении:
.card {
position: relative;
width: 320px;
aspect-ratio: 9/14;
overflow: hidden;
border-radius: 20px;
cursor: pointer;
}
.card img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: -1;
transition: 0.4s;
}
.card:hover img {
transform: scale(1.15);
}
JavaScript touch‑события для мобильных
Для обработки свайпов на мобильных устройствах необходимо реализовать JavaScript‑обработку touch‑событий:
function swipe(event) {
const touches = event.changedTouches;
const startX = touches[0].pageX;
const startY = touches[0].pageY;
function handleTouchMove(moveEvent) {
const currentX = moveEvent.touches[0].pageX;
const currentY = moveEvent.touches[0].pageY;
const deltaX = currentX - startX;
const deltaY = currentY - startY;
// Определяем направление свайпа
if (Math.abs(deltaX) > Math.abs(deltaY)) {
if (deltaX > 50) {
// Свайп вправо
showPreviousImage();
} else if (deltaX < -50) {
// Свайп влево
showNextImage();
}
}
}
function handleTouchEnd(endEvent) {
document.removeEventListener('touchmove', handleTouchMove);
document.removeEventListener('touchend', handleTouchEnd);
}
document.addEventListener('touchmove', handleTouchMove);
document.addEventListener('touchend', handleTouchEnd);
}
Для определения свайпа необходимо анализировать последовательность событий: touchstart, touchmove и touchend. Продолжительность, скорость и направление движения определяют, является ли это «свайпом».
Библиотеки и плагины
Существует множество готовых библиотек и плагинов для реализации галерей изображений:
SwiperJS
SwiperJS — мощная библиотека для создания интерактивных галерей:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"/>
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
<div class="swiper productSwiper">
<div class="swiper-wrapper">
<div class="swiper-slide"><img src="image1.jpg" alt="Product"></div>
<div class="swiper-slide"><img src="image2.jpg" alt="Product"></div>
<div class="swiper-slide"><img src="image3.jpg" alt="Product"></div>
</div>
<div class="swiper-pagination"></div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
<script>
const swiper = new Swiper('.productSwiper', {
slidesPerView: 1,
spaceBetween: 30,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
// Включаем свайпы для мобильных
allowTouchMove: true,
touchRatio: 1,
touchAngle: 45,
grabCursor: true,
});
</script>
Другие популярные решения
Smart Product Image Swiper — приложение для Shopify с поддержкой touch‑управления:
- Поддерживает различные темы
- Не требует знаний программирования
- Оптимизирован для мобильных устройств
Stacked Card Slider — минималистичная галерея на чистом JavaScript:
<div class="card-slider">
<div class="card">
<img src="image1.jpg" alt="Product">
</div>
<div class="card">
<img src="image2.jpg" alt="Product">
</div>
<div class="card">
<img src="image3.jpg" alt="Product">
</div>
</div>
Реализация адаптивного дизайна
Для корректной работы на разных устройствах необходимо реализовать адаптивную логику:
Детекция устройства
function isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
function isTouchDevice() {
return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
}
// Использование в коде
if (isTouchDevice()) {
// Включаем свайпы для мобильных
enableSwipeGestures();
} else {
// Включаем hover‑эффекты для десктопа
enableHoverEffects();
}
CSS Media Queries
/* Стили для десктопа */
@media (min-width: 768px) {
.product-card {
/* Hover‑эффекты */
}
}
/* Стили для мобильных устройств */
@media (max-width: 767px) {
.product-card {
/* Touch‑оптимизация */
touch-action: pan-y;
}
.hover-zone {
display: none;
}
}
Примеры кода
Комплексное решение с HTML/CSS/JavaScript
<div class="product-card" data-product-id="123">
<div class="product-images">
<!-- Основное изображение -->
<img src="main-image.jpg" alt="Product" class="active-image">
<!-- Дополнительные изображения -->
<img src="image2.jpg" alt="Product">
<img src="image3.jpg" alt="Product">
<img src="image4.jpg" alt="Product">
<!-- Зоны наведения для десктопа -->
<div class="hover-zone zone1" data-image="0"></div>
<div class="hover-zone zone2" data-image="1"></div>
<div class="hover-zone zone3" data-image="2"></div>
<div class="hover-zone zone4" data-image="3"></div>
</div>
<!-- Элементы управления для мобильных -->
<div class="mobile-controls" style="display: none;">
<button class="prev-image">←</button>
<button class="next-image">→</button>
</div>
</div>
document.addEventListener('DOMContentLoaded', function() {
const productCards = document.querySelectorAll('.product-card');
productCards.forEach(card => {
const images = card.querySelectorAll('.product-images img');
const hoverZones = card.querySelectorAll('.hover-zone');
const mobileControls = card.querySelector('.mobile-controls');
let currentImage = 0;
// Проверка мобильного устройства
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
if (isMobile) {
// Показываем элементы управления для мобильных
mobileControls.style.display = 'block';
// Обработка свайпов
let startX = 0;
let startY = 0;
card.addEventListener('touchstart', (e) => {
startX = e.touches[0].pageX;
startY = e.touches[0].pageY;
});
card.addEventListener('touchend', (e) => {
const endX = e.changedTouches[0].pageX;
const endY = e.changedTouches[0].pageY;
const deltaX = endX - startX;
const deltaY = endY - startY;
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 50) {
if (deltaX > 0) {
showPreviousImage();
} else {
showNextImage();
}
}
});
// Обработка кнопок
card.querySelector('.prev-image').addEventListener('click', showPreviousImage);
card.querySelector('.next-image').addEventListener('click', showNextImage);
} else {
// Hover‑эффекты для десктопа
hoverZones.forEach(zone => {
zone.addEventListener('mouseenter', () => {
const imageIndex = parseInt(zone.dataset.image);
switchImage(imageIndex);
});
});
}
function switchImage(index) {
images.forEach(img => img.classList.remove('active-image'));
images[index].classList.add('active-image');
currentImage = index;
}
function showNextImage() {
currentImage = (currentImage + 1) % images.length;
switchImage(currentImage);
}
function showPreviousImage() {
currentImage = (currentImage - 1 + images.length) % images.length;
switchImage(currentImage);
}
});
});
Рекомендации по выбору решения
Для простых проектов
Если вам нужно простое решение без сложной логики, используйте CSS‑зоны для наведения. Этот метод не требует JavaScript и работает отлично на десктопе.
Для проектов электронной коммерции
Для интернет‑магазинов рекомендуется использовать специализированные плагины:
- SwiperJS — гибкое решение с множеством настроек
- Smart Product Image Swiper — для Shopify платформ
- Custom implementation — для полной кастомизации
Для мобильной оптимизации
Приоритетные требования для мобильной версии:
- Поддержка touch‑событий
- Оптимизация производительности
- Адаптивный дизайн под разные размеры экранов
- Интуитивная навигация
Комплексный подход
Наиболее эффективным является комбинированный подход:
- CSS hover‑эффекты для десктопа
- JavaScript touch‑обработка для мобильных
- Использование медиа‑запросов для адаптации
- Оптимизация производительности для плавной работы
Источники
- Different product gallery on desktop&mobile, swipe controls - XTemos
- Product Card Second Image On Hover/Touch For Mobile - Shopify Community
- Mobile image Swipe - Magento Stack Exchange
- Product card with multiple thumbnail images (change on mouse hover) - DEV Community
- CSS Card Hover Effect Examples - Subframe
- Carousel UI: best practices, examples and alternatives - Justinmind
- Card Hover Effect: Image Scale - CodePen
- Flexible card component and layout demos for mobile and desktop - Mobiscroll
- Smart Product Image Swiper - Shopify App Store
- CSS Card Hover Effects: 40 Examples - WPDean
- Minimal Swipeable Gallery In Pure JavaScript - SwiperBox | CSS Script
- 64 JavaScript Carousels | FreeFrontend
- How To Create Image Hover Overlay Slide Effects - W3Schools
- How to add swipe feature to a image gallery? - Stack Overflow
- Pure Javascript slider on swipe for mobile - Stack Overflow
Заключение
- Основные подходы: Для реализации смены изображений в карточках товаров используйте комбинацию CSS hover‑эффектов для десктопа и JavaScript touch‑обработки для мобильных устройств.
- Решения: Существуют как простые CSS‑методы с зонами наведения, так и мощные библиотеки вроде SwiperJS для сложных галерей.
- Адаптивность: Реализуйте детекцию устройств и медиа‑запросы для корректной работы на всех платформах.
- Производительность: Оптимизируйте изображения и минимизируйте JavaScript для плавной работы на мобильных устройствах.
- Практические рекомендации: Для новых проектов рекомендуется использовать современные библиотеки вроде SwiperJS, а для простых случаев — CSS‑решения с минимальным JavaScript.