Lecaw

Учимся создавать Web-сайты

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

October 5, 2012 777hits

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

 Исходные файлыДЕМО

 

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="#">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 -->

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

CSS

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

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

Оболочка вертикального слайдера будет расширена, сверху - 0px, в нижней части – 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; 
}

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

Мы должны установить 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();
 
};

 Исходные файлыДЕМО

 

Дополнительная информация

RATTING:
(0 голосов)