Слайдер с эффектом перелистывания страниц с помощью CSS3 и jQuery
6 февраля 2013 | Опубликовано в css | 4 Комментариев »
В последнее время на многих сайтах стал достаточно популярным эффект перелистывания. Поэтому достаточно актуальным было бы добиться этого эффекта с помощью jQuery и CSS3. Мы будем создавать блоки с картинками, которые в дальнейшем будут преобразованы в книгу. Также наш слайдер будет иметь кнопки, с помощью которых пользователь сможет видеть, на какой странице он сейчас находится. Страницы слайдера будут представлены в виде изображений в HTML, но каждое из них будет разделено на две страницы с помощью jQuery.
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
Перевод — Дежурка
7 февраля 2013 в 6:28
Он в ие не работает. нафиг тогда он нужен
февраля 11, 2013 at 9:56 дп
и в фаирфоксе косячит
8 февраля 2014 в 20:18
Лучшая программа для 3D эффекта листания страниц: 3D PageFlip Professional. Превосходит FlippingBook PDF publusher по простоте и легкости встраивания видео в публикацию, да и не создает множества файлов в папке (в 2,5 раза меньше, чем у FlippingBook).
А функционал такой же, хотя и дешевле в 10 раз.
Вот рабочий пример программы с встроенным видео в публикацию: sadmordovii.ucoz.ru/files1/FlipBook3DMain.swf
Дешево и сердито!
12 марта 2015 в 19:14
Не работает поправка z-index, поэтому некоторые слайды перелистываются по два-три раза. Слайды вообще листаются с разной скоростью — одни плавно, другие с запаздыванием или опережением.