Вертикальный слайдер на jQuery и CSS transitions

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

Сложность

HTML разметка вертикального слайдера

В разметке будет основной контейнер содержащий следующие элементы: заголовок, оболочка для контента (описания) и оболочка для слайдов:

<section id="ps-container" class="ps-container">
 
 <div class="ps-header">
 <h1>Vertical Showcase Slider</h1>
 </div><!-- /ps-header -->
 
 <div class="ps-contentwrapper">
 
 <div class="ps-content">
 <h2>Bernhard</h2>
 <span class="ps-price">£100</span>
 <p>With restful springiness in the seat; prevents static sitting and provides enhanced seating comfort. Padded seat and back for enhanced seating comfort. Soft, hardwearing and easy care leather, which ages gracefully.</p>
 <a href="http://www.ikea.com/gb/en/catalog/products/80163804/#/60203882">Buy this item</a>
 </div>
 
 <div class="ps-content">
 <!-- description item 2 -->
 </div>
 
 <div class="ps-content">
 <!-- description item 3 -->
 </div>
 
 <div class="ps-content">
 <!-- description item 4 -->
 </div>
 
 <div class="ps-content">
 <!-- description item 5 -->
 </div>
 
 </div><!-- /ps-contentwrapper -->
 
 <div class="ps-slidewrapper">
 
 <div class="ps-slides">
 <div style="background-image: url('/images/1.jpg');"></div>
 <div style="background-image: url('/images/2.jpg');"></div>
 <div style="background-image: url('/images/3.jpg');"></div>
 <div style="background-image: url('/images/4.jpg');"></div>
 <div style="background-image: url('/images/5.jpg');"></div>
 </div>
 
 <nav>
 <a href="#" class="ps-prev"></a>
 <a href="#" class="ps-next"></a>
 </nav>
 
 </div><!-- /ps-slidewrapper -->
 
</section><!-- /ps-container -->

Оболочка для jQuery слайдера будет иметь такое же количество блоков, как и оболочка контента, у каждого блока будет соответствующее фоновое изображение. Также мы добавили навигацию, которая будет иметь две ссылки. Для ссылок также зададим фоновое изображение, но мы установим его динамически.

CSS

Для начала добавим шрифт, который сделали на сайте fontello.com. В этом шрифте мы добавили один символ - небольшая тележка магазина для ссылки "Купить товар":

@font-face { 
  font-family: 'icon'; 
  src: url("font/icon.eot"); 
  src:  
    url("font/icon.eot?#iefix") format('embedded-opentype'), 
    url("font/icon.woff") format('woff'),  
    url("font/icon.ttf") format('truetype'),  
    url("font/icon.svg#icon") format('svg'); 
  font-weight: normal; 
  font-style: normal; 
}

Мы должны создать разметку, которая будет 100% шириной и высотой экрана, таким образом, зададим абсолютную позицию нашему контейнеру и установим overflow: hidden.

.ps-container { 
    position: absolute; 
    width: 100%; 
    height: 100%; 
    overflow: hidden; 
    text-transform: uppercase; 
    color: #555; 
    background: #fff; 
}

Ширина и высота составят 100%. Обратите внимание, что мы установили высоту HTML к 100% (demo.css).

У всех дочерних элементов нашего основного контейнера будет ширина 50%, а также абсолютное расположение:

.ps-container > div { 
    position: absolute; 
    width: 50%; 
}

Для следующих элементов зададим абсолютное расположение:

.ps-container > div > div, 
.ps-slidewrapper > nav, 
.ps-slides > div { 
    position: absolute; 
}

У заголовка будет высота 150px, поместим его в верхний левый угол:

.ps-header { 
    top: 0px; 
    left: 0px; 
    height: 150px; 
    z-index: 1001; 
    background: #fff; 
}

Стиль для элемента h1:

.ps-header h1 { 
    color: #ccc; 
    line-height: 150px; 
    margin: 0; 
    padding: 0 50px; 
    font-weight: 200; 
    font-size: 14px; 
    letter-spacing: 10px; 
}

Оболочка контента будет иметь такой же размер заголовка, также установим overflow: hidden:

.ps-contentwrapper { 
    top: 150px; 
    bottom: 0px; 
    overflow: hidden; 
    z-index: 1000; 
}

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

.ps-content { 
    background: #fff; 
    width: 100%; 
    height: 100%; 
    padding: 50px; 
}

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

.ps-content h2 { 
    padding: 10px 15px; 
    border-right: 1px solid #f2f2f2; 
    border-bottom: 1px solid #f2f2f2; 
    letter-spacing: 4px; 
    margin: 10px 0 30px; 
    text-align: right; 
    font-weight: 700; 
} 
  
.ps-content p { 
    line-height: 26px; 
    font-size: 12px; 
    letter-spacing: 2px; 
    word-spacing: 10px; 
    padding: 10px 15px; 
    font-weight: 400; 
    text-align: justify; 
    border-left: 1px solid #f2f2f2; 
    border-top: 1px solid #f2f2f2; 
}

Цена будет находиться на левой стороне блока:

.ps-content span.ps-price { 
    float: left; 
    margin: 10px; 
    width: 140px; 
    height: 140px; 
    line-height: 140px; 
    text-align: center; 
    color: #fff; 
    background: #f7cfc6; 
    background: rgba(247,197,185,0.8); 
    font-size: 55px; 
    font-weight: 200; 
}

Обратите внимание, что мы устанавливаем HEX цвет фона, а потом уже RGBA. Старые браузеры, которые не поддерживают значения RGBA, проигнорируют вторую строку и будут использовать первый цвет.

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

.ps-content a:last-child { 
    font-size: 14px; 
    font-weight: 700; 
    color: #555; 
    letter-spacing: 4px; 
    float: right; 
    border: 3px solid #555; 
    padding: 3px; 
    text-indent: 4px; 
} 
  
.no-touch .ps-content a:last-child:hover { 
    color: #b2d79d; 
    border-color: #b2d79d; 
}

Добавим небольшую иконку тележки магазина при помощи псевдо-класса :after:

.ps-content a:last-child:before { 
    content: '\53'; 
    font-family: 'icon'; 
    font-style: normal; 
    font-weight: normal; 
    speak: none; 
    padding-right: 5px; 
}

Контейнер для слайдов и навигации разместим с правой стороны и зададим 100% высоту:

.ps-slidewrapper { 
    right: 0px; 
    top: 0px; 
    height: 100%; 
    overflow: hidden; 
}

Поднимаем оболочку jquery слайдера вверх на 200px.

.ps-slides { 
    top: 0px; 
    bottom: 200px; 
    width: 100%; 
}

У внутренних блоков, которые содержат фоновое изображение, будет ширина и высота 100%, зададим для них тень, которая будет служить тонким наложением.

.ps-slides > div { 
    width: 100%; 
    height: 100%; 
    box-shadow: inset 0 0 0 9999px rgba(179,157,250,0.1); 
}

Навигацию разместим у основания контейнера слайдов, зададим для неё фиксированную высоту в 200px:

.ps-slidewrapper > nav { 
    width: 100%; 
    height: 200px; 
    bottom: 0px; 
    right: 0px; 
    z-index: 1000; 
}

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

.ps-slidewrapper > nav > a { 
    width: 50%; 
    height: 100%; 
    position: relative; 
    float: left; 
    outline: none; 
    box-shadow: inset 0 0 0 9999px rgba(207,227,206,0.8); 
} 
  
.ps-slidewrapper > nav > a:first-child { 
    box-shadow: inset 0 0 0 9999px rgba(233,217,141,0.8); 
} 
  
.no-touch .ps-slidewrapper > nav > a { 
    transition: box-shadow 0.4s ease-in-out; 
} 
  
.no-touch .ps-slidewrapper > nav > a:hover { 
    box-shadow: inset 0 0 0 9999px rgba(246,224,121,0.1); 
} 
  
.no-touch .ps-slidewrapper > nav > a:first-child:hover { 
    box-shadow: inset 0 0 0 9999px rgba(249,15,15,0.1); 
}

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

.ps-slidewrapper > nav > a:after { 
    content: ''; 
    position: absolute; 
    width: 100px; 
    height: 100px; 
    top: 50%; 
    left: 50%; 
    margin: -20px 0 0 -50px; 
    transform: rotate(45deg); 
    border-left: 1px solid #fff; 
    border-top: 1px solid #fff; 
} 
  
.ps-slidewrapper > nav > a:first-child:after { 
    transform: rotate(-135deg); 
    margin: -80px 0 0 -50px; 
}

Предварительный просмотр и навигация будут иметь фоновое изображение:

.ps-slides > div, 
.ps-slidewrapper > nav > a { 
    background-color: #fff; 
    background-position: center top; 
    background-repeat: no-repeat; 
    background-size: auto 100%; 
}

Следующий класс используется динамически:

.ps-move { 
    transition: top 400ms ease-out; 
}

Перейдем к медиа запросам для устройств с небольшим экраном.

Мы должны установить 100% ширину для вложенных элементов основного контейнера:

@media screen and (max-width: 860px) { 
  
    .js .ps-container > div { 
        width: 100%; 
    }

Заголовок будет немного меньше:


.js .ps-header { 
    height: 50px; 
} 
 
.js .ps-header h1 { 
    line-height: 50px; 
    padding: 0px 20px; 
    letter-spacing: 4px; 
}

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

.js .ps-slides { 
    bottom: 320px; 
    top: 50px; 
}

Высоту навигации уменьшим в два раза:

.js .ps-slidewrapper > nav { 
    height: 100px; 
}

У оболочки контента будет высота 220px, поместим её над навигацией:

.js .ps-contentwrapper { 
    top: auto; 
    height: 220px; 
    bottom: 100px; 
}

Изменим размеры текстовых элементов:

.js .ps-content { 
    padding: 10px; 
} 
 
.js .ps-content h2 { 
    border-right: none; 
    font-size: 18px; 
    margin: 10px 0; 
    padding-top: 0; 
} 
 
.js .ps-content span.ps-price { 
    font-size: 18px; 
    width: 50px; 
    height: 50px; 
    line-height: 50px; 
    font-weight: 700; 
    margin-bottom: 0; 
}

У нас нет большого свободного пространства, поэтому установим фиксированную высоту для текста и добавим прокрутку:

.js .ps-content p { 
    line-height: 20px; 
    border: none; 
    padding: 5px 10px; 
    height: 80px; 
    overflow-y: scroll; 
}

Немного уменьшим размер ссылки:

.js .ps-content a:last-child { 
        font-size: 13px; 
        margin: 10px 20px 0 0; 
    } 
}

JavaScript

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

var $container = $( '#ps-container' ), 
    $contentwrapper = $container.children( 'div.ps-contentwrapper' ), 
    // элементы (элементы описания для слайдов/продуктов)
    $items = $contentwrapper.children( 'div.ps-content' ), 
    itemsCount = $items.length, 
    $slidewrapper = $container.children( 'div.ps-slidewrapper' ), 
    // слайды (изображения продуктов) 
    $slidescontainer = $slidewrapper.find( 'div.ps-slides' ), 
    $slides = $slidescontainer.children( 'div' ), 
    // стрелки навигации 
    $navprev = $slidewrapper.find( 'nav > a.ps-prev' ), 
    $navnext = $slidewrapper.find( 'nav > a.ps-next' ), 
    // текущий индекс для слайдов 
    current = 0, 
    // проверка 
    isAnimating = false, 
    // поддержка css transitions
    support = Modernizr.csstransitions// transition end event 
    // https://github.com/twitter/bootstrap/issues/2870 
    transEndEventNames = { 
        'WebkitTransition' : 'webkitTransitionEnd', 
        'MozTransition' : 'transitionend', 
        'OTransition' : 'oTransitionEnd', 
        'msTransition' : 'MSTransitionEnd', 
        'transition' : 'transitionend'
    };

При вызове функции init, первое что нужно сделать это, показать первый элемент и соответствующий слайд/изображение. Кроме того, мы должны обновить фоновое изображение в навигации. Наконец, вызов функции initEvents.

init = function() {
 
    // show first item
    var $currentItem = $items.eq( current ),
        $currentSlide = $slides.eq( current ),
        initCSS = {
            top : 0,
            zIndex : 999
        };
 
    $currentItem.css( initCSS );
    $currentSlide.css( initCSS );
     
    // update nav images
    updateNavImages();
 
    // initialize some events
    initEvents();
 
},
updateNavImages = function() {
 
    // updates the background image for the navigation arrows
    var configPrev = ( current > 0 ) ? $slides.eq( current - 1 ).css( 'background-image' ) : $slides.eq( itemsCount - 1 ).css( 'background-image' ),
        configNext = ( current < itemsCount - 1 ) ? $slides.eq( current + 1 ).css( 'background-image' ) : $slides.eq( 0 ).css( 'background-image' );
 
    $navprev.css( 'background-image', configPrev );
    $navnext.css( 'background-image', configNext );
 
},
adjustLayout = function() {
 
    $container.css( 'height', $window.height() );
 
},

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

initEvents = function() {
 
    $navprev.on( 'click', function( event ) {
 
        if( !isAnimating ) {
             
            slide( 'prev' );
         
        }
        return false;
 
    } );
 
    $navnext.on( 'click', function( event ) {
 
        if( !isAnimating ) {
             
            slide( 'next' );
         
        }
        return false;
 
    } );
 
    $items.on( transEndEventName, removeTransition );
    $slides.on( transEndEventName, removeTransition );
     
},

Основная функция - функция слайдов. Необходимо расположить следующий элемент/слайд, который будет отображаться до или после текущего слайда (в зависимости по какому элементу навигации мы нажимаем). Затем мы перемещаем текущий элемент/слайд из оболочки. Мы также обновим фоновое изображение элементов навигации.

slide = function( dir ) {
 
    isAnimating = true;
 
    var $currentItem = $items.eq( current ),
        $currentSlide = $slides.eq( current );
 
    // обновление текущего значения
    if( dir === 'next' ) {
 
        ( current < itemsCount - 1 ) ? ++current : current = 0;
 
    }
    else if( dir === 'prev' ) {
 
        ( current > 0 ) ? --current : current = itemsCount - 1;
 
    }
        // новый элемент который будет отображаться
    var $newItem = $items.eq( current ),
        // новый слайд который будет отображаться
        $newSlide = $slides.eq( current );
 
    // расположение нового элемента
    $newItem.css( {
        top : ( dir === 'next' ) ? '-100%' : '100%',
        zIndex : 999
    } );
     
    $newSlide.css( {
        top : ( dir === 'next' ) ? '100%' : '-100%',
        zIndex : 999
    } );
 
    setTimeout( function() {
 
        $currentItem.addClass( 'ps-move' ).css( {
            top : ( dir === 'next' ) ? '100%' : '-100%',
            zIndex : 1
        } );
 
        $currentSlide.addClass( 'ps-move' ).css( {
            top : ( dir === 'next' ) ? '-100%' : '100%',
            zIndex : 1
        } );
 
        // перемещение новых элементов в текущую область просмотра
        $newItem.addClass( 'ps-move' ).css( 'top', 0 );
        $newSlide.addClass( 'ps-move' ).css( 'top', 0 );
 
        if( !support ) {
 
            isAnimating = false;
 
        }
 
    }, 0 );
 
    // обновление навигационных изображений
    updateNavImages();
 
};

ДЕМО СКАЧАТЬ Перевод статьи Vertical Showcase Slider with jQuery and CSS Transitions

 

Тэги: transitionslider

Вход

Уважаемый пользователь! Мы обнаружили, что вы используете AdBlock и вынуждены скрыть часть материалов на нашем сайте. Siteacademy существует и развивается за счет доходов от рекламы. Просим внести наш сайт в список исключений или отключить Блокировщик рекламы на нашем сайте.