Простой слайдер товаров со множеством позиций

Как создать простой многопозиционный слайдер

От автора: учебник о том, как применив минимум дизайна, создать при помощи анимации CSS и jQuery простой слайдер товаров с категориями. Идея состоит в последовательном пролистывании элементов в зависимости от направления скольжения.

В сегодняшнем учебнике мы покажем, как создать простой слайдер товаров с отдельными элементами при помощи CSS-анимации и небольшого количества jQuery. Мысль была навеяна слайдером продукции Apple, где несколько анимированных элементов прямо-таки «влетают» на страницу. Мы хотели перенести эту концепцию на современную альтернативу минималистичного дизайна онлайн-магазина, где элементы представляют различные категории. В данном случае, категории весьма хорошо подходят для этого типа слайдера товаров, по причине ограниченности его использования. Если нужно показать большее количество элементов, то это решение, несомненно, далеко от оптимального. Однако ограниченность позиций придает этому опыту интересный оттенок.

скачать исходникидемо

Разметка слайдера товаров

Для HTML мы применим обертку, которая будет включать в себя несколько неупорядоченных списков, которые будут содержать элементы и навигацию со ссылками на категории. У каждого пункта списка будет ссылка, содержащая изображение и заголовок h4.

<div id="mi-slider" class="mi-slider">
    <ul>
        <li><a href="#"><img src="images/1.jpg" alt="img01"><h4>Boots</h4></a></li>
        <li><a href="#"><img src="images/2.jpg" alt="img02"><h4>Oxfords</h4></a></li>
        <li><a href="#"><img src="images/3.jpg" alt="img03"><h4>Loafers</h4></a></li>
        <li><a href="#"><img src="images/4.jpg" alt="img04"><h4>Sneakers</h4></a></li>
    </ul>
    <ul>
        <li><a href="#"><img src="images/5.jpg" alt="img05"><h4>Belts</h4></a></li>
        <li><a href="#"><img src="images/6.jpg" alt="img06"><h4>Hats & Caps</h4></a></li>
        <li><a href="#"><img src="images/7.jpg" alt="img07"><h4>Sunglasses</h4></a></li>
        <li><a href="#"><img src="images/8.jpg" alt="img08"><h4>Scarves</h4></a></li>
    </ul>
    <ul>
        <li><a href="#"><img src="images/9.jpg" alt="img09"><h4>Casual</h4></a></li>
        <li><a href="#"><img src="images/10.jpg" alt="img10"><h4>Luxury</h4></a></li>
        <li><a href="#"><img src="images/11.jpg" alt="img11"><h4>Sport</h4></a></li>
    </ul>
    <ul>
        <li><a href="#"><img src="images/12.jpg" alt="img12"><h4>Carry-Ons</h4></a></li>
        <li><a href="#"><img src="images/13.jpg" alt="img13"><h4>Duffel Bags</h4></a></li>
        <li><a href="#"><img src="images/14.jpg" alt="img14"><h4>Laptop Bags</h4></a></li>
        <li><a href="#"><img src="images/15.jpg" alt="img15"><h4>Briefcases</h4></a></li>
    </ul>
    <nav>
        <a href="#">Shoes</a>
        <a href="#">Accessories</a>
        <a href="#">Watches</a>
        <a href="#">Bags</a>
    </nav>
</div>

Давайте рассмотрим стили.

CSS

Обратите внимание, что CSS не будет содержать никаких префиксов, но вы найдете их в файлах.

Мы собираемся сделать следующее: изначально нам требуется показать первый список элементов в то время, когда все остальные li будут смещены вправо, вне поля просмотра. При щелчке на навигационную ссылку элементы сдвинутся либо справа, либо слева, в зависимости от текущей позиции и того, какова заново выбранная категория.

Давайте сначала назначим стили обертке, которая является разделом с классом mi-slider. У него будет предопределенная высота, нужная нам для того, чтобы правильно установить расположение ul’ов:

.mi-slider {
    position: relative;
    margin-top: 30px;
    height: 490px;
}

ul будет абсолютно позиционирован, это означает, что все списки будут поверх других. Помните, что нам нужно сдвинуть лишь элементы списка, а не сами списки. Мы устанавливаем события указателя pointer-events на none, так как нам требуется возможность щелкать на ссылки текущего списка:

.mi-slider ul {
    list-style-type: none;
    position: absolute;
    width: 100%;
    left: 0;
    bottom: 140px;
    overflow: hidden;
    text-align: center;
    pointer-events: none;
}

События указателя pointer events текущего списка должны возвращаться в исходное положение, чтобы можно было щелкать на ссылки:

.mi-slider ul.mi-current {
    pointer-events: auto;
}

При деактивированном JavaScript’е нельзя допустить разрушения дизайна (мы используем Modernizr):

.no-js .mi-slider ul {
    position: relative;
    left: auto;
    bottom: auto;
    margin: 0;
    overflow: visible;
}

Для центрирования элементов списка мы назначили ul’у выравнивание по центру, а теперь зададим отображение inline-block шириной 20%. Эта ширина гарантирует, что наши элементы будут подходить к списку.

По умолчанию все элементы списка смещены вправо. Здесь мы применяем 600%, потому что это достаточно большое значение, чтобы убрать их из окна просмотра. Также добавим небольшой переход непрозрачности:

.mi-slider ul li {
    display: inline-block;
    padding: 20px;
    width: 20%;
    max-width: 300px;
    transform: translateX(600%);
    transition: opacity 0.2s linear;
}

Нам не нужно, чтобы они сдвигались при деактивированном JS:

.no-js .mi-slider ul li {
    transform: translateX(0);
}

Давайте назначим стили содержимому элементов списка. Обратите внимание, что мы устанавливаем максимальную ширину max-width изображений на 100%. Это гарантия, что разметка не нарушится, а изображения станут менять размер в соответствии со своей оберткой, которой является li с шириной в процентах:

.mi-slider ul li a,
.mi-slider ul li img {
    display: block;
    margin: 0 auto;
}
 
.mi-slider ul li a {
    outline: none;
    cursor: pointer;
}
 
.mi-slider ul li img {
    max-width: 100%;
    border: none;
}
 
.mi-slider ul li h4 {
    display: inline-block;
    font-family: Baskerville, "Baskerville Old Face", "Hoefler Text", Garamond, "Times New Roman", serif;
    font-style: italic;
    font-weight: 400;
    font-size: 18px;
    padding: 20px 10px 0;
}

При проведении мышью над элементом мы будем анимировать непрозрачность элемента списка:

.mi-slider ul li:hover {
    opacity: 0.7;
}

Для навигации необходимо самое высокое значение, так как списки позиционированы абсолютно. Мы разместим навигацию по центру, назначив боковые margin-ы в auto и установив максимальную ширину в 800px:

.mi-slider nav {
    position: relative;
    top: 400px;
    text-align: center;
    max-width: 800px;
    margin: 0 auto;
    border-top: 5px solid #333;
}

Не нужно показывать навигацию, если JavaScript не активирован:

.no-js nav {
    display: none;
}

У навигационных ссылок будет щедрый отступ, а для состояния проведения мышью мы назначим им переход:

.mi-slider nav a {
    display: inline-block;
    text-transform: uppercase;
    letter-spacing: 5px;
    padding: 40px 30px 30px 34px;
    position: relative;
    color: #888;
    outline: none;
    transition: color 0.2s linear;
}
 
.mi-slider nav a:hover,
.mi-slider nav a.mi-selected {
    color: #000;
}

Класс mi-selected, совсем как класс списков mi-current, мы установим с помощью JavaScript’а.

Теперь добавим вверху маленькую стрелку. Для создания двух треугольников с границами воспользуемся псевдоклассами :before и :after:

.mi-slider nav a.mi-selected:after,
.mi-slider nav a.mi-selected:before {
    content: '';
    position: absolute;
    top: -5px;
    border: solid transparent;
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
}
 
.mi-slider nav a.mi-selected:after {
    border-color: transparent;
    border-top-color: #fff;
    border-width: 20px;
    left: 50%;
    margin-left: -20px;
}
 
.mi-slider nav a.mi-selected:before {
    border-color: transparent;
    border-top-color: #333;
    border-width: 27px;
    left: 50%;
    margin-left: -27px;
}

Теперь перейдем к самому интересному – анимации. Первая – это масштабирование элементов первого списка. Анимация scaleUp также будет содержать элементы, смещенные на 0, так как нам нужно, чтобы они находились в области просмотра:

.mi-slider ul:first-child li,
.no-js .mi-slider ul li {
    animation: scaleUp 350ms ease-in-out both;
}
 
@keyframes scaleUp {
    0% { transform: translateX(0) scale(0); }
    100% { transform: translateX(0) scale(1); }
}

Давайте добавим каждому элементу списка разную задержку delay, чтобы те появлялись поочередно:

.mi-slider ul:first-child li:first-child {
    animation-delay: 90ms;
}
 
.mi-slider ul:first-child li:nth-child(2) {
    animation-delay: 180ms;
}
 
.mi-slider ul:first-child li:nth-child(3) {
    animation-delay: 270ms;
}
 
.mi-slider ul:first-child li:nth-child(4) {
    animation-delay: 360ms;
}

Для своего примера мы возьмем максимум четыре элемента, поэтому определим четыре задержки. Если делать больше элементов, то следует включать больше задержек.

Для скользящей анимации нам понадобится четыре оболочки: две для появления новых элементов и две для убирания текущих элементов, в зависимости от направления. Так что для списков мы определим четыре класса с JavaScript:

/* moveFromRight */
 
.mi-slider ul.mi-moveFromRight li {
    animation: moveFromRight 350ms ease-in-out both;
}
 
/* moveFromLeft */
 
.mi-slider ul.mi-moveFromLeft li {
    animation: moveFromLeft 350ms ease-in-out both;
}
 
/* moveToRight */
 
.mi-slider ul.mi-moveToRight li {
    animation: moveToRight 350ms ease-in-out both;
}
 
/* moveToLeft */
 
.mi-slider ul.mi-moveToLeft li {
    animation: moveToLeft 350ms ease-in-out both;
}

Теперь нужно установить соответствующие задержки анимации, тоже в зависимости от направления. Например, первый элемент будет выскальзывать без задержки, если он появляется справа, а также когда уходит влево. То же самое верно для последнего элемента:

.mi-slider ul.mi-moveToLeft li:first-child,
.mi-slider ul.mi-moveFromRight li:first-child,
.mi-slider ul.mi-moveToRight li:nth-child(4),
.mi-slider ul.mi-moveFromLeft li:nth-child(4) {
    animation-delay: 0ms;
}

Соответственно будут установлены увеличенные задержки:

.mi-slider ul.mi-moveToLeft li:nth-child(2),
.mi-slider ul.mi-moveFromRight li:nth-child(2),
.mi-slider ul.mi-moveToRight li:nth-child(3),
.mi-slider ul.mi-moveFromLeft li:nth-child(3) {
    -webkit-animation-delay: 90ms;
    animation-delay: 90ms;
}
 
.mi-slider ul.mi-moveToLeft li:nth-child(3),
.mi-slider ul.mi-moveFromRight li:nth-child(3),
.mi-slider ul.mi-moveToRight li:nth-child(2),
.mi-slider ul.mi-moveFromLeft li:nth-child(2) {
    -webkit-animation-delay: 180ms;
    animation-delay: 180ms;
}
 
.mi-slider ul.mi-moveToLeft li:nth-child(4),
.mi-slider ul.mi-moveFromRight li:nth-child(4),
.mi-slider ul.mi-moveToRight li:first-child,
.mi-slider ul.mi-moveFromLeft li:first-child  {
    -webkit-animation-delay: 270ms;
    animation-delay: 270ms;
}

А теперь назначим саму анимацию. Например, перемещение справа будет означать, что мы установим значение translateX на 600% и переместим до 0. При движении слева мы установим исходную позицию на -600% с тем, чтобы элементы, находящиеся слева, были вне области просмотра. И так далее:

@keyframes moveFromRight {
    0% { transform: translateX(600%); }
    100% { transform: translateX(0); }
}
 
@keyframes moveFromLeft {
    0% { transform: translateX(-600%); }
    100% { transform: translateX(0); }
}
 
@keyframes moveToRight {
    0% { transform: translateX(0%); }
    100% { transform: translateX(600%); }
}
 
@keyframes moveToLeft {
    0% { transform: translateX(0%); }
    100% { transform: translateX(-600%); }
}

И последнее по счету, но отнюдь не по важности – давайте применим медиазапросы, чтобы адаптировать содержимое слайдера к маленьким экранам.

Начнем с подгонки навигации, чтобы та не разрушалась при слишком маленьком экране:

@media screen and (max-width: 910px){
    .mi-slider nav {
        max-width: 90%;
    }
 
    .mi-slider nav a {
        font-size: 12px;
        padding: 40px 10px 30px 14px;
    }
}

Так как мы установили слайдеру фиксированную высоту, нам нужно убедиться, что она способна адаптироваться:

@media screen and (max-width: 740px){
    .mi-slider {
        height: 300px;
    }
 
    .mi-slider nav {
        top: 220px;
    }
}

Для действительно маленьких экранов нам не только нужно все супермаленькое, но и легкая навигация для устройств с сенсорными дисплеями. Так что просто покажем все категории. Назначим стили таким образом, чтобы ничего не скрывалось, а все списки демонстрировались один под другим:

@media screen and (max-width: 490px){
    .mi-slider {
        text-align: center;
        height: auto;
    }
 
    .mi-slider ul {
        position: relative;
        display: inline;
        bottom: auto;
        pointer-events: auto;
    }
 
    .mi-slider ul li {
        animation: none !important;
        transform: translateX(0) !important;
        padding: 10px 3px;
        min-width: 140px;
    }
 
    .mi-slider nav {
        display: none;
    }
}

Вот и все стили. Теперь проконтролируем кое-что с помощью jQuery.

JavaScript

Давайте создадим для своего слайдера простой плагин jQuery. Большая часть работы проделана в CSS, где мы определили всю анимацию. Плагин в основном будет нацелен на добавление и удаление классов, и контроль текущей показываемой категории. Для браузеров, не поддерживающих анимацию, мы вернемся к простому подходу show/hide.

Начнем с кэширования некоторых элементов и инициализации нескольких переменных:

_init : function( options ) {
 
    // the categories (ul)
    this.$categories = this.$el.children( 'ul' );
    // the navigation
    this.$navcategories = this.$el.find( 'nav > a' );
    var animEndEventNames = {
        'WebkitAnimation' : 'webkitAnimationEnd',
        'OAnimation' : 'oAnimationEnd',
        'msAnimation' : 'MSAnimationEnd',
        'animation' : 'animationend'
    };
    // animation end event name
    this.animEndEventName = animEndEventNames[ Modernizr.prefixed( 'animation' ) ];
    // animations and transforms support
    this.support = Modernizr.csstransforms && Modernizr.cssanimations;
    // if currently animating
    this.isAnimating = false;
    // current category
    this.current = 0;
    var $currcat = this.$categories.eq( 0 );
    if( !this.support ) {
        this.$categories.hide();
        $currcat.show();
    }
    else {
        $currcat.addClass( 'mi-current' );
    }
    // current nav category
    this.$navcategories.eq( 0 ).addClass( 'mi-selected' );
    // initialize the events
    this._initEvents();
 
}

Мы привяжем событие щелчка к ссылкам навигационной категории под слайдером. Допустим, что индекс каждой соотносится с индексом соответствующей категории (ul’а). При щелчке на ссылку категории элементы текущей категории убираются, а новой категории появляются один за другим (помните, мы определили в CSS задержку анимации).

_initEvents : function() {
 
    var self = this;
    this.$navcategories.on( 'click.catslider', function() {
        self.showCategory( $( this ).index() );
        return false;
    } );
 
    // reset on window resize..
    $( window ).on( 'resize', function() {
        self.$categories.removeClass().eq( 0 ).addClass( 'mi-current' );
        self.$navcategories.eq( self.current ).removeClass( 'mi-selected' ).end().eq( 0 ).addClass( 'mi-selected' );
        self.current = 0;
    } );
 
}
 
showCategory : function( catidx ) {
 
    if( catidx === this.current || this.isAnimating ) {
        return false;
    }
    this.isAnimating = true;
    // update selected navigation
    this.$navcategories.eq( this.current ).removeClass( 'mi-selected' ).end().eq( catidx ).addClass( 'mi-selected' );
 
    var dir = catidx > this.current ? 'right' : 'left',
        toClass = dir === 'right' ? 'mi-moveToLeft' : 'mi-moveToRight',
        fromClass = dir === 'right' ? 'mi-moveFromRight' : 'mi-moveFromLeft',
        // current category
        $currcat = this.$categories.eq( this.current ),
        // new category
        $newcat = this.$categories.eq( catidx ),
        $newcatchild = $newcat.children(),
        lastEnter = dir === 'right' ? $newcatchild.length - 1 : 0,
        self = this;
 
    if( this.support ) {
 
        $currcat.removeClass().addClass( toClass );
         
        setTimeout( function() {
 
            $newcat.removeClass().addClass( fromClass );
            $newcatchild.eq( lastEnter ).on( self.animEndEventName, function() {
 
                $( this ).off( self.animEndEventName );
                $newcat.addClass( 'mi-current' );
                self.current = catidx;
                var $this = $( this );
                // solve chrome bug
                self.forceRedraw( $this.get(0) );
                self.isAnimating = false;
 
            } );
 
        }, $newcatchild.length * 90 );
 
    }
    else {
 
        $currcat.hide();
        $newcat.show();
        this.current = catidx;
        this.isAnimating = false;
 
    }
 
}

Вот и все, мы закончили с вами создание простого слайдера товаров! Надеюсь, что вам понравился этот учебник, оказался для вас полезным и вдохновляющим!

Автор: Mary Lou

Источник: http://tympanus.net/

Редакция: Команда webformyself.

JavaScript&jQuery с нуля до профи

Пройдите пошаговый видеокурс по JavaScript&jQuery

Научиться

Метки:

Комментарии Вконтакте:

Комментарии Facebook:

Комментарии (8)

  1. Елена

    Автору спасибо за детально объяснение, остался вопрос — как пошагово встроить этот скрипт слайдера на сайт (в шапку сайта)? Я создала отдельную папку в корне сайта, загрузила туда все исходники, что дальше? Спасибо за ответ.

    • Данила

      Елена привет, у вас получилось слайдер вмонтировать? я тут пытаюсь его заставить крутиться, неполучается, просто выводятся башмаки и все, не могу сообразить как клик назначить, а как у вас?

  2. prst

    Весь день убил, ничего не выходит. Появляются башмаки и прямая линия. Делал полный копипаст, нифига не работает! Ваш демо файл работает, копирую к себе код, правлю пути, и все перестает работать хотя 100% скрипты загружены и стили тоже. Не понимаю уже в чем дело, автор подскажи, может какие стили перебиваются или какие то пути в скриптах зарыты? Что должно быть неизменно чтобы эта карусель завелась???

    • Андрей Кудлай

      Значит все же где-то есть ошибка. Чтобы понять где — нужно посмотреть на Ваш код. Можете задать вопрос на нашем форуме и дать ссылку на архив с Вашим кодом, в котором слайдер не работает, завтра я попробую посмотреть или может кто-то из пользователей форума подскажет, в чем проблема.

      • prst

        Андрей, верно, вычислил ошибку, раньше времени психанул, вобщем в моем шаблоне подключение jquery шло в самом конце файла, видимо поэтому остальные скрипты и не срабатывали. Как же не хватает знаний по javascript…

  3. prst

    Андрей, последний вопрос, а можно как то сделать autoplay?

    • Андрей Кудлай

      Думаю да, но как — не подскажу, поскольку плагин не мой, и я в его коде не ковырялся. Да и на практике не приходилось использовать этот слайдер.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree