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

 

Используя различные атрибуты data, мы определим тип, угол вращения и масштаб частей слайда.
Мы будем использовать следующие jQuery плагины:

  • http://benalman.com/projects/jquery-cond-plugin/
  • http://ricostacruz.com/jquery.transit/

А иконки животных возьмем из шрифта:

  • http://www.dafont.com/animals.font

Разметка HTML

Наша начальная разметка будет состоять из основного контейнера с классом и идентификатором sl-slider, который будет содержать все слайды, каждый из которых имеет класс sl-slide. Также будут дополнительно добавлены классы для изменения цвета слайдов:

<section id="sl-slider" class="sl-slider">
 
    <div class="sl-slide">
        <div class="sl-deco" data-icon="6"></div>
        <h2>Цитаты, высказывания, афоризмы</h2>
        <blockquote>
            <p>Будь проще к людям. Хочешь быть мудрей — Не делай больно мудростью своей.</p>
            <cite>Омар Хайям</cite>
        </blockquote>
    </div>
 
    <div class="sl-slide sl-slide-dark">
        <!-- ... -->
    </div>
 
    <!-- ... -->
 
</section>

Каждый слайд имеет некоторые атрибуты data, которые будут использоваться для управления эффектами:
data-orientation
data-cut1-rotation
data-cut2-rotation
data-cut1-scale
data-cut2-scale

Первый - data-orientation - ориентация или "vertical" или "horizontal". Это необходимо, чтобы нам знать, где разделять слайд - горизонтально или вертикально. Атрибуты data-cut1-rotation и data-cut2-rotation определяют угол вращения для каждого отрезанного кусочка, а data-cut1-scale и data-cut2-scale - будут определять значение масштабирования.
Так для первого слайда у нас будут такие значения:
<div class="sl-slide" data-orientation="horizontal" data-cut1-rotation="-25" data-cut2-rotation="-25" data-cut1-scale="2" data-cut2-scale="2">

Наша структура - это "базовая структура". Мы построим эту структуру, используя javascript, чтобы можно было создать эффекты. Итак, мы преобразуем нашу структуру в это:
<section id="sl-slider" class="sl-slider">
 
    <div class="sl-slides-wrapper">
 
        <div class="sl-slide sl-slide-horizontal">
            <div class="sl-content-wrapper">
                <div class="sl-content">
                    <!-- контент -->
                </div>
            </div>
        </div>
 
        <!-- ... -->
 
    </div>
 
    <nav>
        <span class="sl-prev">Назад</span>
        <span class="sl-next">Вперед</span>
    </nav>
 
</section>

Добавим навигацию и несколько оболочек (wrapper) для контента.
В момент, когда мы переходим к следующему или предыдущему слайду, мы берем текущий слайд и дублируем его оболочку (wrapper) контента, создавая "разрез".
<div class="sl-slide sl-slide-horizontal" >
 
    <div class="sl-content-cut">
        <div class="sl-content-wrapper">
            <div class="sl-content">
                <!-- ... -->
            </div>
        </div>
    </div>
 
    <div class="sl-content-cut">
        <div class="sl-content-wrapper">
            <div class="sl-content">
                <!-- ... -->
            </div>
        </div>
    </div>
 
</div>

Теперь перейдем к стилям.

CSS

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

.sl-slider {
    position: absolute;
    top: 0;
    left: 0;
    font-family: 'Montserrat', Arial, sans-serif;
}

Ширина и высота будет устанавливаться динамически в javascript.
Для стрелок навигации мы будем использовать технику image-less (уменьшения изображения). У нас будет простой небольшой box (контейнер), который повернем на 45 градусов. Далее добавим штриховую границу (dashed border) к сторонам box и получим аккуратные стрелочки:
.sl-slider nav span {
    position: fixed;
    z-index: 2000;
    top: 50%;
    width: 80px;
    height: 80px;
    border: 2px dashed #ddd;
    border: 2px dashed rgba(150,150,150,0.4);
    text-indent: -90000px;
    margin-top: -40px;
    cursor: pointer;
    transform: rotate(45deg);
    transition: all 0.3s ease-in-out;
}
.sl-slider nav span.sl-prev {
    left: 60px;
    border-right: none;
    border-top: none;
}
 
.sl-slider nav span.sl-next {
    right: 60px;
    border-left: none;
    border-bottom: none;
}

Также мы добавили переход, чтобы изменять значение прозрачности RGBA при наведении:
.sl-slider nav span:hover {
    border-color: rgba(150,150,150,0.9);
}

Слайды и новая оболочка (wrapper) будет абсолютно позиционирована и займет 100% ширину и высоту:
.sl-slide, .sl-slides-wrapper {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    overflow: hidden;
}

У каждого слайда будет z-index равный 1; мы будем управлять появлением и расположением слайдов с помощью javascript:
.sl-slide {
    z-index: 1;
}

Содержимое "кусочков" будет позиционироваться абсолютно и их общий стиль будет таким:
/* Дублирование частей/кусочков */
 
.sl-content-cut {
    overflow: hidden;
    position: absolute;
    box-sizing: content-box;
    background: #fff;
}

Мы используем box-sizing: content-box, потому что по умолчанию (в нашем normalize.css) мы используем border-box.
Содержимое "кусочков" будет горизонтально или вертикально располагаться, а их высота или ширина будет равна половине размера экрана. Чтобы невидеть края "кусочков" при вращении, мы добавим отступ (padding):
/* Horizontal cut */
 
.sl-slide-horizontal .sl-content-cut {
    width: 100%;
    height: 50%;
    left: -200px;
}
 
.sl-slide-horizontal .sl-content-cut:first-child {
    top: -200px;
    padding: 200px 200px 0px 200px;
}
 
.sl-slide-horizontal .sl-content-cut:nth-child(2) {
    top: 50%;
    padding: 0px 200px 200px 200px;
}
 
/* Vertical cut */
 
.sl-slide-vertical .sl-content-cut {
    width: 50%;
    height: 100%;
    top: -200px;
}
 
.sl-slide-vertical .sl-content-cut:first-child {
    left: -200px;
    padding: 200px 0px 200px 200px;
}
 
.sl-slide-vertical .sl-content-cut:nth-child(2) {
    left: 50%;
    padding: 200px 200px 200px 0px;
}

Мы используем отрицательные значения положения, чтобы "вернуть" кусочки на место.
Далее стиль оболочки контента и разделения контента:
/* Обоолчка контента */
/* Ширина и Высота устанавливаются динамически */
.sl-content-wrapper {
    position: absolute;
}
 
.sl-content {
    width: 100%;
    height: 100%;
    background: #fff;
}

Разделение с классом sl-content-wrapper получит высоту и ширину динамически. Если, например, слайд горизонтальный, то у оболочки ширина будет равна 100% ширине экрана и 50% высоте экрана. Оболочка второго "кусочка" будет также иметь отрицательный отступ сверху - top (горизонтально) или слева - left (вертикально), чтобы вернуть дублированный контент сверху или слева.
Элементы, которые используются в контенте будут декоративными элементами (животные с кружками), заголовок и блок цитирования. Мы будем использовать шрифт с иконками животных, которые будут у нас, как псевдо-элементы.
Разделение с классом sl-deco, точно также, как и все другие элементы контента будут абсолютно позиционированы. Также отцентрируем по горизонтали и присвоим значение bottom 50%.
/* Элементы контента */
 
.sl-deco{
    width: 260px;
    height: 260px;
    border: 2px dashed rgba(150,150,150,0.4);
    border-radius: 50%;
    position: absolute;
    bottom: 50%;
    left: 50%;
    margin-left: -130px;
}

Используем атрибут "data-icon" в декоративном элементе и используем псевдо-элемент :after, который будет содержать букву из шрифта с иконками животных:
[data-icon]:after {
    content: attr(data-icon);
    font-family: 'AnimalsNormal';
    color: #000;
    text-shadow: 0 0 1px #000;
    position: absolute;
    width: 220px;
    height: 220px;
    line-height: 220px;
    text-align: center;
    font-size: 100px;
    top: 50%;
    left: 50%;
    margin: -110px 0 0 -110px;
    box-shadow: inset 0 0 0 10px #f7f7f7;
    border-radius: 50%;
}

Box-shadow создаст "поддельную" внутреннюю границу.
Заголовок, также будет позиционироваться абсолютно и мы дадим ему то же самое минимальное значение, что мы и дали декоративному элементу, которое составляет 50%. Затем добавим отрицательный отступ снизу, чтобы поместить его под другим элементом. Мы можем использовать декоративный элемент в качестве контрольной точки и расположить другие элементы относительно него, используя отрицательное значение отступа снизу:
.sl-slide h2 {
    color: #000;
    text-shadow: 0 0 1px #000;
    padding: 20px;
    position: absolute;
    font-size: 34px;
    font-weight: 300;
    letter-spacing: 13px;
    text-transform: uppercase;
    width: 80%;
    left: 10%;
    text-align: center;
    line-height: 50px;
    bottom: 50%;
    margin: 0 0 -120px 0;
}

У блока цитирования будет ширина 30% и так как мы хотим центрировать его, то дадим ему значение слева равное 35% (потому что мы имеем про запас 70%, и берем половину), и устанавливаем соответствующее значение text-align:
.sl-slide blockquote {
    position: absolute;
    width: 30%;
    text-align: center;
    left: 35%;
    font-size: 13px;
    line-height: 20px;
    height: 70px;
    color: #8b8b8b;
    z-index: 2;
    bottom: 50%;
    margin: 0 0 -200px 0;
    padding: 0;
}

Давайте добавим кавычку к блоку цитирования. Используя псевдо класс :before, мы добавим кавычку увеличенного размера позади блока цитирования:
.sl-slide blockquote:before {
    color: rgba(244,244,244,0.65);
    font-family: "Bookman Old Style", Bookman, Garamond, serif;
    position: absolute;
    line-height: 60px;
    width: 75px;
    height: 75px;
    font-size: 200px;
    z-index: -1;
    left: -15px;
    top: 35px;
    content: '201C';
}

А цитата будет выглядеть так:
.sl-slide blockquote cite {
    font-size: 10px;
    font-style: normal;
    text-transform: uppercase;
    letter-spacing: 4px;
}

Далее, определим некоторые классы для управления цветами слайдов. Когда мы применяем класс цвета к слайду, мы хотим, чтобы цвет фона и цвета элементов отличались. По умолчанию, наши слайды белые, а элементы контента черные и серые.
У темных или черных слайдов будет инвертированная цветовая схема:
/* Dark slides */
.sl-slide-dark .sl-content-cut,
.sl-slide-dark .sl-content {
    background: #000;
}
 
.sl-slide-dark [data-icon]:after,
.sl-slide-dark.sl-slide h2 {
    color: #fff;
}
 
.sl-slide-dark.sl-slide blockquote:before {
    color: #222;
}

А вот стили для других цветовых схем:
/* Цвет 1 для слайда */
.sl-slide-color-1 .sl-content-cut,
.sl-slide-color-1 .sl-content {
    background: #8d0f39;
}
 
.sl-slide-color-1 [data-icon]:after {
    color: #e6a6bb;
    text-shadow: 0 0 1px #e6a6bb;
    box-shadow: inset 0 0 0 10px #e6a6bb;
}
 
.sl-slide-color-1.sl-slide h2,
.sl-slide-color-1.sl-slide blockquote{
    color: #fff;
}
 
.sl-slide-color-1.sl-slide blockquote:before {
    color: #7b0c31;
}
 
/* Цвет 2 для слайда */
.sl-slide-color-2 .sl-content-cut,
.sl-slide-color-2 .sl-content {
    background: #ade1f4;
}
 
.sl-slide-color-2 [data-icon]:after {
    text-shadow: 0 0 1px #8bc7dd;
    color: #8bc7dd;
}
 
.sl-slide-color-2.sl-slide h2,
.sl-slide-color-2.sl-slide blockquote{
    color: #fff;
    text-shadow: 1px 1px 1px rgba(0,0,0,0.2);
}
 
.sl-slide-color-2.sl-slide blockquote:before {
    color: #8bc7dd;
}
 
/* Цвет 3 для слайда */
.sl-slide-color-3 .sl-content-cut,
.sl-slide-color-3 .sl-content {
    background: #ffeb41;
}
 
.sl-slide-color-3.sl-slide h2,
.sl-slide-color-3.sl-slide blockquote{
    color: #000;
    text-shadow: 1px 1px 1px rgba(0,0,0,0.1);
}
 
.sl-slide-color-3.sl-slide blockquote:before {
    color: #ecd82c;
}

И наконец, добавим движения нашим элементам контента. Когда мы перемещаемся по слайдам, то хотим, чтобы элементы контента делали что-нибудь интересное
/* Анимация для элементов */
 
.sl-trans-elems .sl-deco{
    animation: roll 1s ease-out both;
}
 
.sl-trans-elems h2{
    animation: moveUp 1s ease-in-out both;
}
 
.sl-trans-elems blockquote{
    animation: fadeIn 0.5s linear 0.5s both;
}
 
@keyframes roll{
    0% {transform: translateX(500px) rotate(360deg); opacity: 0;}
    100% {transform: translateX(0px) rotate(0deg); opacity: 1;}
}
 
@keyframes moveUp{
    0% {transform: translateY(40px);}
    100% {transform: translateY(0px);}
}
 
@keyframes fadeIn{
    0% {opacity: 0;}
    100% {opacity: 1;}
}

Декоративный элемент будет "выкатываться" с правой стороны, заголовок будет двигаться вверх, а цитата будет растворяться.
Теперь, когда мы будем перемещаться по слайдам назад, то мы бы хотели увидеть, что же случиться при таком реверсе:
.sl-trans-back-elems .sl-deco{
    animation: scaleDown 1s ease-in-out both;
}
.sl-trans-back-elems h2{
    animation: fadeOut 1s ease-in-out both;
}
.sl-trans-back-elems blockquote{
    animation: fadeOut 1s linear both;
}
@keyframes scaleDown{
    0% {transform: scale(1);}
    100% {transform: scale(0.5);}
}
@keyframes fadeOut{
    0% {opacity: 1;}
    100% {opacity: 0;}
}

А увидим мы следующее: декоративный элемент будет уменьшаться и растворится.

javascript

Для начала подключим все используемые скрипты:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.ba-cond.min.js"></script>
<script type="text/javascript" src="js/jquery.transit.min.js"></script>
<script type="text/javascript" src="js/jquery.slitslider.js"></script>
<script type="text/javascript">   
    $(function() {           
        $( '#sl-slider' ).slitslider();           
    });
</script>

А теперь поговорим подробнее о скрипте jquery.slitslider.js.
У нашего плагина доступны следующие опции:
$.Slitslider.defaults   = {
    speed       : 1000, //скорость переходов
    autoplay    : false, //выключение слайдшоу, true - включение
    interval    : 4000, // интервал смены слайдов при включенном autoplay в мс
    optOpacity  : false, // непрозрачность "кусочков" (true, false)
    translateF  : 160, // Значение в % определяющее скорость, масштабирование переходов при разделении на кусочки.
    maxAngle    : 25, // максимальное значение угла
    maxScale    : 2 // максимальная величина масштабирования
};

Начнем с _init функции:
_init               : function( options ) {
 
    // опции
    this.options    = $.extend( true, {}, $.Slitslider.defaults, options );
    // слайдер
    this.$slides    = this.$slider.children( '.sl-slide' ).hide();
    // общее количество слайдов
    this.slidesCount= this.$slides.length;
    // текущий слайд
    this.current    = 0;
    // анимировать текущий?
    this.isAnimating= false;
    // получение размеров окна
    this._getWinSize();
    // создание макета
    this._layout();
    // загрузка событий
    this._loadEvents();
    // старт слайдшоу
    if( this.options.autoplay ) {
 
        this._startSlideshow();
 
    }
 
}

Взглянем на _layout функцию
_layout             : function() {
 
    this.$slideWrapper = $( '<div class="sl-slides-wrapper" />' );
    // wrap the slides into "sl-slides-wrapper"
    this.$slides.wrapAll( this.$slideWrapper ).each( function( i ) {
 
        var $slide          = $( this ),
            // vertical || horizontal
            orientation     = $slide.data( 'orientation' );
 
        $slide.addClass( 'sl-slide-' + orientation )
              .children()
              .wrapAll( '<div class="sl-content-wrapper" />' )
              .wrapAll( '<div class="sl-content" />' );
 
    } );
 
    // set the right size of the slider and slides according to the current window size
    this._setSize();
    // show first slide
    this.$slides.eq( this.current ).show();
    // add navigation
    if( this.slidesCount > 1 ) {
 
        this.$slider.append(
            '<nav><span class="sl-prev">Previous</span><span class="sl-next">Next</span></nav>'
        );
 
    }
 
}

Вставляем оболочку слайдов в разделитель с классом sl-slides-wrapper. Как мы уже упоминали ранее, содержимое каждого слайда будет обернуто двумя разделителями, первый с классом sl-content и второй с классом sl-content-wrapper.
Также мы добавим соответствующий класс определяющий ориентацию (sl-slide-vertical или sl-slide-horizontal).
Слайдер и разделитель sl-content-wrapper должны иметь ширину и высоту окна. Это мы будем делать в _setSize функции.
Наконец, мы покажем текущий/первый слайд и добавим кнопки навигации.
В функции _loadEvents мы будем связывать события для двух кнопок навигации и событие изменения размера окна (smartresize):
_loadEvents         : function() {
 
    var _self = this;
 
    if( this.slidesCount > 1 ) {
 
        // navigate "in" or "out"
        this.$slider.find( 'nav > span.sl-prev' ).on( 'click.slitslider', function( event ) {
 
            if( _self.options.autoplay ) {
 
                clearTimeout( _self.slideshow );
                _self.options.autoplay  = false;
 
            }
            _self._navigate( 'out' );
 
        } ).end().find( 'nav > span.sl-next' ).on( 'click.slitslider', function( event ) {
 
            if( _self.options.autoplay ) {
 
                clearTimeout( _self.slideshow );
                _self.options.autoplay  = false;
 
            }
            _self._navigate( 'in' );
 
        } );
 
    }
 
    $( window ).on( 'smartresize.slitslider', function( event ) {
 
        // update window size
        _self._getWinSize();
        _self._setSize();
 
    } );
 
}

Теперь посмотрим, как мы будем "разделять" слайды и переходить к следующему:
_navigate           : function( dir ) {
 
    // return if currently navigating / animating
    if( this.isAnimating ) {
 
        return false;
 
    }
 
    var _self = this;
 
    // while isAnimating is true we cant navigate..
    this.isAnimating = true;
 
    // the current slide
    var $currentSlide   = this.$slides.eq( this.current ), css;
 
    // set new current
    ( dir === 'in' ) ?
            ( ( this.current < this.slidesCount - 1 ) ? ++this.current : this.current = 0 ) :
            ( ( this.current > 0 ) ? --this.current : this.current = this.slidesCount - 1 )
 
        // next slide to be shown
    var $nextSlide      = this.$slides.eq( this.current ).show(),
        // the slide we want to cut and animate
        $movingSlide    = ( dir === 'in' ) ? $currentSlide : $nextSlide,
        // the following are the data attrs set for each slide
        orientation     = $movingSlide.data( 'orientation' ) || 'horizontal',
        cut1angle       = $movingSlide.data( 'cut1Rotation' ) || 0,
        cut1scale       = $movingSlide.data( 'cut1Scale' ) || 1,
        cut2angle       = $movingSlide.data( 'cut2Rotation' ) || 0,
        cut2scale       = $movingSlide.data( 'cut2Scale' ) || 1;
 
    this._validateValues( cut1angle, cut2angle, cut1scale, cut2scale, orientation );
 
    if( orientation === 'vertical' ) {
 
        css = { marginLeft : -this.windowProp.width / 2 };
 
    }
    else if( orientation === 'horizontal' ) {
 
        css = { marginTop : -this.windowProp.height / 2 };
 
    }
    // default slides cuts style
    var resetStyle  = ( orientation === 'horizontal' ) ? { x : '0%', y : '0%', rotate : 0, scale : 1, opacity : 1 } : { x : '0%', y : '0%', rotate : 0, scale : 1, opacity : 1 },
 
        // cut1 style
        cut1Style   = ( orientation === 'horizontal' ) ? { y : '-' + this.options.translateF + '%', rotate : cut1angle, scale : cut1scale } : { x : '-' + this.options.translateF + '%', rotate : cut1angle, scale : cut1scale },
 
        // cut2 style
        cut2Style   = ( orientation === 'horizontal' ) ? { y : this.options.translateF + '%', rotate : cut2angle, scale : cut2scale } : { x : this.options.translateF + '%', rotate : cut2angle, scale : cut2scale };
 
    if( this.options.optOpacity ) {
 
        cut1Style.opacity = 0;
        cut2Style.opacity = 0;
 
    }
 
    // we are adding the classes sl-trans-elems and sl-trans-back-elems
    // to the slide that is either coming "in"
    // or going "out" according to the direction
 
    // the idea is to make it more interesting by
    // giving some animations to the respective slides elements
 
    ( dir === 'in' ) ? $nextSlide.addClass( 'sl-trans-elems' ) : $currentSlide.addClass( 'sl-trans-back-elems' );
 
    $currentSlide.removeClass( 'sl-trans-elems' );
 
    // add the 2 cuts and animate them
    // (we are using the jquery.transit plugin:
    // http://ricostacruz.com/jquery.transit/ to
    // add transitions to the elements)
 
    $movingSlide.css( 'z-index', this.slidesCount )
                .find( 'div.sl-content-wrapper' )
                .wrap( '<div class="sl-content-cut" />' )
                .parent()
                .cond(
                    dir === 'out',
                    function() {
 
                        this.css( cut1Style )
                            .transition( resetStyle, _self.options.speed, dir );
 
                    },
                    function() {
 
                        this.transition( cut1Style, _self.options.speed, dir )
 
                    }
                )
                .clone()
                .appendTo( $movingSlide )
                .cond(
                    dir === 'out',
                    function() {
 
                        var cut = this;
                        cut.css( cut2Style )
                            .transition( resetStyle, _self.options.speed, dir , function() {
 
                                _self._onEndNavigate( cut, $currentSlide, dir );
 
                            } )
 
                    },
                    function() {
 
                        var cut = this;
                        cut.transition( cut2Style, _self.options.speed, dir, function() {
 
                            _self._onEndNavigate( cut, $currentSlide, dir );
 
                        } )
 
                    }
                )
                .find( 'div.sl-content-wrapper' )
                .css( css );
 
}

Таким образом, весь фокус заключается в том, чтобы дублировать контент слайда в разделителях с классом sl-content-cut и установить второй margin-left или margin-top от половины ширины окна или высоты.
Затем, согласно значений указанных в data атрибутах мы будем анимировать разделение слайдов с помощью плагина jQuery Transit (http://ricostacruz.com/jquery.transit/).
В соответствии с направлением, мы либо режем текущий слайд и показываем следующий, или будем резать предыдущий (не показано) и помещать его поверх текущего.
Мы добавляем классы sl-trans-elems и sl-trans-back-elems к слайду, который будет следующим (когда мы двигаемся вперед) или к текущему (когда мы двигаемся назад).
Далее функция _onEndNavigate, где мы будем разворачивать содержимое текущего слайда, удалив два разделителя sl-content-cut:
_onEndNavigate      : function( $slice, $oldSlide, dir ) {
 
    // reset previous slide's style after next slide is shown
    var $slide          = $slice.parent(),
        removeClasses   = 'sl-trans-elems sl-trans-back-elems';
 
    // remove second slide's cut
    $slice.remove();
    // unwrap..
    $slide.css( 'z-index', 1 )
          .find( 'div.sl-content-wrapper' )
          .unwrap();
 
    // hide previous current slide
    $oldSlide.hide().removeClass( removeClasses );
    $slide.removeClass( removeClasses );
    // now we can navigate again..
    this.isAnimating = false;
 
}
СКАЧАТЬСкачек: 645
204,51 Kb
Кто скачал?

ДЕМОПосмотреть
пример