Слайдер с эффектом параллакса

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

Изображения для демонстрации взяты у автора Tetsumo с сайта Flickr: http://www.flickr.com/photos/tetsumo/

Разметка HTML


Структура HTML состоит из основного контейнера с классом "pxs_container”. Также мы добавим контейнер для трех различных изображений фона, которые будут смещаться на разные расстояния для создания эффекта параллакса. Фоновые изображения имеют области прозрачности, так что мы будем видеть их движение при наложении.

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

Code
<div id="pxs_container" class="pxs_container">
  <div class="pxs_bg">
  <div class="pxs_bg1"></div>
  <div class="pxs_bg2"></div>
  <div class="pxs_bg3"></div>
  </div>
  <div class="pxs_loading">Загрузка изображений...</div>
  <div class="pxs_slider_wrapper">
  <ul class="pxs_slider">
  <li><img src="images/1.jpg" alt="First Image" /></li>
  <li><img src="images/2.jpg" alt="Second Image" /></li>
  ...
  </ul>
  <div class="pxs_navigation">
  <span class="pxs_next"></span>
  <span class="pxs_prev"></span>
  </div>
  <ul class="pxs_thumbnails">
  <li><img src="images/thumbs/1.jpg" alt="First Image" /></li>
  <li><img src="images/thumbs/2.jpg" alt="Second Image" /></li>
  ...
  </ul>
  </div>
</div>


CSS


Начнем с задания стилей для основного контейнера. Так как мы думаем использовать всю страницу для слайдера, то установим его ширину на 100%. Он будет иметь относительно позиционирование, а элементы внутри него будут иметь абсолютное позиционирование (они будут позиционироваться по отношению к контейнеру, а не ко всей странице):

Code
.pxs_container{
  width:100%;
  height:420px;
  position:relative;
  border-top:7px solid #333;
  border-bottom:7px solid #333;
  overflow:hidden;
  -moz-box-shadow:0px 0px 7px #000;
  -webkit-box-shadow:0px 0px 7px #000;
  box-shadow:0px 0px 7px #000;
}


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

Code
.pxs_bg{
  background:transparent url(../images/bg.png) repeat top left;
}


Элементы div внутри контейнера будут иметь одинаковый стиль:

Code
.pxs_bg div{
  position:absolute;
  top:0px;
  left:0px;
  height:420px;
  background-repeat:repeat;
  background-position:top left;
  background-color:transparent;
}



Ширина будет динамически устанавливаться в коде JavaScript. Каждый элемент div будет иметь свое собственное фоновое изображение:

Code
.pxs_bg .pxs_bg1{
  background-image:url(../images/bg1.png);
}
.pxs_bg .pxs_bg2{
  background-image:url(../images/bg2.png);
}
.pxs_bg .pxs_bg3{
  background-image:url(../images/bg3.png);
}



Мы также динамически устанавливаем значение свойства left для данных элементов div.

Следующий контейнер сначала будет скрыт:

Code
.pxs_slider_wrapper{
  display:none;
}



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

Нужно сбросить стили для обоих списков:

Code
.pxs_container ul{
  margin:0px;
  padding:0px;
  list-style:none;
}



Основная идея слайдера заключается в том, что мы делаем очень длинный список, в котором все элементы li имеют ширину равную ширине окна. Таким образом, то, что вы видите на экране, в действительности является элементом li. Мы будем устанавливать ширину списка ul динамически равной произведению ширины окна на количество элементов (изображений) списка. Устанавливая для элементов li смещение влево и правильную ширину списка ul, мы добиваемся того, что все элементы li выстраиваются в одну линию один за другим:

Code
ul.pxs_slider{
  position:absolute;
  left:0px;
  top:0px;
  height:420px;
}
ul.pxs_slider li{
  height:420px;
  float:left;
  position:relative;
}



Изображение слайда внутри элемента li будет центрироваться горизонтально с помощью значения auto для левого и правого полей:

Code
ul.pxs_slider li img{
  display:block;
  margin:35px auto 0px auto;
  -moz-box-shadow:0px 0px 7px #222;
  -webkit-box-shadow:0px 0px 7px #222;
  box-shadow:0px 0px 7px #222;
  border: 8px solid transparent;
  -moz-border-radius:4px;
  -webkit-border-radius:4px;
  border-radius:4px;
}



Добавление прозрачной границы и тени создает эффект стекла для изображения.

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

Code
ul.pxs_thumbnails{
  height:35px;
  position:absolute;
  top:320px;
  left:50%;
}
ul.pxs_thumbnails li{
  position:absolute;
  display:block;
}



Добавим белую рамочку вокруг миниатюр и установим для них легкую тень:

Code
ul.pxs_thumbnails li img{
  border: 5px solid #FFFFFF;
  -moz-box-shadow:1px 1px 7px #555;
  -webkit-box-shadow:1px 1px 7px #555;
  box-shadow:1px 1px 7px #555;
  cursor:pointer;
  display:block;
  opacity:0.7;
}



Миниатюра текущего изображения должна быть полностью непрозрачна:

Code
ul.pxs_thumbnails li.selected img{
  opacity:1.0;
}



Общий стиль двух элементов span для навигации будет следующим:

Code
.pxs_navigation span{
  position:absolute;
  width:30px;
  height:60px;
  -moz-box-shadow:0px 0px 2px #000;
  -webkit-box-shadow:0px 0px 2px #000;
  box-shadow:0px 0px 2px #000;
  top:145px;
  opacity:0.6;
  -moz-border-radius:4px;
  -webkit-border-radius:4px;
  border-radius:4px;
  cursor:pointer;
}
.pxs_navigation span:hover{
  opacity:0.9;
}



Добавим стрелки для каждого элемента навигации:

Code
.pxs_navigation span.pxs_prev{
  background:#000 url(../images/prev.png) no-repeat center center;
}
.pxs_navigation span.pxs_next{
  background:#000 url(../images/next.png) no-repeat center center;
}



Мы будем устанавливать значения для свойства left (pxs_prev) и свойства right (pxs_next) динамически для того, чтобы элементы навигации находились у левого и правого краев изображения.

И в завершении мы зададим стиль для индикатора загрузки, который будет центрироваться:

Code
.pxs_loading{
  color:#fff;
  font-size:20px;
  padding:15px 15px 15px 50px;
  position:absolute;
  background:#333 url(../images/ajax-loader.gif) no-repeat 10px 50%;
  -moz-border-radius:15px;
  -webkit-border-radius:15px;
  border-radius:15px;
  opacity:0.7;
  width:180px;
  position:absolute;
  top:150px;
  left:50%;
  margin-left:-90px;
}


JavaScript


Основная идея слайдера заключается в том, чтобы при перемещении слайда по-разному анимировать три фоновых изображения для создания эффекта перспективы. Таким образом, например, при перемещении к следующему изображению, мы будем анимировать изменение значения свойства слайдера ul left, которое уменьшится на ширину окна (потому, что это ширина одного элемента li). Также будет анимироваться перемещение верхнего фонового элемента div, но на расстояние равное половине ширине окна. Следующее фоновое изображение будет смещаться только на четверть ширины окна. То есть фоновое изображение, которое располагается "дальше" от пользователя смещается меньше, точно в соответствии с принципом параллакса.

Сам скрипт будет сделан плагином с несколькими опциями.

Code
(function($) {
  $.fn.parallaxSlider = function(options) {
  var opts = $.extend({}, $.fn.parallaxSlider.defaults, options);
  return this.each(function() {
  var $pxs_container = $(this),
  o = $.meta ? $.extend({}, opts, $pxs_container.data()) : opts;
   
  //Основной слайдер
  var $pxs_slider = $('.pxs_slider',$pxs_container),
  //Элементы в слайдере
  $elems = $pxs_slider.children(),
  //Общее количество элементов
  total_elems = $elems.length,
  //Кнопки навигации
  $pxs_next = $('.pxs_next',$pxs_container),
  $pxs_prev = $('.pxs_prev',$pxs_container),
  //Фоновые изображения
  $pxs_bg1 = $('.pxs_bg1',$pxs_container),
  $pxs_bg2 = $('.pxs_bg2',$pxs_container),
  $pxs_bg3 = $('.pxs_bg3',$pxs_container),
  //Текущее изображение
  current = 0,
  //Контейнер миниатюр
  $pxs_thumbnails = $('.pxs_thumbnails',$pxs_container),
  //Миниатюры
  $thumbs = $pxs_thumbnails.children(),
  //Интервал для режима автопроигрывания
  slideshow,
  //Загрузка изображения
  $pxs_loading = $('.pxs_loading',$pxs_container),
  $pxs_slider_wrapper = $('.pxs_slider_wrapper',$pxs_container);
   
  //Сначала загружаем все изображения
  var loaded = 0,
  $images = $pxs_slider_wrapper.find('img');
   
  $images.each(function(){
  var $img = $(this);
  $('<img/>').load(function(){
  ++loaded;
  if(loaded == total_elems*2){
  $pxs_loading.hide();
  $pxs_slider_wrapper.show();
   
  //Ширина изображения (предполагаем, что все изображения имеют одинаковые размеры)
  var one_image_w = $pxs_slider.find('img:first').width();
   
  /*
  Нужно установить ширину слайдера, каждого из его элементов  
  и кнопок навигации
  */
  setWidths($pxs_slider,
  $elems,
  total_elems,
  $pxs_bg1,
  $pxs_bg2,
  $pxs_bg3,
  one_image_w,
  $pxs_next,
  $pxs_prev);
   
  /*
  Устанавливаем ширину миниатюр
  и распределяем их равномерно
  */
  $pxs_thumbnails.css({
  'width' : one_image_w + 'px',
  'margin-left' : -one_image_w/2 + 'px'
  });
  var spaces = one_image_w/(total_elems+1);
  $thumbs.each(function(i){
  var $this = $(this);
  var left = spaces*(i+1) - $this.width()/2;
  $this.css('left',left+'px');
   
  if(o.thumbRotation){
  var angle = Math.floor(Math.random()*41)-20;
  $this.css({
  '-moz-transform' : 'rotate('+ angle +'deg)',
  '-webkit-transform' : 'rotate('+ angle +'deg)',
  'transform' : 'rotate('+ angle +'deg)'
  });
  }
  //При прохождении курсора над миниатюрой, она приподнимается
  $this.bind('mouseenter',function(){
  $(this).stop().animate({top:'-10px'},100);
  }).bind('mouseleave',function(){
  $(this).stop().animate({top:'0px'},100);
  });
  });
   
  //Делаем первую миниатюру выбранной
  highlight($thumbs.eq(0));
   
  //Проскальзываем при нажатии кнопки навигации
  $pxs_next.bind('click',function(){
  ++current;
  if(current >= total_elems)
  if(o.circular)
  current = 0;
  else{
  --current;
  return false;
  }
  highlight($thumbs.eq(current));
  slide(current,
  $pxs_slider,
  $pxs_bg3,
  $pxs_bg2,
  $pxs_bg1,
  o.speed,
  o.easing,
  o.easingBg);
  });
  $pxs_prev.bind('click',function(){
  --current;
  if(current < 0)
  if(o.circular)
  current = total_elems - 1;
  else{
  ++current;
  return false;
  }
  highlight($thumbs.eq(current));
  slide(current,
  $pxs_slider,
  $pxs_bg3,
  $pxs_bg2,
  $pxs_bg1,
  o.speed,
  o.easing,
  o.easingBg);
  });
   
  /*
  Нажатие на миниатюру приводит к выскальзыванию соответствующего изображения
  */
  $thumbs.bind('click',function(){
  var $thumb = $(this);
  highlight($thumb);
  //если включено автопроигрывание, прерываем его при нажатии кнопки мыши
  if(o.auto)
  clearInterval(slideshow);
  current = $thumb.index();
  slide(current,
  $pxs_slider,
  $pxs_bg3,
  $pxs_bg2,
  $pxs_bg1,
  o.speed,
  o.easing,
  o.easingBg);
  });
   
   
   
  /*
  Активируем автопроигрывание,  
  если установлена соответствующая опция
  */
  if(o.auto != 0){
  o.circular = true;
  slideshow = setInterval(function(){
  $pxs_next.trigger('click');
  },o.auto);
  }
   
  /*
  При изменении размеров окна
  нужно пересчитать ширину элементов
  на основе новой ширины окна.
  Нужно также передвинуть текущий элемент,
  чтобы перерисовать левую часть.
  */
  $(window).resize(function(){
  w_w = $(window).width();
  setWidths($pxs_slider,$elems,total_elems,$pxs_bg1,$pxs_bg2,$pxs_bg3,one_image_w,$pxs_next,$pxs_prev);
  slide(current,
  $pxs_slider,
  $pxs_bg3,
  $pxs_bg2,
  $pxs_bg1,
  1,
  o.easing,
  o.easingBg);
  });
  }
  }).error(function(){
  alert('here')
  }).attr('src',$img.attr('src'));
  });
   
   
   
  });
  };
   
  //Текущая ширина окна
  var w_w = $(window).width();
   
  var slide = function(current,
  $pxs_slider,
  $pxs_bg3,
  $pxs_bg2,
  $pxs_bg1,
  speed,
  easing,
  easingBg){
  var slide_to = parseInt(-w_w * current);
  $pxs_slider.stop().animate({
  left : slide_to + 'px'
  },speed, easing);
  $pxs_bg3.stop().animate({
  left : slide_to/2 + 'px'
  },speed, easingBg);
  $pxs_bg2.stop().animate({
  left : slide_to/4 + 'px'
  },speed, easingBg);
  $pxs_bg1.stop().animate({
  left : slide_to/8 + 'px'
  },speed, easingBg);
  }
   
  var highlight = function($elem){
  $elem.siblings().removeClass('selected');
  $elem.addClass('selected');
  }
   
  var setWidths = function($pxs_slider,
  $elems,
  total_elems,
  $pxs_bg1,
  $pxs_bg2,
  $pxs_bg3,
  one_image_w,
  $pxs_next,
  $pxs_prev){
  /*
  Ширина слайдера - это ширина окна умноженная на общее количество элементов в слайдере
  */
  var pxs_slider_w = w_w * total_elems;
  $pxs_slider.width(pxs_slider_w + 'px');
  //Каждый элемент имеет ширину равную ширине окна
  $elems.width(w_w + 'px');
  /*
  Мы также устанавливаем ширину каждого изображения фона.
  Значение также вычисляется с помощью pxs_slider
  */
  $pxs_bg1.width(pxs_slider_w + 'px');
  $pxs_bg2.width(pxs_slider_w + 'px');
  $pxs_bg3.width(pxs_slider_w + 'px');
   
  /*
  Для обеих навигационных кнопок:
  windowWidth/2 - imgWidth/2 + небольшое поле (чтобы не касаться рамок изображений)
  */
  var position_nav = w_w/2 - one_image_w/2 + 3;
  $pxs_next.css('right', position_nav + 'px');
  $pxs_prev.css('left', position_nav + 'px');
  }
   
  $.fn.parallaxSlider.defaults = {
  auto : 0, //задержка в секундах для периодического прокручивания контента,
  //если значение 0 - автопрокрутка выключена
  speed : 1000, //скорость проскальзывания слайда
  easing : 'jswing', //эффект перехода для анимации
  easingBg : 'jswing', //эффект перехода для анимации фона
  circular : true, //проскальзывание по кругу
  thumbRotation : true //миниатюры поворачиваются случайным образом
  };
  //easeInOutExpo,easeInBack
})(jQuery);


Запускается плагин следующим кодом:

Code
$(function() {
  var $pxs_container = $('#pxs_container');
  $pxs_container.parallaxSlider();
});



Опции слайдера:

auto: задержка при переключении к следующему слайду. Если установлено значение 0, то автопроигрывание отключено.
speed: скорость анимации перемещения слайдов
easing: эффект перехода для анимации слайдов
easingBg: эффект перехода для анимации фона
circular: включить проход слайдов по кругу
thumbRotation: миниатюры будут поворачиваться на случайный угол


Готово!


  • FalleN

  • 6551

  • 1

  • 269

Ссылки на статью:

Похожие статьи: