「Johanna Knauer」

Johanna Knauer

Johanna Knauer – 德国女摄影师

01

02

03

04

05

「Anna Ovchinnikova」

Anna Ovchinnikova

Anna Ovchinnikova – 乌克兰女摄影师

01

02

03

04

05

06

「通过jQuery和CSS变换属性打造垂直展示幻灯片」

通过jQuery和CSS变换属性打造垂直展示幻灯片

原文:VERTICAL SHOWCASE SLIDER WITH JQUERY AND CSS TRANSITIONS

在本教程中,我们将针对网上商店创建一个非常简单的和响应式的产品幻灯片。我们的想法是在一个全屏视图中包含不同的部分:图像或预览,导航以及描述。当浏览项目时,我们将通过滑动来展示预览部分,并且同时相反方向滑动展示描述部分。这种反方向动画效果的灵感来自于 National LGBT Museum 网站,当浏览或者滚动页面时以相同的方式来移动左边和右边的内容。

演示demo源码下载

请注意:该效果仅工作在支持各自CSS属性的浏览器上。

用于Demo演示的产品图片和信息内容来自于IKEA

标记

我们将有过一个包裹以下元素的主容器:一个标题,一个内容或者是描述的包装器以及一个幻灯片包装器:


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

幻灯片包装器将包含与内容包装器相同数量的div,每一个div有各自的图片作为背景图片。还将有一个包含前一个和后一个锚点的导航,这些锚点也将有一个背景图片,但是我们将其设置为动态的。

接下来让我们添加一些样式。

CSS

需要注意的是,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%屏幕宽度和高度的布局,所以我们将容器设置为绝对定位,并且内容溢出时隐藏:


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

内容包装器将需要与标题高度相同的高度,并且我们将其设置为溢出时隐藏:


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

内部div将占据父元素全部的高度和宽度,我们将给它添加一些padding:


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

需要注意的是,我们在设置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;
}

幻灯片包装器将被从顶部0像素到底部200px的位置拉伸,这将保持其高度是弹性的:


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

包含背景图片的内部div将会有100%的宽度和高度,我们将给它们一个内嵌盒阴影,巧妙的覆盖在主图片预览上。由于我们不知道div的确切大小,所以我们给它一个极其大的传播半径值:


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

当我们要使幻灯片元素滑入或滑出,下一个class是动态的:


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

最后,但并非最不重要的是,我们将针对小型设备定义一个媒体查询。当JavaScript可用时,我们只希望通过media query来改变样式,而在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;
}

The wrapper for the preview slides will be positioned differently since we’ll place the content under it:


.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。

Javascript

我们将从通过缓存一些元素和定义一些变量开始:


var $container = $( '#ps-container' ),
    $contentwrapper = $container.children( 'div.ps-contentwrapper' ),
    // the items (description elements for the slides/products)
    $items = $contentwrapper.children( 'div.ps-content' ),
    itemsCount = $items.length,
    $slidewrapper = $container.children( 'div.ps-slidewrapper' ),
    // the slides (product images)
    $slidescontainer = $slidewrapper.find( 'div.ps-slides' ),
    $slides = $slidescontainer.children( 'div' ),
    // navigation arrows
    $navprev = $slidewrapper.find( 'nav > a.ps-prev' ),
    $navnext = $slidewrapper.find( 'nav > a.ps-next' ),
    // current index for items and slides
    current = 0,
    // checks if the transition is in progress
    isAnimating = false,
    // support for CSS transitions
    support = Modernizr.csstransitions// transition end event
    // transition end event
    // https://github.com/twitter/bootstrap/issues/2870
    transEndEventNames = {
        'WebkitTransition' : 'webkitTransitionEnd',
        'MozTransition' : 'transitionend',
        'OTransition' : 'oTransitionEnd',
        'msTransition' : 'MSTransitionEnd',
        'transition' : 'transitionend'
    };

当初始函数调用时,首先显示的第一条项目及相关图片,同时,我们要更新导航箭头正确的背景图片,这意味着我们要使用相同的背景图片作为预览。最后,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() );
 
},

我们需要初始化两个导航元素的click事件以及项目/描述和幻灯片两者的transitionend事件。


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

主函数当然是slide函数,我们的想法是将下一张幻灯片放置在当前幻灯片的上方或下方(取决于我们所点击的导航元素)。


slide = function( dir ) {
 
    isAnimating = true;
 
    var $currentItem = $items.eq( current ),
        $currentSlide = $slides.eq( current );
 
    // update current value
    if( dir === 'next' ) {
 
        ( current  0 ) ? --current : current = itemsCount - 1;
 
    }
        // new item that will be shown
    var $newItem = $items.eq( current ),
        // new slide that will be shown
        $newSlide = $slides.eq( current );
 
    // position the new item up or down the viewport depending on the direction
    $newItem.css( {
        top : ( dir === 'next' ) ? '-100%' : '100%',
        zIndex : 999
    } );
     
    $newSlide.css( {
        top : ( dir === 'next' ) ? '100%' : '-100%',
        zIndex : 999
    } );
 
    setTimeout( function() {
 
        // move the current item and slide to the top or bottom depending on the direction 
        $currentItem.addClass( 'ps-move' ).css( {
            top : ( dir === 'next' ) ? '100%' : '-100%',
            zIndex : 1
        } );
 
        $currentSlide.addClass( 'ps-move' ).css( {
            top : ( dir === 'next' ) ? '-100%' : '100%',
            zIndex : 1
        } );
 
        // move the new ones to the main viewport
        $newItem.addClass( 'ps-move' ).css( 'top', 0 );
        $newSlide.addClass( 'ps-move' ).css( 'top', 0 );
 
        // if no CSS transitions set the isAnimating flag to false
        if( !support ) {
 
            isAnimating = false;
 
        }
 
    }, 0 );
 
    // update nav images
    updateNavImages();
 
};

这就是全部代码,希望你喜欢这个教程并能够有所启发!

原创译文 转载请注明出处
英文原文:VERTICAL SHOWCASE SLIDER WITH JQUERY AND CSS TRANSITIONS