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

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

Слайдер с эффектом перелистывания страниц с помощью CSS3 и jQuery

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

В последнее время на многих сайтах стал достаточно популярным эффект перелистывания. Поэтому достаточно актуальным было бы добиться этого эффекта с помощью  jQuery и CSS3. Мы будем создавать  блоки с картинками, которые в дальнейшем будут преобразованы в книгу. Также наш слайдер будет иметь кнопки, с помощью которых пользователь  сможет видеть, на какой странице он сейчас находится. Страницы слайдера будут представлены в виде изображений в  HTML, но каждое из них будет разделено на две страницы с помощью jQuery. 

 
Мы собираемся писать этот код как плагин  JQuery, поэтому сначала нам нужно включить jQuery. Далее подключаем библиотеку Modernizr. Нам нужны только 3d-преобразования, и вы можете скачать необходимый скрипт отсюда. Это будет гарантировать, что все будет прекрасно работать в браузерах, которые не поддерживают 3D преобразования. Дальше нужно создать файл с именем jquery.pictureflip.js, который будет размещен в том же месте, где и код нашего плагина. HTML должен выглядеть следующим образом:
<script src="modernizr.js"></script>
<script src="jquery.js"></script>
<script src="javascript.js"></script>

Body

HTML-разметка  довольно проста.  Все что нужно сделать, поместить группу дивов, которые будут представлять наши изображения в HTML. А затем Создать еще один блок с определенным  ID? например, #flipbook.

<div id="container">
    <div id="flipbook">

        <div id="image-1"> <div class="content"><a href="#">Flowers: What you didn't know</a></div> </div>
        <div id="image-2"> <div class="content"><a href="#">Flowers: Real or Fiction?</a></div> </div>
        <div id="image-3"> <div class="content"><a href="#">A Flower ate my Baby!</a></div> </div>
        <div id="image-4"> <div class="content"><a href="#">Will Flowers Destroy Earth?</a></div> </div>
    </div>
</div>

Давайте теперь перейдем к стилям.

CSS

Вместе с некоторыми стандартными стилями  CSS, мы будем использовать 3D-преобразования для выполнения эффекта листания страниц. В JQuery мы  разделим блок с изображениями на два отдельных дивы, а затем повернем один таким образом, чтобы казалось, что мы переворачиваем страницу . Для начала, давайте добавим некоторые основные стили.

#container {
    padding: 10px;
    box-shadow: 0px 0px 10px rgba(0,0,0,0.1);
    margin: 20px auto;
    width: 600px;
    height: 330px;
}

/* 600x300px in size */
.flipbook {
    position: relative;
    width: 600px;
    height: 300px;
    z-index: 999;
}

.flipbook > div {
    width: inherit;
    height: inherit;
    position: absolute;
    top: 0px;
    left: 0px;
    text-align: left;
}

.flipbook .hide {
    display: none;
}

.flipbook > div > div {
    width: inherit;
    height: inherit;
    background-size: 600px 300px;
    width: 50%;
    height: 100%;
    position: absolute;
}
/* разделяем блок с картинкой на два отдельных. */
/* Второй должен быть справа, а первый слева */
.flipbook div[class$="-fend"] {
    background-position: 100% 0;
    left: 50%;
}

В разделе JQuery мы будем подвигать две части изображений в следующий див, который будет иметь название  moving-div. Мы разместим их так, чтобы в целом они давали цельное изображение, а затем вращать. Чтобы это правильно осуществить, применяем к moving-div 3D- трансформацию.

/* Preserve 3D */

.flipbook .moving-div {
    z-index: 99999;
    width: 50%;

    -webkit-perspective: 1000;
    -webkit-transform-style: preserve-3d;
    -webkit-transform-origin: 0 0;

    -moz-perspective: 1000;
    -moz-transform-style: preserve-3d;
    -moz-transform-origin: 0 0;

    -o-perspective: 1000;
    -o-transform-style: preserve-3d;
    -o-transform-origin: 0 0;

    -ms-perspective: 1000;
    -ms-transform-style: preserve-3d;
    -ms-transform-origin: 0 0;

    perspective: 1000;
    transform-style: preserve-3d;
    transform-origin: 0 0;
}

/* Make the backfaces invisible */
.flipbook .moving-div div {
    -webkit-backface-visibility: hidden;
    -moz-backface-visibility: hidden;
    -o-backface-visibility: hidden;
    -ms-backface-visibility: hidden;
    backface-visibility: hidden;
    width: 100%;
    z-index: 9999;
}
/* Ensure the divs are in the correct position */
.flipbook .moving-div > div[class$="-fend"] {
    left: 0;
}
/* Rotate the last card so its facing back to back with the first one */
.flipbook .moving-div > div[class$="-fstart"] {
    -webkit-transform: rotateY(180deg);
    -moz-transform: rotateY(180deg);
    -o-transform: rotateY(180deg);
    -ms-transform: rotateY(180deg);
    transform: rotateY(180deg);
}

 

 Внутри moving-div будут размещены два span, которые будут создавать эффект тени. Они будут анимированы в части jQuery. 

 

/* The two spans are shadows for depth */
.flipbook .moving-div span {
    box-shadow: inset 60px 0 60px -60px rgba(0,0,0,0.1);
    width: 100%;
    height: 100%;
    position: absolute;
    opacity: 0;
    display: block;
    z-index: 999999;
    top: 0;
    background: rgba(0,0,0,0.1);
    -webkit-backface-visibility: hidden;
    -moz-backface-visibility: hidden;
    -o-backface-visibility: hidden;
    -ms-backface-visibility: hidden;
    backface-visibility: hidden;
    left: 0;
}
.flipbook .moving-div span:last-of-type {
    -webkit-transform: rotateY(180deg);
    -moz-transform: rotateY(180deg);
    -o-transform: rotateY(180deg);
    -ms-transform: rotateY(180deg);
    transform: rotateY(180deg);
    box-shadow: inset -60px 0 60px -60px rgba(0,0,0,0.1);
}

Есть также несколько других классов, которые будут добавлены в классы, чтобы создавать вращение moving-div . Для них используем простые 3D-трансформации

.flipbook .rotateYForward {
    -webkit-transform: rotateY(180deg);
    -webkit-transition: -webkit-transform 1s ease-in;

    -moz-transform: rotateY(180deg);
    -moz-transition: -moz-transform 1s ease-in;

    -o-transform: rotateY(180deg);
    -o-transition: -o-transform 1s ease-in;

    -ms-transform: rotateY(180deg);
    -ms-transition: -o-transform 1s ease-in;

    transform: rotateY(180deg);
    transition: transform 1s ease-in;
    left: 50%;
}

.flipbook .beginMove {
    left: 50%;
    -webkit-transform: rotateY(180deg);
    -moz-transform: rotateY(180deg);
    -o-transform: rotateY(180deg);
    transform: rotateY(180deg);
}

.flipbook .rotateYBackward {
    -webkit-transform: rotateY(360deg);
    -webkit-transition: -webkit-transform 1s ease-in;

    -moz-transform: rotateY(360deg);
    -moz-transition: -moz-transform 1s ease-in;

    -o-transform: rotateY(360deg);
    -o-transition: -o-transform 1s ease-in;

    -ms-transform: rotateY(360deg);
    -ms-transition: -o-transform 1s ease-in;
    transform: rotateY(360deg);
    transition: transform 1s ease-in;
}

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

.flipbook.back-arrow.flipbook.forward-arrow{

    width: 100px;
    height: 100px;
    box-sizing: border-box;
        -moz-box-sizing: border-box;
    padding: 8px 28px;
    font-size: 7em;
    font-weight: bold;
    z-index: 10;
    left: -140px;
    color: #fff;
    top: 30%;
    border-radius: 100px;
    position: absolute;
    cursor: pointer;
    z-index: 999999;
    background-color: #396275;
}

.flipbook div[class$="-arrow"]:hover {
    box-shadow: inset 0px 0px 30px rgba(0,0,0,0.2);
}

.flipbook div[class$="-arrow"]:active {
    background-color: #2e505f;
    box-shadow: inset 0px 0px 30px rgba(0,0,0,0.1);
}

.flipbook .forward-arrow {
    right: -140px;
    left: auto;
    padding: 8px 34px;
    font-weight: bold;
}

.flipbook .buttons {
    width: 98%;
    padding: 7px 1%;
    height: 16px;
    background: #fff;
    position: relative;
    top: 300px;

}

.flipbook .buttons span {
    background: #fff;
    box-shadow: inset 0 0 8px rgba(0,0,0,0.1);
    width: 16px;
    cursor: pointer;
    height: 16px;
    border-radius: 16px;
    display: block;
    float: right;
    position: relative;
    margin-right: 5px;
}

.flipbook .buttons .selected {
    background-color: #47b1e2;
    box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
}

.flipbook .content {
    display: none;
    height: 30px;
    padding: 7px;
    z-index: 99999999;
    position: absolute;
    bottom: 0;
    width: 50%;
    font-size: 2em;
}
.flipbook a {
    color: #fff;
    font-weight: bold;
    text-decoration: none;
    border-bottom: 2px solid #fff;
    text-shadow: 0 0 10px rgba(0,0,0,0.1);
}

И, наконец, мы собираемся добавить изображения, которые мы будем использовать. Вы можете добавить больше, если пожелаете. В примере их будет 4. Они будут относиться к дивам image, которые мы определили ранее в HTML.   

/* THE IMAGES YOU WANT TO USE */

/* == add more if you want == */
/* == update the HTML too! == */

div[class^="image-1-"] {
    background: url('images/1.jpg');
}

div[class^="image-2-"] {
    background: url('images/2.jpg');
}

div[class^="image-3-"] {
    background: url('images/3.jpg');
}
div[class^="image-4-"] {
    background: url('images/4.jpg');
}

Переходим к JQuery! 

jQuery

Откройте ваш файл <span><span>jquery.pictureflip.js</span></span> файл. Основная структура JQuery плагина должна иметь следующий вид:  

(function($){

    $.fn.extend({ 

        // The name of your plugin 
        pictureflip: function(options) {

            // Some default values. The user will be able to alter these
            var defaults = {
                time: 1000,
                start: 1
            }

            // Connect the default values with the function variables
            var options = $.extend(defaults, options);

            // This bit is important, it ensures the chainability of jQuery
            // We have to return each object this plugin applies to, so that
            // the user can still add more jQuery functions on the end, i.e.
            // $('#item').pictureflip().appendClass('pictures');

            return this.each(function() {

                var o = options;
                var obj = $(this);

                // This is where our plugin code goes! It's just regular jQuery
                // from here on out!

            });

        }

    });
})(jQuery);

Создание плагина 

Чтобы приступить к определенным действиям, нам нужно объявить некоторые основные переменные, такие как количество изображений и проверку на анимацию изображений. 

// Некоторые переменные для начала работы

var time = o.time;
var imageNumber = $('div[id^="image"]', obj).length;
var animated = 0;

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

// Append UI
obj.append('<div class="back-arrow"><</div><div class="forward-arrow">></div><div class="moving-div hide"><span></span><span></span></div><div class="buttons"></div>');
obj.addClass('flipbook');

// Добавление кнопки в зависимости от выбранной фотографии
while(imageNumber > 0) {
    $('<span class="button-'+imageNumber+'"></span>').appendTo($('.buttons'));
    --imageNumber;
} 

// Fade в содержании текста 
$('div[id^="image-"]:first .content', obj).fadeIn();
// Эту функцию добавим позже
selectCircle();

Затем мы должны определить несколько простых функций. Эти функции анимации, z-index, перезапуск слайдов  и выбор правильного круга. 

// Изменение z-индекса 
function zIndexFix() {

    $('[id^="image"]').each(function(index) {
        zindex = index * -1;
        $(this).css('zIndex', zindex);
    });

}

// Restarts the slides to the regular position so they're ready to flip
// again!
function restartSlides() {

    var $moveFirst = $('.moving-div div:first').attr('class').split('-')[1];
    var $moveLast = $('.moving-div div:last').attr('class').split('-')[1];

    $('> .moving-div div:first', obj).appendTo($('> #image-'+$moveFirst, obj));
    $('> .moving-div div:last', obj).appendTo($('> #image-'+$moveLast, obj));

    $('.moving-div').removeClass('rotateYForward rotateYBackward beginMove').removeAttr('style');

    $('.moving-div').addClass('hide');
}

    // Анимация тени
function shadowAnimate(time) {

    $('.moving-div span').animate({opacity : 1}, time/2);

    setTimeout(function() {

        $('.moving-div span').animate({opacity : 0}, time/2);

    }, time/2);

}

// Выбор соответствующего круга на основе выбранных изображений.
function selectCircle() {
    var imageID = parseFloat($('> div[id^="image"]:first', obj).attr('id').split('-')[1]);

    $('.buttons span').removeClass('selected');
    $('.buttons .button-'+imageID).addClass('selected');
}

Давайте теперь перейдем к функции анимации. Была добавлена переменная, которая будет проверять, есть ли кнопка вперед или назад. Если вы заметили, то с помощью переменной prev будет идти проверка, какая кнопка нажата.  На данный момент, это не работает в Safari, поэтому был отключен эффект листания  в Safari .

 

// Функция анимации

 

function animation(prev, time, buttons) {

    // Исчезание текста
    $('div[id^="image-"]:first .content', obj).fadeOut(50);

    // Если анимация не работает, то мы можем начать 
    if(animated == 0) {
        // Анимация работает
        animated = 1;

            // Следующий слайд
            if(prev != true) {
                var $nextSlide = $('div[id^="image-"]:first ~ div[id^="image-"]:first', obj).attr('id');
            } else {
                var $nextSlide = $('div[id^="image-"]:last', obj).attr('id');
            }

            // Текущий слайд
            var $thisSlide = $('div[id^="image-"]:first', obj).attr('id');

            // If 3D Transforms are not supported then we just default back to 
            // fade in slides. These will not have the 3D effect but it will
            // still be usable.

            if(Modernizr.csstransforms3d == "" || (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1)) {

                $('> #'+$nextSlide, obj).prependTo(obj);
                if(prev != true) {
                    $('> #'+$thisSlide, obj).appendTo(obj);
                }
                animated = 0;
                zIndexFix();
                selectCircle();

                return false;

            }

            // Если нажата кнопка вперед
            if(prev != true) {

                // Добавление дивов к moving div
                $('> #'+$nextSlide+' > div[class$="-fstart"], > #'+$thisSlide+' > div[class$="-fend"]', obj).appendTo($('.moving-div'));

                // Rotate the moving div holder and change the time
                // based on what is set via Javascript
                $('.moving-div', obj).addClass('rotateYForward').css({

                    '-webkit-transition-duration': time/1000+'s',
                    '-moz-transition-duration': time/1000+'s',
                    '-ms-transition-duration': time/1000+'s',
                    '-o-transition-duration': time/1000+'s',
                    'transition-duration': time/1000+'s'

                });

                // Вращение дивов таким образом, чтобы было видно следующий 
                // А предыдущий див находился под ним
                $('> #'+$nextSlide, obj).prependTo(obj);
                $('> #'+$thisSlide, obj).appendTo(obj);

            }
            else {
                // Else this is the back button
                // So put the divs in the correct order so we can create
                // the illusion of flipping
                $('> #'+$thisSlide, obj).prependTo($(obj));
                $('> #'+$nextSlide, obj).insertAfter($('div[id^="image-"]:first', obj));

                // Then append the correct divs to the moving div
                $('> #'+$nextSlide+' > div[class$="-fend"], > #'+$thisSlide+' > div[class$="-fstart"]', obj).appendTo($('.moving-div'));

                // Fix the z-index real quick since we've been moving stuff around 
                zIndexFix();

                // Rotate the moving div holder
                $('.moving-div').addClass('beginMove');

                // A very small timeout so that this function does not interfere with 
                // other functions
                setTimeout(function() {

                    // Вращение!
                    $('.moving-div').addClass('rotateYBackward').css({

                        '-webkit-transition-duration': time/1000+'s',
                        '-moz-transition-duration': time/1000+'s',
                        '-ms-transition-duration': time/1000+'s',
                        '-o-transition-duration': time/1000+'s',
                        'transition-duration': time/1000+'s'

                    });

                }, time/50);

            }

            // Анимация тени!
            shadowAnimate(time);

            // Another timeout, to be run at the end of the animation
            setTimeout(function() {
                // Put the slides back to their default classes and values
                restartSlides();

                if(buttons != true) {
                    $('.moving-div').addClass('hide');
                }

                // Prepend accordingly
                if(prev == true) {
                    $(' > #'+$nextSlide, obj).prependTo($(obj));
                }

                // Fix up the z-index and change the circle
                zIndexFix();
                selectCircle();

                // The animation is now over
                animated = 0;

                // Fade in the content!
                $('div[id^="image-"]:first .content', obj).fadeIn();

            }, time);

        }
}

 

Теперь все, что нам нужно сделать — вызвать определенную реакцию на нажатие кнопки.

 

$('.forward-arrow').click(function() {
    $('.moving-div').removeClass('hide');
    setTimeout(function() {
        animation(false, time);
    }, 1);
});
$('.back-arrow').click(function() {
    $('.moving-div').removeClass('hide');
    setTimeout(function() {
        animation(true, time);
    }, 1);
});

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

 

$('.buttons span[class^="button-"]', obj).click(function() {

    // Remove the hide class from the moving div
    $('.moving-div').removeClass('hide');

    // Get the button ID
    var buttonID = parseFloat($(this).attr('class').split('-')[1]);

    // Get the current iamge ID
    var currentImageID = parseFloat($('> div[id^="image"]:first', obj).attr('id').split('-')[1]);

    // Calculate a faster time
    var reduxTime = time/10;    

    // And set an interval in a variable using the rotateImages function
    var interval = setInterval(rotateImages, reduxTime);

    function rotateImages() {

        // Update the current image everytime the interval is run
        currentImageID = parseFloat($('> div[id^="image"]:first', obj).attr('id').split('-')[1]);

        // If the button number is equal to the current image number
        if(buttonID == currentImageID) {
            // The animation is over, clear in the interval
            clearInterval(interval);
            // Hide moving-div
            $('.moving-div').addClass('hide');
            // Cancel the function!
            return false;
        }
        else {
            // Otherwise keep running the animation
            animation(false, reduxTime, true);
        }               

    }
});

 

И наконец просто нужно проверить  z-index, и установить первое изображение, если пользователь определит его.

 

// Make sure to fix the z-index too!
zIndexFix();
// Oh, and change the start image if the user defines it.
$('.buttons .button-'+o.start, obj).click();

Теперь, когда мы закончили, можно запустить наш плагин.

Подключение

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

<script type="text/javascript">
$(document).ready(function() {

    $('#flipbook').pictureflip({time : 1000, start : 1});
});
</script>

 

                                               Демо                  Скачать исходные файлы  

Автор: Johnny Simpson

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




Комментарии

  1. Алена Данилина
    Thumb up Thumb down -2

    Он в ие не работает. нафиг тогда он нужен

    Макс Ответ:

    Thumb up Thumb down +3

    и в фаирфоксе косячит

  2. Дмитрий
    Thumb up Thumb down 0

    Лучшая программа для 3D эффекта листания страниц: 3D PageFlip Professional. Превосходит FlippingBook PDF publusher по простоте и легкости встраивания видео в публикацию, да и не создает множества файлов в папке (в 2,5 раза меньше, чем у FlippingBook).

    А функционал такой же, хотя и дешевле в 10 раз.

    Вот рабочий пример программы с встроенным видео в публикацию: sadmordovii.ucoz.ru/files1/FlipBook3DMain.swf

    Дешево и сердито!

  3. Андрей
    Thumb up Thumb down 0

    Не работает поправка z-index, поэтому некоторые слайды перелистываются по два-три раза. Слайды вообще листаются с разной скоростью — одни плавно, другие с запаздыванием или опережением.