От автора: данный урок посвящён созданию анимированного эффекта перелистыванию страниц с сайта с помощью плагинов jQuery. Идея состоит в том, чтобы перелистывать содержимое, как книгу, и переходить к страницам посредством появляющегося слева бокового меню.
Мы получили множество писем о том, как с помощью плагина BookBlock, создавать эффекты перелистывания страниц, но уже в полноэкранном режиме. Поэтому было решено создать разметку, применить к ней BookBlock и добавить боковое меню. Мы покажем вам, как применить к своим целям BookBlock и использовать для навигации по содержимому некоторые доступные опции.
Идея состоит в том, чтобы переходить по страницам с помощью стрелок или «перелистывая» их, и заставлять меню появляться по щелчку на кнопку. Боковое меню будет содержать ссылки на различные страницы, например, на оглавление. Таким образом, мы получим с вами эффект перелистывания страниц на нашем сайте.
Мы также применим jScrollPane от Кевина Лака (Kevin Luck) для добавления пользовательской полосы прокрутки содержимого там, где это требуется.
Пожалуйста, обратите внимание: 3D-transforms CSS будут работать только в современных браузерах, поддерживающих эти свойства.
Демоверсия содержит выдержки из уморительной книги «Смешная медицина» А.Д. Крэбтри (“The Funny Side of Physic” by A. D. Crabtree) с сайта Project Gutenberg.
Для получения эффекта перелистывания страниц, мы воспользуемся следующими плагинами jQuery:
BookBlock от Педро Ботельо (Pedro Botelho)
Пользовательский jQuery++ от Битови (Bitovi)
jScrollPane от Кевина Лака (Kevin Luck)
Плагин jQuery Mouse Wheel от Брендона Аарона (Brandon Aaron)
Пользовательский Modernizr
Итак, давайте начнем создание эффекта перелистывания страниц!
Разметка
Давайте сделаем основной контейнер для всех элементов. Внутрь добавим раздел для бокового меню, которому назначим класс “menu-panel”, и обертку для BookBlock’а с классом “bb-custom-wrapper”. BookBlock будет содержать обертку (к которой мы применим плагин) и нужную плагину структуру. Внутрь каждого элемента мы добавим обертку содержимого с разделом, необходимым для функциональности пользовательской прокрутки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<div id="container" class="container"> <div class="menu-panel"> <h3>Table of Contents</h3> <ul id="menu-toc" class="menu-toc"> <li class="menu-toc-current"><a href="#item1">Self-destruction</a></li> <li><a href="#item2">Why we die</a></li> <li><a href="#item3">The honeymoon</a></li> <li><a href="#item4">A drawing joke</a></li> <li><a href="#item5">Commencing practice</a></li> </ul> </div> <div class="bb-custom-wrapper"> <div id="bb-bookblock" class="bb-bookblock"> <div class="bb-item" id="item1"> <div class="content"> <div class="scroller"> <h2>Self-destruction</h2> <p>...</p> </div> </div><!-- /content --> </div><!-- /bb-item --> <div class="bb-item" id="item2"><!-- ... --></div> <div class="bb-item" id="item3"><!-- ... --></div> <div class="bb-item" id="item4"><!-- ... --></div> <div class="bb-item" id="item5"><!-- ... --></div> </div><!-- /bb-bookblock --> <nav> <a id="bb-nav-prev" href="#">←</a> <a id="bb-nav-next" href="#">→</a> </nav> <span id="tblcontents" class="menu-button">Table of Contents</span> </div><!-- /bb-custom-wrapper --> </div><!-- /container --> |
Элементы меню будут указывать на соответствующие страницы BookBlock’а (bb-item). Также добавим навигационные стрелки-указатели и кнопку переключения открытия и закрытия меню.
Давайте перейдем к стилям.
CSS
Заметьте, что здесь мы не станем использовать никаких специальных префиксов, но вы отыщете их в файлах.
Здесь мы не обсуждаем стиль плагина BookBlock (стили можно найти в bookblock.css), вместо этого сосредоточимся на остальных важных для разметки стилях, и пару штук из них модифицируем.
Начнем с импортирования шрифта Lato из веб-шрифтов Google:
1 |
@import url(//fonts.googleapis.com/css?family=Lato:300,400,700); |
Элемент html должен быть высотой в 100%, так как нам необходимо растянуть высоту внутренних элементов до высоты окна:
1 2 3 |
html { height: 100%; } |
Для изменения размера блока применим border-box, что позволит нам определить процентное соотношение высоты и ширины элементов при использовании отступов, и не волноваться о том, что элементы будут слишком большими:
1 2 3 4 5 6 7 8 9 |
*, *:after, *:before { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; padding: 0; margin: 0; } |
(Мы «зверски» сбрасываем отступы полей всех элементов; вам этого делать не нужно, вместо этого можно просто упорядочить соответствующие элементы.)
Давайте определим шрифт основного текста body и установим его высоту на 100%. Помните, что нам нужно определить ее из-за дочерних записей, которые будут абсолютными и тоже высотой в 100%:
1 2 3 4 5 6 7 |
body { font-family: 'Lato', Calibri, Arial, sans-serif; font-weight: 400; font-size: 100%; color: #333; height: 100%; } |
Мы пользуемся Modernizr’ом и добавили к html-элементу класс “no-js”. При активированном JavaScript’е Modernizr заменит этот класс на “js”. Это даст нам возможность назначить элементам определенные свойства CSS, что при выключенном JavaScript’е не требуется. Наша разметка шириной и высотой в 100% имеет смысл, только если у нас активен JS, и тогда нам нужно, чтобы переполнение overflow у body было скрыто hidden:
1 2 3 |
.js body { overflow: hidden; } |
Давайте определим несколько стилей ссылок:
1 2 3 4 5 6 7 8 |
a { color: #555; text-decoration: none; } a:hover { color: #000; } |
Нам требуется, чтобы основной контейнер занимал всю ширину и высоту окна. Боковое меню будет расположено вне его путем установки отрицательного левого значения (его собственной ширины). Идея состоит в том, чтобы анимировать весь контейнер при щелчке для открытия меню. Оно соскользнет вправо, открывая переполненное боковое меню.
Так, давайте установим ширину и высоту основного контейнера на 100% и добавим к контейнеру переход:
1 2 3 4 5 6 7 8 9 10 11 12 |
.container, .bb-custom-wrapper, .bb-bookblock { width: 100%; height: 100%; } .container { position: relative; left: 0px; transition: left 0.3s ease-in-out; } |
При щелчке на кнопку меню мы добавим к контейнеру другой класс, который установит значение left на 240 px (ширину бокового меню):
1 2 3 |
.slideRight { left: 240px; } |
При деактивированном JavaScript’е мы не сможем этого сделать, поэтому давайте добавим вместо этого отступ слева:
1 2 3 |
.no-js .container { padding-left: 240px; } |
Нам нужно, чтобы по умолчанию боковое меню было зафиксировано по левой стороне:
1 2 3 4 5 6 7 8 9 10 |
.menu-panel { background: #f1103a; width: 240px; height: 100%; position: fixed; z-index: 1000; top: 0; left: 0; text-shadow: 0 1px 1px rgba(0,0,0,0.1); } |
При активном JS мы установим position на absolute, а left на -240 px:
1 2 3 4 |
.js .menu-panel { position: absolute; left: -240px; } |
Давайте назначим стили элементам меню:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
.menu-panel h3 { font-size: 1.8em; padding: 20px; font-weight: 300; color: #fff; box-shadow: inset 0 -1px 0 rgba(0,0,0,0.05); } .menu-toc { list-style: none; } .menu-toc li a { display: block; color: #fff; font-size: 1.1em; line-height: 3.5; padding: 0 20px; cursor: pointer; background: #f1103a; border-bottom: 1px solid #dd1338; } .menu-toc li a:hover, .menu-toc li.menu-toc-current a{ background: #dd1338; } |
Навигация будет располагаться абсолютно поверх всего:
1 2 3 4 5 6 |
.bb-custom-wrapper nav { top: 20px; left: 60px; position: absolute; z-index: 1000; } |
Ссылки на стрелки-указатели и кнопку меню тоже будут позиционированы абсолютно, и мы скруглим их, установив border-radius на 50%:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
.bb-custom-wrapper nav span, .menu-button { position: absolute; width: 32px; height: 32px; top: 0; left: 0; background: #f1103a; border-radius: 50%; color: #fff; line-height: 30px; text-align: center; speak: none; font-weight: bold; cursor: pointer; } .bb-custom-wrapper nav span:last-child { left: 40px; } .bb-custom-wrapper nav span:hover, .menu-button:hover { background: #000; } |
Кнопка меню будет расположена в левом верхнем углу, и ее текст мы скроем:
1 2 3 4 5 6 |
.menu-button { z-index: 1000; left: 20px; top: 20px; text-indent: -9000px; } |
Давайте создадим маленькую иконку меню, воспользовавшись псевдоэлементом с двойной тенью блока применительно к верхней и нижней линиям:
1 2 3 4 5 6 7 8 9 10 11 |
.menu-button:after { position: absolute; content: ''; width: 50%; height: 2px; background: #fff; top: 50%; margin-top: -1px; left: 25%; box-shadow: 0 -4px #fff, 0 4px #fff; } |
В случае, когда JS не активирован, нам эти элементы окажутся не нужны, поэтому просто спрячем их:
1 2 3 4 |
.no-js .bb-custom-wrapper nav span, .no-js .menu-button { display: none; } |
Перейдем к внутренним частям элементов BookBlock’а. Раздел контента должен быть absolute, а также установим переполнение overflow на hidden. Это важно, потому что тут нам требуется применить свою модифицированную пользовательскую прокрутку, и сделаем мы это, только когда страница перевернута. Если не установить overflow на hidden, то мы увидели бы переполнение содержимого. И снова, это имеет смысл только при активном JS, поэтому добавим класс “js”:
1 2 3 4 5 6 7 8 |
.js .content { position: absolute; top: 60px; left: 0; bottom: 50px; width: 100%; overflow: hidden; } |
Div scroller будет разрастаться вместе с контентом, поэтому давайте добавим сюда несколько отступов:
1 2 3 |
.scroller { padding: 10px 5% 10px 5%; } |
Применение процентного соотношения в качестве бокового отступа заставит разметку гибко подстраиваться к размеру экрана.
Давайте скроем острые края при прокрутке, добавив псевдоэлементы с градиентом от белого цвета до прозрачного к верху и низу div’а content:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
.js .content:before, .js .content:after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 20px; z-index: 100; pointer-events: none; background: linear-gradient( to bottom, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100% ); } .js .content:after { top: auto; bottom: 0; background: linear-gradient( to top, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100% ); } |
Так текст будет смотреться слегка выцветшим. Добавим стили к элементам текста:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
.content h2 { font-weight: 300; font-size: 4em; padding: 0 0 10px; color: #333; margin: 0 1% 40px; text-align: left; box-shadow: 0 10px 0 rgba(0,0,0,0.02); text-shadow: 0 0 2px #fff; } .no-js .content h2 { padding: 40px 1% 20px; } .content p { font-size: 1.2em; line-height: 1.6; font-weight: 300; padding: 5px 8%; text-align: justify; } |
Наконец давайте добавим медиазапросы. При деактивированном JavaScript’е нам больше уже не требуется показывать меню 800 px. Простой пример того, как можно при определенных условиях контролировать эти элементы.
Последний медиазапрос немного изменит размер шрифта под меньшие устройства. В таких случаях очень облегчает задачу применение em’ов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@media screen and (max-width: 800px){ .no-js .menu-panel { display: none; } .no-js .container { padding: 0; } } @media screen and (max-width: 400px){ .menu-panel, .content { font-size: 75%; } } |
Вот и все стили!
JavaScript
Начнем с кэширования некоторых элементов и инициализации плагина BookBlock. Нам нужно кое-что установить после перелистывания каждой страницы, в основном указатель текущего элемента и поведение jScrollPane’а. Это определено в обратном вызове onEndFlip, передаваемом BookBlock’у.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
var $container = $( '#container' ), // элемент, к которому мы применим плагин BookBlock $bookBlock = $( '#bb-bookblock' ), // элементы BookBlock (bb-item) $items = $bookBlock.children(), // указатель текущего элемента current = 0, // инициализируйте BookBlock bb = $( '#bb-bookblock' ).bookblock( { speed : 800, perspective : 2000, shadowSides : 0.8, shadowFlip : 0.4, // после каждого перелистывания... onEndFlip : function(old, page, isLimit) { // обновите текущее значение current = page; // обновите выбранный элемент оглавления (TOC) updateTOC(); // покажите и/или скройте стрелки-указатели навигации updateNavigation( isLimit ); // инициализируйте jScrollPane на div контента для нового элемента setJSP( 'init' ); // ликвидируйте jScrollPane на div контента для старого элемента setJSP( 'destroy', old ); } } ), // стрелки-указатели навигации $navNext = $( '#bb-nav-next' ), $navPrev = $( '#bb-nav-prev' ).hide(), // оглавление элементов $menuItems = $container.find( 'ul.menu-toc > li' ), // кнопка для открывания TOC $tblcontents = $( '#tblcontents' ), transEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd', 'transition': 'transitionend' }, // названия события перехода transEndEventName = transEndEventNames[Modernizr.prefixed('transition')], // проверьте, поддерживаются ли переходы supportTransitions = Modernizr.csstransitions; |
Сначала привяжем события к некоторым ранее инициализированным элементам. Кроме того, нам следует инициализировать jScrollPane для первого (текущего) элемента.
1 2 3 4 5 6 7 |
function init() { // инициализируйте jScrollPane на div контента первого элемента setJSP( 'init' ); initEvents(); } |
Так как нам со временем придется инициализировать, реинициализировать и ликвидировать jScrollPane, давайте определим для этого функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function setJSP( action, idx ) { var idx = idx === undefined ? current : idx, $content = $items.eq( idx ).children( 'div.content' ), apiJSP = $content.data( 'jsp' ); if( action === 'init' &amp;&amp; apiJSP === undefined ) { $content.jScrollPane({verticalGutter : 0, hideFocus : true }); } else if( action === 'reinit' &amp;&amp; apiJSP !== undefined ) { apiJSP.reinitialise(); } else if( action === 'destroy' &amp;&amp; apiJSP !== undefined ) { apiJSP.destroy(); } } |
Нам понадобится привязать несколько событий:
Мы вызовем методы BookBlock’а next() и prev() при щелчке на стрелки навигации или перелистывании страницы
TOC будет показываться/скрываться при щелчке на кнопку $tblcontents (меню)
Мы вызовем метод BookBlock’а jump() при щелчке на элемент
jScrollPane будет инициализироваться при изменении размера окна
Итак, вот мы где:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
function initEvents() { // добавьте события навигации $navNext.on( 'click', function() { bb.next(); return false; } ); $navPrev.on( 'click', function() { bb.prev(); return false; } ); // добавьте события перелистывания $items.on( { 'swipeleft' : function( event ) { if( $container.data( 'opened' ) ) { return false; } bb.next(); return false; }, 'swiperight' : function( event ) { if( $container.data( 'opened' ) ) { return false; } bb.prev(); return false; } } ); // покажите TOC $tblcontents.on( 'click', toggleTOC ); // щелкните элемент меню $menuItems.on( 'click', function() { var $el = $( this ), idx = $el.index(), jump = function() { bb.jump( idx + 1 ); }; current !== idx ? closeTOC( jump ) : closeTOC(); return false; } ); // реинициализируйте jScrollPane при изменении размера окна $( window ).on( 'debouncedresize', function() { // реинициализируйте jScrollPane на div контента setJSP( 'reinit' ); } ); } |
Видимость навигационных стрелок-указателей будет зависеть от текущей страницы. Находясь на первой странице, мы увидим только следующую стрелку, а будучи на последней – только предыдущую:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function updateNavigation( isLastPage ) { if( current === 0 ) { $navNext.show(); $navPrev.hide(); } else if( isLastPage ) { $navNext.hide(); $navPrev.show(); } else { $navNext.show(); $navPrev.show(); } } |
Открывая текущий контент, нужно скрыть навигационные стрелки-указатели, а снова показываем мы их лишь после закрытия текущщего контента.
Анимировать боковое меню мы будем с помощью перехода CSS. Если поддержка переходов отсутствует, то следует применить простую альтернативу show/hide:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
function toggleTOC() { var opened = $container.data( 'opened' ); opened ? closeTOC() : openTOC(); } function openTOC() { $navNext.hide(); $navPrev.hide(); $container.addClass( 'slideRight' ).data( 'opened', true ); } function closeTOC( callback ) { $navNext.show(); $navPrev.show(); $container.removeClass( 'slideRight' ).data( 'opened', false ); if( callback ) { if( supportTransitions ) { $container.on( transEndEventName, function() { $( this ).off( transEndEventName ); callback.call(); } ); } else { callback.call(); } } } |
Уффф! 🙂 Вот так мы и создали с вами на сайте, эффект перелистывания страниц! Надеюсь, вам понравился и оказался полезен этот учебник!
Автор: Mary Lou
Источник: //tympanus.net/
Редакция: Команда webformyself.
Комментарии (2)