Простой слайдер для нескольких пунктов

В данном уроке мы сделаем простой слайдер для пунктов списка на основе анимаций CSS и jQuery. Идея для урока инспирирована слайдером продукции Aplle, где несколько товаров выскальзывают с использованием анимации. Мы трансформируем данную концепцию для онлайн магазина, чтобы представлять товары в разных категориях. Категории с небольшим количеством товаров отлично подходят к данному слайдеру. Конечно, для большого количества товаров такое решение далеко от оптимума, но для магазинов с небольшим ассортиментом слайдер станет отличным инструментом.

 

Разметка

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

				<div id="mi-slider" class="mi-slider">
					<ul>
						<li><a href="#"><img src="/images/1.jpg" alt="img01"><h4>Ботинки</h4></a></li>
						<li><a href="#"><img src="/images/2.jpg" alt="img02"><h4>Классика</h4></a></li>
						<li><a href="#"><img src="/images/3.jpg" alt="img03"><h4>Мокасины</h4></a></li>
						<li><a href="#"><img src="/images/4.jpg" alt="img04"><h4>Кроссовки</h4></a></li>
					</ul>
					<ul>
						<li><a href="#"><img src="/images/5.jpg" alt="img05"><h4>Ремни</h4></a></li>
						<li><a href="#"><img src="/images/6.jpg" alt="img06"><h4>Шляпы и кепи</h4></a></li>
						<li><a href="#"><img src="/images/7.jpg" alt="img07"><h4>Очки</h4></a></li>
						<li><a href="#"><img src="/images/8.jpg" alt="img08"><h4>Шарфы</h4></a></li>
					</ul>
					<ul>
						<li><a href="#"><img src="/images/9.jpg" alt="img09"><h4>Свобода</h4></a></li>
						<li><a href="#"><img src="/images/10.jpg" alt="img10"><h4>Роскошь</h4></a></li>
						<li><a href="#"><img src="/images/11.jpg" alt="img11"><h4>Спорт</h4></a></li>
					</ul>
					<ul>
						<li><a href="#"><img src="/images/12.jpg" alt="img12"><h4>Чемоданы</h4></a></li>
						<li><a href="#"><img src="/images/13.jpg" alt="img13"><h4>Дорожные сумки</h4></a></li>
						<li><a href="#"><img src="/images/14.jpg" alt="img14"><h4>Для ноутбуков</h4></a></li>
						<li><a href="#"><img src="/images/15.jpg" alt="img15"><h4>Портфели</h4></a></li>
					</ul>
					<nav>
						<a href="#">Обувь</a>
						<a href="#">Аксессуары</a>
						<a href="#">Часы</a>
						<a href="#">Сумки</a>
					</nav>
				</div>

 

CSS

Примечание: префиксы производителей браузеров опущены для большей наглядности кода.

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

Сначала определим стили для контейнера, который будет иметь класс mi-slider. У него будет предустановлена высота, которая требуется для установки правильного положения элементов ul:

.mi-slider {
    position: relative;
    margin-top: 30px;
    height: 490px;
}

Элемент ul будет позиционироваться абсолютно, чтобы списки располагались один над другим. Мы будем перемещать пункты списка но не сам список. Установим для свойства  pointer-events значение none, так как нам нужно чтобы на нажатие кнопки мыши реагировала ссылка текущего списка:

.mi-slider ul {
    list-style-type: none;
    position: absolute;
    width: 100%;
    left: 0;
    bottom: 140px;
    overflow: hidden;
    text-align: center;
    pointer-events: none;
}

Свойство pointer-events для текущего списка нужно обновить, чтобы ссылки в содержании стали доступны для нажатия:

.mi-slider ul.mi-current {
    pointer-events: auto;
}

Когда JavaScript отключен мы сохраняем внешний вид (используем Modernizr):

.no-js .mi-slider ul {
    position: relative;
    left: auto;
    bottom: auto;
    margin: 0;
    overflow: visible;
}

Для того, чтобы центрировать все пункты установим для свойство выравнивания текста по центру для элемента ul, а для пунктов списка  свойство display:inline-block; и ширину 20%. Такое значение для ширины даст гарантию, что пункт поместится в списка и сохранит подвижность.

По умолчанию все пункты смещаются вправо. Используем значение 600%, так как его будет достаточно, чтобы убрать все из поля видимости. Также добавляем небольшую трансформацию для прозрачности:

.mi-slider ul li {
    display: inline-block;
    padding: 20px;
    width: 20%;
    max-width: 300px;
    transform: translateX(600%);
    transition: opacity 0.2s linear;
}

Без JavaScript смещения не требуется:

.no-js .mi-slider ul li {
    transform: translateX(0);
}

Определим стили для содержимого пунктов списка. Обратите внимание на установку для свойства изображений max-width значения 100%. Таким образом обеспечивается целостность шаблона при масштабировании изображений в соответствии с размерами контейнера, который представляет собой наш элемент li с процентным значением ширины.

.mi-slider ul li a,
.mi-slider ul li img {
    display: block;
    margin: 0 auto;
}
 
.mi-slider ul li a {
    outline: none;
    cursor: pointer;
}
 
.mi-slider ul li img {
    max-width: 100%;
    border: none;
}
 
.mi-slider ul li h4 {
    display: inline-block;
    font-family: Baskerville, "Baskerville Old Face", "Hoefler Text", Garamond, "Times New Roman", serif;
    font-style: italic;
    font-weight: 400;
    font-size: 18px;
    padding: 20px 10px 0;
}

При наведении курсора будем анимировать прозрачность пункта:

.mi-slider ul li:hover {
    opacity: 0.7;
}

Навигация нуждается в установке значения свойства top, так как шаблон позиционируется абсолютно. Мы центрируем навигацию устанавливая автоматические боковые поля и устанавливая максимальную ширину 800px:

.mi-slider nav {
    position: relative;
    top: 400px;
    text-align: center;
    max-width: 800px;
    margin: 0 auto;
    border-top: 5px solid #333;
}

При отключенном JavaScript выводить навигацию совсем не нужно:

.no-js nav {
    display: none;
}

Ссылки навигации будут иметь достаточные отступы и трансформироваться при наведении курсора:

.mi-slider nav a {
    display: inline-block;
    text-transform: uppercase;
    letter-spacing: 5px;
    padding: 40px 30px 30px 34px;
    position: relative;
    color: #888;
    outline: none;
    transition: color 0.2s linear;
}
 
.mi-slider nav a:hover,
.mi-slider nav a.mi-selected {
    color: #000;
}

Класс mi-selected, так же как и класс mi-current для списка, будет устанавливаться с помощью JavaScript.

Добавим небольшую стрелку вверху. Используем псевдо классы :before и :after для создания двух треугольников с помощью рамок

.mi-slider nav a.mi-selected:after,
.mi-slider nav a.mi-selected:before {
    content: '';
    position: absolute;
    top: -5px;
    border: solid transparent;
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
}
 
.mi-slider nav a.mi-selected:after {
    border-color: transparent;
    border-top-color: #fff;
    border-width: 20px;
    left: 50%;
    margin-left: -20px;
}
 
.mi-slider nav a.mi-selected:before {
    border-color: transparent;
    border-top-color: #333;
    border-width: 27px;
    left: 50%;
    margin-left: -27px;
}

Улучшим визуальное представление с помощью анимаций. Первая анимация увеличение масштаба пунктов первого списка. Анимация scaleUp также включает перемещение пунктов в координату 0, так как нам нужно вывести их в поле обзора:

.mi-slider ul:first-child li,
.no-js .mi-slider ul li {
    animation: scaleUp 350ms ease-in-out both;
}
 
@keyframes scaleUp {
    0% { transform: translateX(0) scale(0); }
    100% { transform: translateX(0) scale(1); }
}

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

.mi-slider ul:first-child li:first-child {
    animation-delay: 90ms;
}
 
.mi-slider ul:first-child li:nth-child(2) {
    animation-delay: 180ms;
}
 
.mi-slider ul:first-child li:nth-child(3) {
    animation-delay: 270ms;
}
 
.mi-slider ul:first-child li:nth-child(4) {
    animation-delay: 360ms;
}

Для нашего примера мы имеем максимум четыре пункта, поэтому и определены только четыре задержки. Если вам требуется большее количество пунктов, нужно определить большее количество задержек.

Для анимаций выскальзывания определяем четыре случая: два для выскальзывания нового пункта и два для убирания текущего пункта, в зависимости от направления. Определим четыре класса для списков, которые добавляются с помощью JavaScript:

/* Движение справа */

.mi-slider ul.mi-moveFromRight li {
	animation: moveFromRight 350ms ease-in-out both;
}

/* Движение слева */

.mi-slider ul.mi-moveFromLeft li {
	animation: moveFromLeft 350ms ease-in-out both;
}

/* Движение направо */

.mi-slider ul.mi-moveToRight li {
	animation: moveToRight 350ms ease-in-out both;
}

/* Движение налево */

.mi-slider ul.mi-moveToLeft li {
	animation: moveToLeft 350ms ease-in-out both;
}

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

.mi-slider ul.mi-moveToLeft li:first-child,
.mi-slider ul.mi-moveFromRight li:first-child,
.mi-slider ul.mi-moveToRight li:nth-child(4),
.mi-slider ul.mi-moveFromLeft li:nth-child(4) {
    animation-delay: 0ms;
}

Увеличиваем задержки соответственно:

.mi-slider ul.mi-moveToLeft li:nth-child(2),
.mi-slider ul.mi-moveFromRight li:nth-child(2),
.mi-slider ul.mi-moveToRight li:nth-child(3),
.mi-slider ul.mi-moveFromLeft li:nth-child(3) {
    -webkit-animation-delay: 90ms;
    animation-delay: 90ms;
}
 
.mi-slider ul.mi-moveToLeft li:nth-child(3),
.mi-slider ul.mi-moveFromRight li:nth-child(3),
.mi-slider ul.mi-moveToRight li:nth-child(2),
.mi-slider ul.mi-moveFromLeft li:nth-child(2) {
    -webkit-animation-delay: 180ms;
    animation-delay: 180ms;
}
 
.mi-slider ul.mi-moveToLeft li:nth-child(4),
.mi-slider ul.mi-moveFromRight li:nth-child(4),
.mi-slider ul.mi-moveToRight li:first-child,
.mi-slider ul.mi-moveFromLeft li:first-child  {
    -webkit-animation-delay: 270ms;
    animation-delay: 270ms;
}

Теперь определим сами анимации. Например, движение справа означает, что мы устанавливаем значение translateX равным 600% и смещаем его в 0. Движение налево означает установку конечной позиции в -600%, чтобы убрать пункт за пределы области видимости. И так далее:

@keyframes moveFromRight {
    0% { transform: translateX(600%); }
    100% { transform: translateX(0); }
}
 
@keyframes moveFromLeft {
    0% { transform: translateX(-600%); }
    100% { transform: translateX(0); }
}
 
@keyframes moveToRight {
    0% { transform: translateX(0%); }
    100% { transform: translateX(600%); }
}
 
@keyframes moveToLeft {
    0% { transform: translateX(0%); }
    100% { transform: translateX(-600%); }
}

И последнее по списку, но не по значимости: воспользуемся медиа запросами для выравнивания содержания слайдера на маленьких экранах.

Начнем с навигации. так как она должна сохраняться целостной в любых условиях:

@media screen and (max-width: 910px){
    .mi-slider nav {
        max-width: 90%;
    }
 
    .mi-slider nav a {
        font-size: 12px;
        padding: 40px 10px 30px 14px;
    }
}

Так как мы установили фиксированную высоту слайдера, то ее нужно адаптировать:

@media screen and (max-width: 740px){
    .mi-slider {
        height: 300px;
    }
 
    .mi-slider nav {
        top: 220px;
    }
}

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

@media screen and (max-width: 490px){ 
    .mi-slider {
        text-align: center;
        height: auto;
    }
 
    .mi-slider ul {
        position: relative;
        display: inline;
        bottom: auto;
        pointer-events: auto;
    }
 
    .mi-slider ul li {
        animation: none !important;
        transform: translateX(0) !important;
        padding: 10px 3px;
        min-width: 140px;
    }
 
    .mi-slider nav {
        display: none;
    }
}

Теперь пришло время переходить к jQuery.

 

JavaScript

Сделаем простой плагин для нашего слайдера. Большая часть работы выполняется в CSS, где определяются все анимации. Плагин сфокусирован на добавлении и убирании классов, а также на контроле за текущей выводимой категорией. Для браузеров, которые не поддерживают анимации используется метод "показать/скрыть".

Начнем с кеширования некоторых элементов и инициализации переменных:

		_init : function( options ) {

			// Категории (ul)
			this.$categories = this.$el.children( 'ul' );
			// Навигация
			this.$navcategories = this.$el.find( 'nav > a' );
			var animEndEventNames = {
				'WebkitAnimation' : 'webkitAnimationEnd',
				'OAnimation' : 'oAnimationEnd',
				'msAnimation' : 'MSAnimationEnd',
				'animation' : 'animationend'
			};
			// Название анимации и события
			this.animEndEventName = animEndEventNames[ Modernizr.prefixed( 'animation' ) ];
			// Поддержка анимаций и событий
			this.support = Modernizr.csstransforms && Modernizr.cssanimations;
			// Если анимация проводится
			this.isAnimating = false;
			// Текущая категория
			this.current = 0;
			var $currcat = this.$categories.eq( 0 );
			if( !this.support ) {
				this.$categories.hide();
				$currcat.show();
			}
			else {
				$currcat.addClass( 'mi-current' );
			}
			// Текущая категория навигации
			this.$navcategories.eq( 0 ).addClass( 'mi-selected' );
			// Инициализация событий
			this._initEvents();

		},

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

		_initEvents : function() {

			var self = this;
			this.$navcategories.on( 'click.catslider', function() {
				self.showCategory( $( this ).index() );
				return false;
			} );

			// Сброс при измении размеров окна
			$( window ).on( 'resize', function() {
				self.$categories.removeClass().eq( 0 ).addClass( 'mi-current' );
				self.$navcategories.eq( self.current ).removeClass( 'mi-selected' ).end().eq( 0 ).addClass( 'mi-selected' );
				self.current = 0;
			} );

		},
		showCategory : function( catidx ) {

			if( catidx === this.current || this.isAnimating ) {
				return false;
			}
			this.isAnimating = true;
			// Обновляем выбранную навигацию
			this.$navcategories.eq( this.current ).removeClass( 'mi-selected' ).end().eq( catidx ).addClass( 'mi-selected' );

			var dir = catidx > this.current ? 'right' : 'left',
				toClass = dir === 'right' ? 'mi-moveToLeft' : 'mi-moveToRight',
				fromClass = dir === 'right' ? 'mi-moveFromRight' : 'mi-moveFromLeft',
				// Текущая категория
				$currcat = this.$categories.eq( this.current ),
				// Новая категория
				$newcat = this.$categories.eq( catidx ),
				$newcatchild = $newcat.children(),
				lastEnter = dir === 'right' ? $newcatchild.length - 1 : 0,
				self = this;

			if( this.support ) {

				$currcat.removeClass().addClass( toClass );
				
				setTimeout( function() {

					$newcat.removeClass().addClass( fromClass );
					$newcatchild.eq( lastEnter ).on( self.animEndEventName, function() {

						$( this ).off( self.animEndEventName );
						$newcat.addClass( 'mi-current' );
						self.current = catidx;
						var $this = $( this );
						// Решение для ошибки в Chrome 
						self.forceRedraw( $this.get(0) );
						self.isAnimating = false;

					} );

				}, $newcatchild.length * 90 );

			}
			else {

				$currcat.hide();
				$newcat.show();
				this.current = catidx;
				this.isAnimating = false;

			}

		},
		// На основании http://stackoverflow.com/a/8840703/989439
		forceRedraw : function(element) {
			if (!element) { return; }
			var n = document.createTextNode(' '),
				position = element.style.position;
			element.appendChild(n);
			element.style.position = 'relative';
			setTimeout(function(){
				element.style.position = position;
				n.parentNode.removeChild(n);
			}, 25);
		}

	}

	$.fn.catslider = function( options ) {
		var instance = $.data( this, 'catslider' );
		if ( typeof options === 'string' ) {
			var args = Array.prototype.slice.call( arguments, 1 );
			this.each(function() {
				instance[ options ].apply( instance, args );
			});
		}
		else {
			this.each(function() {
				instance ? instance._init() : instance = $.data( this, 'catslider', new $.CatSlider( options, this ) );
			});
		}
		return instance;
	};

 

Готово!

Источник: http://feedproxy.google.com/~r/ruseller/CdHX/~3/SIK-FN0pDU4/lessons.php

Читать комменты и комментировать

Добавить комментарий / отзыв



Защитный код
Обновить

Простой слайдер для нескольких пунктов | | 2013-01-16 22:42:24 | | Статьи Web-мастеру | | В данном уроке мы сделаем простой слайдер для пунктов списка на основе анимаций CSS и jQuery. Идея для урока инспирирована слайдером продукции Aplle, где несколько товаров выскальзывают с | РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
 
Поделиться с друзьями: