В этой статье рассмотрим процесс создания легкого, простого и адаптивного слайдера для сайта с помощью CSS и JavaScript.

Исходные коды и подключение слайдера к сайту

Проект слайдера расположен на гитхабе, перейти к нему можно по этой ссылке.

Основные характеристики слайдера:

  • адаптивный;
  • лёгкий (без jQuery);
  • простой (с минимальным набором функций);
  • наличие механизма автоматического смена слайдов через определенные промежутки времени;
  • универсальный (можно использовать для текстовой информации, изображений, отзывов, товаров и др.).

Для подключения слайдера к странице необходимо:

  • вставить в необходимое место html код слайдера;
  • подключить файл со стилями или добавить их в существующий файл; также стили можно вставить прямо на страницу;
  • подключить js скрипт слайдера или вставить его в существующий файл; также код можно добавить прямо на страницу.

Демо слайдера можно посмотреть на этой странице.

Примеры использования слайдера для ротации различной информации

Применение слайдера для ротации изображений:

Слайдер изображений для сайта на CSS и JavaScript

Использования слайдера для ротации текстовой информации:

Слайдер текстовой информации (контента) для сайта на CSS и JavaScript

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

Простой слайдер отзывов клиентов для сайта на CSS и JavaScript

Применение слайдера для ротации товаров:

Слайдер товаров для сайта на CSS и JavaScript

Процесс создания слайдера

Процесс разработки слайдера будет состоять из 3 этапов:

  1. создания вёрстки;
  2. написания CSS кода (стилей);
  3. написания JavaScript кода (скрипта).

Вёрстка слайдера

HTML код слайдера:

<div id="slider" class="slider">
  <ol class="slider__indicators">
    <li class="slider__indicator slider__indicator_active" data-slide-to="0"></li>
    <li class="slider__indicator" data-slide-to="1"></li>
    <li class="slider__indicator" data-slide-to="2"></li>
    <li class="slider__indicator" data-slide-to="3"></li>
  </ol>
  <div class="slider__items">
    <div class="slider__item slider__item_active">
      ...
    </div>
    <div class="slider__item">
      ...
    </div>
    <div class="slider__item">
      ...
    </div>
    <div class="slider__item">
      ...
    </div>
  </div>
  <a class="slider__control slider__control_prev" href="#" role="button"></a>
  <a class="slider__control slider__control_next" href="#" role="button"></a>
</div>

Как видно, элемент div с классом slider выступает в качестве контейнера, в котором содержится остальная вёрстка слайдера. Внутри контейнера находятся четыре элемента: обёртка для слайдов (slider__items), блок с индикаторами (slider__indicators), кнопки для перехода к предыдущему и следующему слайду (slider__control).

Обёртка для слайдов (slider__items) содержит элементы (slider__item). В примере слайдер состоит из 4 элементов. Каждый элемент – это слайд. Текущий или активный элемент будет обозначаться с помощью класса slider__item_active.

Блок с индикаторами (slider__indicators) представлен посредством нумерованного списка. Список состоит из четырёх элементов, каждый из которых имеет класс slider__indicator. Первый индикатор (data-slide-to = "0") предназначен для активизации первого слайда, второй – второго и т.д. Текущий или активный индикатор будет выделяться с помощью класса slider__indicator_active.

Кнопки «назад» и «вперед» размечены с помощью элемента a. Кнопка для перехода к предыдущему слайду имеет классы slider__control и slider__control_prev, а к следующему - slider__control и slider__control_next.

Стилизация слайдера

CSS слайдера:

.slider {
  /* устанавливаем относительное позиционирование элементу */
  position: relative;
}

.slider__items {
  /* устанавливаем относительное позиционирование элементу */
  position: relative;
  /* устанавливаем элементу ширину, равную 100% */
  width: 100%;
  overflow: hidden;
}

.slider__item {
  /* устанавливаем относительное позиционирование элементу */
  position: relative;
  /* отключаем по умолчанию отображение всех слайдов */
  display: none;
  /* устанавливаем элементу ширину, равную 100% */
  width: 100%;
  /* длительность анимации трансформации */
  transition: transform 0.6s ease;
  /* не показывать обратную сторону трансформируемого элемента */
  backface-visibility: hidden;
}

.slider__item_active,
.slider__item_next,
.slider__item_prev {
  /* отображаем слайд, если он имеет один из этих классов */
  display: block;
}

.slider__item_next,
.slider__item_prev {
  /* устанавливаем абсолютное позиционирование для элемента, на который будет сменяться слайд (на время трансформации) */
  position: absolute;
  /* устанавливаем положение элемента, т.е. координату top */
  top: 0;
}

.slider__item_next.slider__item_left,
.slider__item_prev.slider__item_right {
  /* сдвигаем элемент на 0 по горизонтали */
  transform: translateX(0);
}

.slider__item_next,
.slider__item_right.slider__item_active {
  /* сдвигаем элемент на 100% по горизонтали */
  transform: translateX(100%);
}

.slider__item_prev,
.slider__item_left.slider__item_active {
  /* сдвигаем элемент на -100% по горизонтали */
  transform: translateX(-100%);
}

/* элементы управления (назад и вперёд) слайдером */

.slider__control {
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 15%;
  color: #fff;
  text-align: center;
  opacity: 0.5;
}

.slider__control:hover,
.slider__control:focus {
  color: #fff;
  text-decoration: none;
  outline: 0;
  opacity: .9;
}

.slider__control_prev {
  left: 0;
}

.slider__control_next {
  right: 0;
}

.slider__control::before {
  content: '';
  display: inline-block;
  width: 20px;
  height: 20px;
  background: transparent no-repeat center center;
  background-size: 100% 100%;
}

.slider__control_prev::before {
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E");
}

.slider__control_next::before {
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E");
}

/* индикаторы слайдера */

.slider__indicators {
  position: absolute;
  right: 0;
  bottom: 10px;
  left: 0;
  z-index: 15;
  display: flex;
  justify-content: center;
  padding-left: 0;
  margin-right: 15%;
  margin-left: 15%;
  list-style: none;
}

.slider__indicator {
  position: relative;
  flex: 0 1 auto;
  width: 30px;
  height: 3px;
  margin-right: 3px;
  margin-left: 3px;
  text-indent: -999px;
  cursor: pointer;
  background-color: rgba(255, 255, 255, 0.5);
  border-radius: 6px;
}

.slider__indicator::before {
  position: absolute;
  top: -10px;
  left: 0;
  display: inline-block;
  width: 100%;
  height: 10px;
  content: "";
}

.slider__indicator::after {
  position: absolute;
  bottom: -10px;
  left: 0;
  display: inline-block;
  width: 100%;
  height: 10px;
  content: "";
}

.slider__indicator_active {
  background-color: #fff;
}

По умолчанию в некоторый момент времени показывается только один слайд. Осуществляется это посредством установки всем элементам slider__item объявления display: none, а активному – display: block.

Аккордеон, заголовки которого отделены друг от друга

Смена слайда, например, в направлении next организовывается посредством выполнения следующих 3 действий:

1. Подготовительный этап. На этом этапе осуществляется добавление к слайду («next»), который должен заменить текущий, класса slider__item_next. Этот класс устанавливает абсолютное позиционирование слайду «next», а также осуществляет его сдвиг на 100% по горизонтали. Но слайд «next» на данном этапе не будет виден пользователю, т.к. обёртка для слайдов (slider__items) имеет объявление overflow:hidden.

Аккордеон, заголовки которого отделены друг от друга

2. Этап смены слайда. На данном шаге осуществляется добавление класса slider-item-left к текущему слайду и элементу, на который будет сменяться текущий слайд. Данный класс устанавливает сдвиг текущего слайда на -100%, а слайда «next» на 0%. Этот сдвиг осуществляется не мгновенно, а некоторый промежуток времени (0.6 секунд). Устанавливается он для элементов с классом slider__item посредством объявления:

.slider__item {
  transition: transform 0.6s ease;
}
Аккордеон, заголовки которого отделены друг от друга

3. Заключительный шаг (после завершения смены слайда).

На этом этапе выполняется:

  • удаление у текущего слайда (который не «next») классов slider__item_active и slider__item_left;
  • удаление у «next» слайда классов slider__item_next и slider__item_left; добавление к нему slider__item_active.

После этих действий «next» слайд станет текущим.

Аккордеон, заголовки которого отделены друг от друга

Логика слайдера

JavaScript слайдера:

'use strict';
var slider = (function (config) {

  const ClassName = {
    INDICATOR_ACTIVE: 'slider__indicator_active',
    ITEM: 'slider__item',
    ITEM_LEFT: 'slider__item_left',
    ITEM_RIGHT: 'slider__item_right',
    ITEM_PREV: 'slider__item_prev',
    ITEM_NEXT: 'slider__item_next',
    ITEM_ACTIVE: 'slider__item_active'
  }

  var
    _isSliding = false, // индикация процесса смены слайда
    _interval = 0, // числовой идентификатор таймера
    _transitionDuration = 700, // длительность перехода
    _slider = {}, // DOM элемент слайдера
    _items = {}, // .slider-item (массив слайдов) 
    _sliderIndicators = {}, // [data-slide-to] (индикаторы)
    _config = {
      selector: '', // селектор слайдера
      isCycling: true, // автоматическая смена слайдов
      direction: 'next', // направление смены слайдов
      interval: 5000, // интервал между автоматической сменой слайдов
      pause: true // устанавливать ли паузу при поднесении курсора к слайдеру
    };

  var
    // функция для получения порядкового индекса элемента
    _getItemIndex = function (_currentItem) {
      var result;
      _items.forEach(function (item, index) {
        if (item === _currentItem) {
          result = index;
        }
      });
      return result;
    },
    // функция для подсветки активного индикатора
    _setActiveIndicator = function (_activeIndex, _targetIndex) {
      if (_sliderIndicators.length !== _items.length) {
        return;
      }
      _sliderIndicators[_activeIndex].classList.remove(ClassName.INDICATOR_ACTIVE);
      _sliderIndicators[_targetIndex].classList.add(ClassName.INDICATOR_ACTIVE);
    },

    // функция для смены слайда
    _slide = function (direction, activeItemIndex, targetItemIndex) {
      var
        directionalClassName = ClassName.ITEM_RIGHT,
        orderClassName = ClassName.ITEM_PREV,
        activeItem = _items[activeItemIndex], // текущий элемент
        targetItem = _items[targetItemIndex]; // следующий элемент

      var _slideEndTransition = function () {
        activeItem.classList.remove(ClassName.ITEM_ACTIVE);
        activeItem.classList.remove(directionalClassName);
        targetItem.classList.remove(orderClassName);
        targetItem.classList.remove(directionalClassName);
        targetItem.classList.add(ClassName.ITEM_ACTIVE);
        window.setTimeout(function () {
          if (_config.isCycling) {
            clearInterval(_interval);
            _cycle();
          }
          _isSliding = false;
          activeItem.removeEventListener('transitionend', _slideEndTransition);
        }, _transitionDuration);
      };

      if (_isSliding) {
        return; // завершаем выполнение функции если идёт процесс смены слайда
      }
      _isSliding = true; // устанавливаем переменной значение true (идёт процесс смены слайда)

      if (direction === "next") { // устанавливаем значение классов в зависимости от направления
        directionalClassName = ClassName.ITEM_LEFT;
        orderClassName = ClassName.ITEM_NEXT;
      }

      targetItem.classList.add(orderClassName); // устанавливаем положение элемента перед трансформацией
      _setActiveIndicator(activeItemIndex, targetItemIndex); // устанавливаем активный индикатор

      window.setTimeout(function () { // запускаем трансформацию
        targetItem.classList.add(directionalClassName);
        activeItem.classList.add(directionalClassName);
        activeItem.addEventListener('transitionend', _slideEndTransition);
      }, 0);

    },
    // функция для перехода к предыдущему или следующему слайду
    _slideTo = function (direction) {
      var
        activeItem = _slider.querySelector('.' + ClassName.ITEM_ACTIVE), // текущий элемент
        activeItemIndex = _getItemIndex(activeItem), // индекс текущего элемента 
        lastItemIndex = _items.length - 1, // индекс последнего элемента
        targetItemIndex = activeItemIndex === 0 ? lastItemIndex : activeItemIndex - 1;
      if (direction === "next") { // определяем индекс следующего слайда в зависимости от направления
        targetItemIndex = activeItemIndex == lastItemIndex ? 0 : activeItemIndex + 1;
      }
      _slide(direction, activeItemIndex, targetItemIndex);
    },
    // функция для запуска автоматической смены слайдов в указанном направлении
    _cycle = function () {
      if (_config.isCycling) {
        _interval = window.setInterval(function () {
          _slideTo(_config.direction);
        }, _config.interval);
      }
    },
    // обработка события click
    _actionClick = function (e) {
      var
        activeItem = _slider.querySelector('.' + ClassName.ITEM_ACTIVE), // текущий элемент
        activeItemIndex = _getItemIndex(activeItem), // индекс текущего элемента
        targetItemIndex = e.target.getAttribute('data-slide-to');

      if (!(e.target.hasAttribute('data-slide-to') || e.target.classList.contains('slider__control'))) {
        return; // завершаем если клик пришёлся на не соответствующие элементы
      }
      if (e.target.hasAttribute('data-slide-to')) {// осуществляем переход на указанный сдайд 
        if (activeItemIndex === targetItemIndex) {
          return;
        }
        _slide((targetItemIndex > activeItemIndex) ? 'next' : 'prev', activeItemIndex, targetItemIndex);
      } else {
        e.preventDefault();
        _slideTo(e.target.classList.contains('slider__control_next') ? 'next' : 'prev');
      }
    },
    // установка обработчиков событий
    _setupListeners = function () {
      // добавление к слайдеру обработчика события click
      _slider.addEventListener('click', _actionClick);
      // остановка автоматической смены слайдов (при нахождении курсора над слайдером)
      if (_config.pause && _config.isCycling) {
        _slider.addEventListener('mouseenter', function (e) {
          clearInterval(_interval);
        });
        _slider.addEventListener('mouseleave', function (e) {
          clearInterval(_interval);
          _cycle();
        });
      }
    };

  // init (инициализация слайдера)
  for (var key in config) {
    if (key in _config) {
      _config[key] = config[key];
    }
  }
  _slider = (typeof _config.selector === 'string' ? document.querySelector(_config.selector) : _config.selector);
  _items = _slider.querySelectorAll('.' + ClassName.ITEM);
  _sliderIndicators = _slider.querySelectorAll('[data-slide-to]');
  // запуск функции cycle
  _cycle();
  _setupListeners();

  return {
    next: function () { // метод next 
      _slideTo('next');
    },
    prev: function () { // метод prev 
      _slideTo('prev');
    },
    stop: function () { // метод stop
      clearInterval(_interval);
    },
    cycle: function () { // метод cycle 
      clearInterval(_interval);
      _cycle();
    }
  }
}({
  selector: '.slider',
  isCycling: true,
  direction: 'next',
  interval: 5000,
  pause: true
}));

Код слайдера написан без использования библиотеки jQuery. Программный код структурирован и организован в виде «модуля».

Основные приватные функции модуля «slider»:

  • _cycle – функция для запуска автоматической смены слайдов через определенные промежутки времени (по умолчанию 5 секунд);
  • _slide – функция, осуществляющая процесс смены слайда в указанном направлении; кроме направления этой функции ещё передаются индекс текущего слайда и индекс того слайда на который он должен смениться;
  • _slideTo – вспомогательная функция, которая подготавливает данные для функции _slide; она используется в функции _cycle и в обработчике события, который выполняется, когда пользователь нажимает на кнопку «назад» или «вперед»;
  • _setActiveIndicator – функция, которая используется для подсветки текущего индикатора слайда;
  • _setupListener – функция, осуществляющая установку обработчиков для событий связанных со слайдером.

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

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

var slider = (function (config) {

  // ...

}({
  selector: '.slider',
  isCycling: true,
  direction: 'next',
  interval: 5000,
  pause: true
}));

Параметры для установки:

  • selector – селектор, на основании которого будет осуществляться поиск слайдера в документе; кроме строки возможно также передача DOM элемента (по умолчанию данный параметр имеет значение '.slider');
  • isCycling – определяет, необходимо ли включать запуск автоматической смены слайдов (по умолчанию он имеет значение true);
  • direction – задаёт направление смены слайдов (по умолчанию 'next'); для изменения направления установите 'prev';
  • interval – интервал времени между автоматической сменой слайдов в миллисекундах (по умолчанию 5000);
  • pause – определяет необходимо ли ставить на паузу автоматическую смену слайдов при нахождении курсора в зоне слайдера (по умолчанию true).

Методы, с помощью которых можно управлять слайдером:

  • stop – выполняет остановку автоматической смены слайдов;
  • next – осуществляет переход на следующий слайд;
  • prev – осуществляет переход на предыдущий слайд;
  • cycle – выполняет включение автоматической смены слайдов.