Другое

Как реализовать смену изображений в карточках товаров

Подробное руководство по реализации смены изображений в карточках товаров с поддержкой hover на десктопе и свайпов на мобильных устройствах.

Как реализовать смену изображений в карточках товаров в каталоге?

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

Подскажите, как реализовать такую функциональность? Какие плагины или решения существуют для этого?

Для реализации смены изображений в карточках товаров с поддержкой наведения на десктопе и свайпов на мобильных устройствах можно использовать комбинацию CSS для hover‑эффектов и JavaScript для обработки touch‑событий. Существуют различные решения от простых CSS‑зон до полноценных библиотек вроде SwiperJS.

Основные подходы реализации

Существует несколько основных подходов к реализации смены изображений в карточках товаров:

CSS‑зоны для наведения

Использование CSS‑классов для создания зон в карточке товаров, при наведении на которые происходит смена изображения. Этот метод прост в реализации и хорошо работает на десктопе.

Touch‑события для мобильных устройств

Обработка событий touchstart, touchmove и touchend для реализации свайпов на мобильных устройствах.

Комбинированный подход

Сочетание CSS hover‑эффектов для десктопа и JavaScript touch‑обработки для мобильных устройств, с определением устройства через медиа‑запросы или детекцию возможностей браузера.


CSS‑решения для hover‑эффектов

Наиболее популярным CSS‑подходом является создание зон в карточке товаров, при наведении на которые происходит смена изображения. Вот пример реализации:

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‑методы

Эффект масштабирования при наведении:

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‑событий:

javascript
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 — мощная библиотека для создания интерактивных галерей:

html
<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:

html
<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>

Реализация адаптивного дизайна

Для корректной работы на разных устройствах необходимо реализовать адаптивную логику:

Детекция устройства

javascript
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

css
/* Стили для десктопа */
@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

html
<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>
javascript
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‑событий
  • Оптимизация производительности
  • Адаптивный дизайн под разные размеры экранов
  • Интуитивная навигация

Комплексный подход

Наиболее эффективным является комбинированный подход:

  1. CSS hover‑эффекты для десктопа
  2. JavaScript touch‑обработка для мобильных
  3. Использование медиа‑запросов для адаптации
  4. Оптимизация производительности для плавной работы

Источники

  1. Different product gallery on desktop&mobile, swipe controls - XTemos
  2. Product Card Second Image On Hover/Touch For Mobile - Shopify Community
  3. Mobile image Swipe - Magento Stack Exchange
  4. Product card with multiple thumbnail images (change on mouse hover) - DEV Community
  5. CSS Card Hover Effect Examples - Subframe
  6. Carousel UI: best practices, examples and alternatives - Justinmind
  7. Card Hover Effect: Image Scale - CodePen
  8. Flexible card component and layout demos for mobile and desktop - Mobiscroll
  9. Smart Product Image Swiper - Shopify App Store
  10. CSS Card Hover Effects: 40 Examples - WPDean
  11. Minimal Swipeable Gallery In Pure JavaScript - SwiperBox | CSS Script
  12. 64 JavaScript Carousels | FreeFrontend
  13. How To Create Image Hover Overlay Slide Effects - W3Schools
  14. How to add swipe feature to a image gallery? - Stack Overflow
  15. Pure Javascript slider on swipe for mobile - Stack Overflow

Заключение

  1. Основные подходы: Для реализации смены изображений в карточках товаров используйте комбинацию CSS hover‑эффектов для десктопа и JavaScript touch‑обработки для мобильных устройств.
  2. Решения: Существуют как простые CSS‑методы с зонами наведения, так и мощные библиотеки вроде SwiperJS для сложных галерей.
  3. Адаптивность: Реализуйте детекцию устройств и медиа‑запросы для корректной работы на всех платформах.
  4. Производительность: Оптимизируйте изображения и минимизируйте JavaScript для плавной работы на мобильных устройствах.
  5. Практические рекомендации: Для новых проектов рекомендуется использовать современные библиотеки вроде SwiperJS, а для простых случаев — CSS‑решения с минимальным JavaScript.
Авторы
Проверено модерацией
Модерация