Уроки Удобный просмотр новостей
7 февраля 2016
1136
просмотр новостей, чтение онлайн-книг, bookblock

Удобный просмотр новостей

Сложность Рубрика JQuery Браузеры
Демонстрация » Скачать »

Привет! Сегодня я покажу вам как использовать плагин BookBlock в полноэкранном режиме, к примеру реализуем удобный просмотр новостей. Я решил создать полноэкранный макет, применить к нему BookBlock и добавить меню в боковую панель. Также я покажу вам, как настроить BookBlock и использовать его опции для навигации по содержимому страницы.
Идея заключается в том, чтобы перемещаться, к примеру, по новостям с помощью стрелок или проводя пальцем по странице (если вы просматриваете новости с смартфона/планшета), также открывать/скрывать меню при нажатии на кнопку меню. Боковое меню будет содержать ссылки на разные страницы/новости. Мы будем также использовать плагин JScrollPane, чтобы добавить прокрутку для содержания в случае необходимости.

 

Будут использоваться следующие библиотеки и плагины JQuery:
1. BookBlock
2. JQuery
3. JScrollPane
4. jQuery Mouse Wheel
5. Modernizr
И так, давайте начнем!

 

Создаем общий контейнер для всех наших элементов. Внутри мы добавим блок для бокового меню, которому дадим класс "menu-panel", и блок-оболочку для BookBlock с классом «bb-custom-wrapper". В последнем блоке у нас будет структура, которую требует сам плагин BookBlock. Внутри каждого элемента, мы добавим блок-обертку, чтобы реализовать функционал прокрутки:

 

HTML

<div id="container" class="container">	
	<div class="menu-panel">
		<h3>Меню</h3>
		<ul id="menu-toc" class="menu-toc">
			<li class="menu-toc-current"><a href="#item1">Новость 1</a></li>
			<li><a href="#item2">Новость 2</a></li>
			<li><a href="#item3">Новость 3</a></li>
			<li><a href="#item4">Новость 4</a></li>
			<li><a href="#item5">Новость 5</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>Новость 1</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">Меню</span>
	</div><!-- /bb-custom-wrapper -->
</div><!-- /container -->

 

Пункты меню будут указаны на соответствующих страницах BookBlock (bb-item). Также добавим навигационные стрелки и кнопку для переключения открытия и закрытия меню.

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

 

CSS

Не будем обсуждать стили плагина BookBlock (вы можете их найти в bookblock.css), вместо этого, мы сосредоточимся на всех других стилях, которые важны для макета и настройки некоторых вещей.
Давайте начнем с импорта шрифта Lato, одного с веб-шрифтов Google:

 

@import url(http://fonts.googleapis.com/css?family=Lato:300,400,700);

 

HTML блок должен иметь высоту 100%, так как нам нужно будет установить абсолютную высоту внутренних элементов и расширить их к высоте окна:

 

html { 
	height: 100%; 
}

 

Применим свойство box-sizing для изменения алгоритма расчета ширины и высоты элемента.

Согласно спецификации CSS ширина блока складывается из ширины контента (width), значений отступов (margin), полей (padding) и границ (border). Аналогично обстоит и с высотой блока. Свойство box-sizing позволяет изменить этот алгоритм, чтобы свойства width и height задавали размеры не контента, а размеры блока. Значение border-box означает, что width и height включают в себя значения полей и границ, но не отступов (margin).

 

*,
*:after,
*:before {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;
	padding: 0;
	margin: 0;
}

 

Давайте определим шрифт для body и установим высоту 100%. Помните, нам нужно это сделать из-за дочерних элементов:

 

body {
	font-family: 'Lato', Calibri, Arial, sans-serif;
	font-weight: 400;
	font-size: 100%;
	color: #333;
	height: 100%;
}

 

Мы используем Modernizr и добавим класс "no-js" к HTML элементам. Когда JavaScript включен в браузере, Modernizr заменит этот класс с "JS". Это позволит нам задать определенные свойства CSS к элементам, которые нам не нужны, если JavaScript отключен. 100% ширина и высота макета имеют смысл только если JS включен. В этом случае нам понадобится свойство overflow:

 

.js body {
	overflow: hidden;
}

 

Стили для ссылок:

 

a {
	color: #555;
	text-decoration: none;
}

a:hover {
	color: #000;
}

 

Мы хотим, чтобы главный контейнер, занял всю ширину и высоту окна. Боковое меню позиционируем вне этого блока, установив отрицательное значение left. Идея заключается в том, что мы оживим весь контейнер при нажатии на кнопку открытия меню. Главный блок будет скользить вправо раскрывая боковое меню.
Устанавливаем ширину и высоту главного блока 100% и добавляем свойство transition к контейнеру для красоты:

 

.container,
.bb-custom-wrapper,
.bb-bookblock {
	width: 100%;
	height: 100%;
}

.container {
	position: relative;
	left: 0px;
	transition: left 0.3s ease-in-out;
}

 

При нажатии на кнопку меню, добавим еще один класс к контейнеру, который будет устанавливать значение left в 240 пикселей (это ширина бокового меню):

 

.slideRight {
	left: 240px;
}

 

При выключенном JS мы не сможем добавить класс slideRight, поэтому в этом случае сделаем это вручную:

 

.no-js .container {
	padding-left: 240px;
}

 

По дефолту, закрепим боковое меню слева:

 

.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 и left:

 

.js .menu-panel {
	position: absolute;
	left: -240px;
}

 

Стили элементов меню:

 

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

 

Блок навигации должен абсолютно позиционироваться сверху:

 

.bb-custom-wrapper nav {
	top: 20px;
	left: 60px;
	position: absolute;
	z-index: 1000;
}

 

Стрелки навигации и кнопка меню, должны также быть с абсолютным позиционированием, плюс сделаем их круглыми при помощи border-radius:

 

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

 

Кнопка меню будет позиционироваться в верхнем левом углу, и мы заодно спрячем его текст:

 

.menu-button {
	z-index: 1000;
	left: 20px;
	top: 20px;
	text-indent: -9000px;
}

 

В случае если JS не включен нам не нужны эти элементы, так что просто скрываем их:

 

.no-js .bb-custom-wrapper nav span,
.no-js .menu-button {
	display: none;
}

 

Давайте перейдем к внутренностям элементов BookBlock. У них позиционирование должно быть абсолютным и мы установим также свойство overflow в hidden. Это важно, поскольку мы хотим применить здесь наш кастомный скролл, делать это мы будем только когда была применена прокрутка на странице. Если мы не будем устанавливать overflow в hidden, то будет видно все содержание, которое переполнит блок. Опять же ж, это имеет смысл только когда включен JS:

 

.js .content {
	position: absolute;
	top: 60px;
	left: 0;
	bottom: 50px;
	width: 100%;
	overflow: hidden;
}

 

Отступы для блока самого скрола:

 

.scroller {
	padding: 10px 5% 10px 5%;
}

 

Сделаем градиент для текста сверху и снизу дабы скрыть острые края букв:

 

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

 

Стили для текстовых элементов:

 

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

 

Наконец, давайте добавим некоторые media запросы. Когда JavaScript выключен, нам не нужно к примеру чтобы меню было больше 800 пикселей. Это один пример того, как мы можем контролировать эти элементы при определенных условиях.

 

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

 

JQuery

Инициализируем скрипты и задаем некоторые настройки:

 

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;

			// обновление выбранного элемента в боковом меню
			updateTOC();

			// показать и/или скрыть стрелки навигации
			updateNavigation( isLimit );

			// инициализация плагина jScrollPane для блока контента нового элемента
			setJSP( 'init' );

			// удалям jScrollPane для блока контента старого элемента
			setJSP( 'destroy', old );

		}
	} ),
	// стрелки навигации
	$navNext = $( '#bb-nav-next' ),
	$navPrev = $( '#bb-nav-prev' ).hide(),
    
    //элементы меню
	$menuItems = $container.find( 'ul.menu-toc > li' ),

	$tblcontents = $( '#tblcontents' ),

	transEndEventNames = {
		'WebkitTransition': 'webkitTransitionEnd',
		'MozTransition': 'transitionend',
		'OTransition': 'oTransitionEnd',
		'msTransition': 'MSTransitionEnd',
		'transition': 'transitionend'
	},

	transEndEventName = transEndEventNames[Modernizr.prefixed('transition')],
	supportTransitions = Modernizr.csstransitions;

 

Во-первых, давайте связывать события некоторых из элементов, инициализированных ранее. Кроме того, мы должны инициализировать JScrollPane для первого (текущего) пункта.

 

function init() {

	setJSP( 'init' );
	initEvents();

}

 

В конечном итоге необходимо инициализировать, пере инициализировать и уничтожить JScrollPane, давайте определим функцию для этого:

 

function setJSP( action, idx ) {
		
	var idx = idx === undefined ? current : idx,
		$content = $items.eq( idx ).children( 'div.content' ),
		apiJSP = $content.data( 'jsp' );
	
	if( action === 'init' && apiJSP === undefined ) {
		$content.jScrollPane({verticalGutter : 0, hideFocus : true });
	}
	else if( action === 'reinit' && apiJSP !== undefined ) {
		apiJSP.reinitialise();
	}
	else if( action === 'destroy' && apiJSP !== undefined ) {
		apiJSP.destroy();
	}

}

 

Нам нужно будет привязать несколько событий:

1. Мы будем вызывать методы next() и prev плагина BookBlock при нажатии стрелки навигации или при проведении мышкой (или пальцем) по странице.

2. Меню должно скрываться/показываться при клике по кнопке меню ($tblcontents).

3. Мы будем вызывать метод jump() плагина BookBlock при нажатии на пункт меню.

4. JScrollPane будет инициализирован при изменении размеров окна.

Приступим:

 

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

	$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;
		
	} );

	$( window ).on( 'debouncedresize', function() {
		setJSP( 'reinit' );
	} );

}

 

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

 

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:

 

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();
		}
	}

}

 

Ну вот, вроде и все) Надеюсь урок был вам полезен. Добавляйтесь к нам в соц. сети дабы быть в курсе новых событий. Скоро увидимся! 





Алексей Копча