Яндекс.Метрика

Дизайн-журнал №1. Актуальная информация для дизайнеров, веб дизайнеров, программистов и разработчиков сайтов.

Простой слайдер с набором категорий

13 февраля 2013 | Опубликовано в css | 2 Комментариев »

В этом уроке мы будем создавать простой слайдер минималистичного дизайна, используя СSS-анимации и jQuery. Идея будет заключаться в том, чтобы последовательно менять изображения в зависимости от выбранной категории. Данный слайдер отлично подойдет для дизайна онлайн-магазина, в котором будет немного категорий с небольшим количеством товаров.

 

Демо      Скачать файлы 

Разметка

Для 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

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

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

Давайте сначала  зададим стили для контейнера с классом mi-sliderОн будет иметь определенную высоту, которая нужна для установки позиций с корректными  uls:   

.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  выравнивание текста по центру, а для пунктов списка свойство display: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%.  

.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;
}

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

.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); }
}

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

.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;
}

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

Для анимации слайдера мы будем определять 4 случая: два для появления нового списка и два для исчезновения текущего — в зависимости от направления. Определим четыре класса для списков, которые будут добавляться с помощью 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. 

JAVA SCRIPT

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

Давайте начнем с кэширования некоторых элементов и объявления несколько переменных:   

_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();
}

Мы будем связывать событие click с выбранной категорией в соответствии с ползунком под слайдером. Предполагаем, что индекс ссылки соответствует индексу каждой категории

При нажатии на ссылку элементы текущей категории исчезают с области видимости, а на их место один за другим появляются новые (все анимации и задержки определены в 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

Перевод — Дежурка




Комментарии

  1. Alex
    Thumb up Thumb down 0

    При обновлении страницы — сбрасывается выбор.

    При сваривание или разворота окна браузера — сбрасывается выбор.

  2. Aleck
    Thumb up Thumb down 0

    При уменьшении страницы по бокам видны фото из категорий, от этого можно избавиться?LVSpneIK7UnUr