Вращающий слайдер на jQuery и CSS3

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

В слайдере используются плагины jQuery 2D Transformation для вращения изображений и Mousewheel для управления мышью.

demosourse

 

Разметка HTML

Все элементы слайдера содержатся в контейнере с классом “rm_wrapper”:

<div class="rm_wrapper">
 ...
</div>

Внутри содержится контейнер для списка элементов слайдера, маски и углы, заголовок и скрытые элементы div, которые содержат наборы изображений:

	<div id="rm_container" class="rm_container">
		<ul>
			<li data-images="rm_container_1" data-rotation="-15"><img src="images/1.jpg"/></li>
			<li data-images="rm_container_2" data-rotation="-5"><img src="images/2.jpg"/></li>
			<li data-images="rm_container_3" data-rotation="5"><img src="images/3.jpg"/></li>
			<li data-images="rm_container_4" data-rotation="15"><img src="images/4.jpg"/></li>
		</ul>
		<div id="rm_mask_left" class="rm_mask_left"></div>
		<div id="rm_mask_right" class="rm_mask_right"></div>
		<div id="rm_corner_left" class="rm_corner_left"></div>
		<div id="rm_corner_right" class="rm_corner_right"></div>
		<h2>Взрыв моды 2012</h2>
		<div style="display:none;">
			<div id="rm_container_1">
				<img src="images/1.jpg"/>
				<img src="images/5.jpg"/>
				<img src="images/6.jpg"/>
				<img src="images/7.jpg"/>
			</div>
			<div id="rm_container_2">
				<img src="images/2.jpg"/>
				<img src="images/8.jpg"/>
				<img src="images/9.jpg"/>
				<img src="images/10.jpg"/>
			</div>
			<div id="rm_container_3">
				<img src="images/3.jpg"/>
				<img src="images/11.jpg"/>
				<img src="images/12.jpg"/>
				<img src="images/13.jpg"/>
			</div>
			<div id="rm_container_4">
				<img src="images/4.jpg"/>
				<img src="images/14.jpg"/>
				<img src="images/15.jpg"/>
				<img src="images/16.jpg"/>
			</div>
		</div>
	</div>

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

Элементы div масок и углов позиционируются абсолютно поверх слайдера и немного повернуты, чтобы прикрывать некоторые области. Так как мы используем одинаковый цвет фона для данных элементов и всей страницы, то создается иллюзия,  что изображения имеют определённую форму.

Затем следуют элементы навигации и управления автопроигрыванием:

	<div class="rm_nav">
		<a id="rm_next" href="#" class="rm_next"></a>
		<a id="rm_prev" href="#" class="rm_prev"></a>
	</div>
	<div class="rm_controls">
		<a id="rm_play" href="#" class="rm_play">Запустить</a>
		<a id="rm_pause" href="#" class="rm_pause">Остановить</a>
	</div>

 

CSS

Сначала осуществляется сброс и определяются свойства для страницы. (Если вы захотите поменять цвет фона страницы, то нужно будет изменять цвета фона и рамок некоторых элементов слайдера):

@import url('reset.css');
body{
	background:#f0f0f0;
	color:#000;
	font-family: 'PT Sans Narrow', Arial, sans-serif;
	font-size:16px;
}
a{
	color:#000;
	text-decoration:none;
}
h1{
	padding:10px;
	margin:20px;
	font-size:40px;
	text-transform:uppercase;
	text-shadow:0px 0px 1px #fff;
	color:#333;
	background:transparent url(../images/line.png) repeat-x bottom left;
}

Основной контейнер имеет следующий стиль:

.rm_wrapper{
	width:1160px;
	margin:0 auto;
	position:relative;
}

Контейнер для слайдера скрывает всё выступающее за его пределы:

.rm_container{
	width:1050px;
	overflow:hidden;
	position:relative;
	height:530px;
	margin:0 auto;
}

Заголовок имеет следующий стиль:

.rm_container h2{
	background:transparent url(../images/lines.png) repeat top left;
	padding:10px 30px;
	position:absolute;
	bottom:170px;
	right:0px;
	color:#000;
	font-size:36px;
	text-transform:uppercase;
	text-shadow:1px 0px 1px #fff;
}

Ширина неупорядоченно списка будет больше ширины контейнера, так как все элементы списка будут плавающими со смещением влево, чтобы располагаться рядом друг с другом:

.rm_container ul{
	width:1170px;
}

Задавая отрицательное левое смещение и толстую рамку для элементов списка, мы добиваемся перекрытия изображений и обрезки правой части для создания ассиметричной формы при последующем вращении. Цвет рамки должен быть таким же, как и цвет фона страницы:

.rm_container ul li{
	float:left;
	margin-left:-80px;
	position:relative;
	overflow:hidden;
	width:310px;
	height:465px;
	border:30px solid #f0f0f0;
	border-width:50px 30px 0px 30px;
	background-color:#f0f0f0;
}

Изображения позиционируются абсолютно:

.rm_container ul li img{
	position:absolute;
	top:0px;
	left:0px;
}

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

.rm_mask_right, .rm_mask_left{
	position: absolute;
	height: 110px;
	background: #f0f0f0;
	width: 530px;
	bottom: -30px;
	left: 0px;
	-moz-transform:rotate(-3deg);
	-webkit-transform:rotate(-3deg);
	transform:rotate(-3deg);
}
.rm_mask_right{
	left:auto;
	right:0px;
	-moz-transform:rotate(3deg);
	-webkit-transform:rotate(3deg);
	transform:rotate(3deg);
}
.rm_corner_right, .rm_corner_left{
	background: #f0f0f0;
	position:absolute;
	width:200px;
	height:100px;
	bottom:0px;
	left:-65px;
	-moz-transform:rotate(45deg);
	-webkit-transform:rotate(45deg);
	transform:rotate(45deg);
}
.rm_corner_right{
	left:auto;
	right:-65px;
	-moz-transform:rotate(-45deg);
	-webkit-transform:rotate(-45deg);
	transform:rotate(-45deg);
}

Элементы навигации размещаются справа и слева от основного контейнера:

.rm_nav a{
	position:absolute;
	top:200px;
	width:38px;
	height:87px;
	cursor:pointer;
	opacity:0.7;
}
.rm_nav a:hover{
	opacity:1.0;
}
.rm_nav a.rm_next{
	background:transparent url(../images/next.png) no-repeat top left;
	right:0px;
}
.rm_nav a.rm_prev{
	background:transparent url(../images/prev.png) no-repeat top left;
	left:0px;
}

Элементы управления автопроигрыванием размещаются слева вверху основного контейнера:

.rm_controls{
	position:absolute;
	top:0px;
	left:0px;
	height:20px;
}
.rm_controls a{
	cursor:pointer;
	opacity:0.7;
	padding-left:24px;
	font-size:16px;
	text-transform:uppercase;
	height:20px;
	float:left;
	line-height:20px;
}
.rm_controls a:hover{
	opacity:1.0;
}
.rm_controls a.rm_play{
	display:none;
	background:transparent url(../images/play.png) no-repeat center left;
}
.rm_controls a.rm_pause{
	background:transparent url(../images/pause.png) no-repeat center left;
}

 

JavaScript

Идея функционирования слайдера заключается в добавлении следующего изображения над текущим с небольшим изменением угла поворота. Затем происходит анимация вращения и появляется новое изображение.

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

		//Наши 4 пункта
	var $listItems 		= $('#rm_container > ul > li'),
		totalItems		= $listItems.length,
		
		//Управление
		$rm_next		= $('#rm_next'),
		$rm_prev		= $('#rm_prev'),
		$rm_play		= $('#rm_play'),
		$rm_pause		= $('#rm_pause'),
		
		//Маски и углы для слайдера
		$rm_mask_left	= $('#rm_mask_left'),
		$rm_mask_right	= $('#rm_mask_right'),
		$rm_corner_left	= $('#rm_corner_left'),
		$rm_corner_right= $('#rm_corner_right'),
		
		//Проверка версии браузера <= IE8
		ieLte8			= ($.browser.msie && parseInt($.browser.version) <= 8),

Затем мы определяем основную функцию:

RotateImageMenu	= (function() {
	...
})();
		
RotateImageMenu.init();

И создаем ее содержание:

	//Разница между анимациями пунктов
var	timeDiff			= 300,
	//Время между анимациями для слайдшоу
	slideshowTime		= 3000,
	slideshowInterval,	
	//Флаг вращения изображения
	isRotating			= false,
	//Счетчик изображений в итерации слайдшоу
	completed			= 0,
	/*
	Все изображения имеют ширину 310 px и высоту 465 px.
	Данные параметры надо вычислять автоматически,
	если нужно использовать изображения разных размеров.
	
	Мы устанавливаем вращение оригинала вокруг центра
	с координатами x = ширина/2 и y = высота*2
	*/
	origin				= ['155px', '930px'],
	init				= function() {
		configure();
		initEventsHandler();
		startSlideshow();
	},
	//Инициализация некоторых событий
	initEventsHandler	= function() {
		/*
		Стрелки "следующий" и "предыдущий":
		останавливаем слайдшоу, если оно активно
		и вращаем каждое изображение.
		1 	поворот вправо,
		-1 	поворот влево
		*/
		$rm_next.bind('click', function(e) {
			stopSlideshow();
			rotateImages(1);
			return false;
		});
		$rm_prev.bind('click', function(e) {
			stopSlideshow();
			rotateImages(-1);
			return false;
		});
		/*
		Остановка и запуск слайдшоу
		*/
		$rm_play.bind('click', function(e) {
			startSlideshow();
			return false;
		});
		$rm_pause.bind('click', function(e) {
			stopSlideshow();
			return false;
		});
		/*
		Добавляем события для мыши и кнопок влево/вправо
		*/
		$(document).bind('mousewheel', function(e, delta) {
			if(delta > 0) {
				stopSlideshow();
				rotateImages(0);
			}	
			else {
				stopSlideshow();
				rotateImages(1);
			}	
			return false;
		}).keydown(function(e){
			switch(e.which){
				case 37:
					stopSlideshow();
					rotateImages(0);
					break;
				case 39:
					stopSlideshow();
					rotateImages(1);
					break;
			}
		});
	},
	/*
	Вращаем каждое изображение.
	Устанавливаем задержку между анимациями пунктов.
	*/
	rotateImages		= function(dir) {
		//Если анимация в процессе выполнения.
		if(isRotating) return false;
		
		isRotating = true;
		
		$listItems.each(function(i) {
			var $item 				= $(this),
				/*
				Вычисление задержки.
				Если вращение выполняется вправо, 
				то первый пункт для вращения будет анимироваться первым,
				иначе - последним.
				*/
				interval			= (dir === 1) ? i * timeDiff : (totalItems - 1 - i) * timeDiff;
			
			setTimeout(function() {
					//Изображения, связанные с данным пунтком
				var	$otherImages		= $('#' + $item.data('images')).children('img'),
					totalOtherImages	= $otherImages.length;
					
					//Текущее изображение
					$img				= $item.children('img:last'),
					//Получаем данные current
					current				= $item.data('current');
					//Проверяем выход за пределы списка
					if(current > totalOtherImages - 1)
						current = 0;
					else if(current < 0)
						current = totalOtherImages - 1;
					
					//Следующее изображение для вывода и его начальное вращение (зависит от направления)
					var otherRotation	= (dir === 1) ? '-30deg' : '30deg',
						$other			= $otherImages.eq(current).clone();
						
					//Для IE <= 8 вращений не будет, но будет затухание ... 
					//Лучше, чем ничего :)	
					if(!ieLte8)
						$other.css({
							rotate	: otherRotation,
							origin	: origin
						});
					
					(dir === 1) ? ++current : --current;
					
					//Вставляем следующее изображение для <li>
					$item.data('current', current).prepend($other);
					
					//Окончательное вращение для текущего изображения
					var rotateTo		= (dir === 1) ? '80deg' : '-80deg';
					
					if(!ieLte8) {
						$img.animate({
							rotate	: rotateTo
						}, 1200, function(){
							$(this).remove();
							++completed;
							if(completed === 4) {
								completed = 0;
								isRotating = false;
							}
						});
						$other.animate({
							rotate	: '0deg'
						}, 600);
					}
					else {
						$img.fadeOut(1200, function(){
							$(this).remove();
							++completed;
							if(completed === 4) {
								completed = 0;
								isRotating = false;
							}
						});
					}
					
			}, interval );	
		});
		
	},
	//Устанавливаем начальное вращение
	configure			= function() {
		if($.browser.msie && !ieLte8)
			rotateMaskCorners();
		else if(ieLte8)
			hideMaskCorners();
			
		$listItems.each(function(i) {
			//Начальное значение current равно 1, 
			//так как мы уже показали первое изображение
			var $item = $(this).data('current', 1);
			
			if(!ieLte8)
			$item.transform({rotate: $item.data('rotation') + 'deg'})
				 .find('img')
				 .transform({origin: origin});
		});
	},
	//Вращаем маски и углы
	rotateMaskCorners	= function() {
		$rm_mask_left.transform({rotate: '-3deg'});
		$rm_mask_right.transform({rotate: '3deg'});
		$rm_corner_left.transform({rotate: '45deg'});
		$rm_corner_right.transform({rotate: '-45deg'});
	},
	//Скрываем маски и углы
	hideMaskCorners		= function() {
		$rm_mask_left.hide();
		$rm_mask_right.hide();
		$rm_corner_left.hide();
		$rm_corner_right.hide();
	},
	startSlideshow		= function() {
		clearInterval(slideshowInterval);
		rotateImages(1);
		slideshowInterval	= setInterval(function() {
			rotateImages(1);
		}, slideshowTime);
		//Выводим кнопку паузы и скрываем кнопку запуска
		$rm_play.hide();
		$rm_pause.show();
	},
	stopSlideshow		= function() {
		clearInterval(slideshowInterval);
		//Выводим кнопку запуска и скрываем кнопку паузы
		$rm_pause.hide();
		$rm_play.show();
	};

return {init : init};

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

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: tympanus.net/codrops/2011/04/28/rotating-image-slider/
Перевел: Сергей Фастунов
Урок создан: 13 Августа 2011
Просмотров: 41606
Правила перепечатки


5 последних уроков рубрики "jQuery"

или авторизуйтесь, чтобы добавлять комментарии, оценивать уроки и сохранять их в личном кабинете
  • 13 Августа 2011 10:59
    MopuC
    Chrome 13, картинок в примере нет. Или я один такой?
    • 13 Августа 2011 11:46
      Faraonic
      да действительно прав - вы один такой))
  • 13 Августа 2011 14:49
    alexsave
    то же самое, картинок нет Chrome 13.0.7 (
    • 14 Августа 2011 07:56
      Faraonic
      Да вот любуйтесь) http://bit.ly/pvbub0
      • 16 Августа 2011 07:09
        alexsave
        У вас не установлен плагин AdBlock для GoogleChrome, если его отключить то галерея начинает работать.
  • 13 Августа 2011 15:36
    Bandyy
    Думаю что задаю странный вопрос но сталкнулся с проблемой: Сайт перестал захадить на главную страничку без www. www.имя.ру заходит имя.ру не заходит Хелп плиз :)
    • 14 Августа 2011 09:55
      mrjohn
      Либо правьте NS записи в конфиге сайта. Либо сделайте редирект в .htaccess с имя.ру на www.имя.ру А вообще, чудес не бывает. Что-то делали значит))
    • 19 Августа 2011 13:37
      rubyx
      если используешь cPanel то ещё проще, там и с "ввв" и без ввв и оба можешь отметить не заглядывая в htaccess файл...
  • 14 Августа 2011 09:52
    mrjohn
    Не работает в Google Chrome 13.0.782.112
  • 16 Августа 2011 12:26
    IKLO
    Работает в Chrome 13, только очень уж края у фото не качественные.
  • 30 Августа 2011 13:43
    xaweleon
    не проходит валидность. there is no attribute "data-rotation" there is no attribute "data-images" как быть?
  • 10 Ноября 2011 09:33
    targetorsk
    А как подложить ссылки под картинки ? Как задать массив ссылок на картинки (или простенький sql запрос по таблице со списком ссылок на картинки) а не прописывать все руками в контейнере списка?
    • 19 Апреля 2013 19:15
      BISE
      targetorsk, у меня тот же вопрос - получилось ли у кого-то установить ссылки для картинок? Или для этого слайдера ссылки вставить невозможно? Все варианты перепробовал, не работают ссылки и все!
  • 27 Мая 2013 08:49
    darkskai
    очень красиво но на foxe края картинок видны и так дешевенько получается да и скрол не работает во всех бразерах
^ Наверх ^