Простой слайдер изображений на CSS и Javascript

    Автор уже опубликовал скрипт карусели, который также использует только CSS и Javascript. Теперь давайте рассмотрим скрипт слайдера. Он отличается от карусели тем, что одновременно виден только один элемент, а не несколько, и элементы не прокручиваются, а медленно замещаются одно другим. И ещё. В данном слайдере в качестве элементов используются только изображения (слайды), поэтому и называется он простой слайдер изображений.

    Навигация осуществляется стрелками “Следующий элемент” или “Предыдущий элемент” и индикаторными точками. Стрелки и точки можно отключить в настройках скрипта. Элементы могут быть показаны с остановкой на первом и последнем элементе или в цикле, когда за последним элементом вновь следует первый. Можно включить автоматический просмотр (пролистывание) элементов, длительность просмотра (интервал между переключениями) регулируется. При наведении мыши на элемент пролистывание прекращается.

    Слайдер автоматически подстраивается под любую ширину экрана любого устройства. Убедиться в этом можно сдвигая влево-вправо какую-либо из боковых сторон браузера.

    image

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

    <div class="sim-slider">
         <ul class="sim-slider-list">
             <li><img src="screen.gif" alt="screen"></li>    <!-- это экран -->
             <li class="sim-slider-element"><img src="img1.jpg" alt="1"></li>
             <li class="sim-slider-element"><img src="img2.jpg" alt="2"></li>
    	  …
             <li class="sim-slider-element"><img src="imgN.jpg" alt="N"></li>
         </ul>
         <div class="sim-slider-arrow-left"></div>
         <div class="sim-slider-arrow-right"></div>
         <div class="sim-slider-dots"></div>
     </div>
    

    В качестве контейнеров использованы теги <ul><li>, но можно использовать и <div><div> или <div><p>. Стрелки и индикаторные точки располагаются абсолютным позиционированием в соответствующих контейнерах. Для стрелок используются рисунки в виде треугольных скобок, которые, при желании, вы можете заменить своими рисунками. Точки генерируются программой, количество точек равно количеству изображений.

    Все изображения располагаются “в стопочку”, одно над другим абсолютным позиционированием в левом верхнем углу объемлющего контейнера. Экран предотвращает схлопывание внешнего контейнера. Всем изображениям присваивается CSS-свойство opacity: 0, кроме первого элемента, которому программа инициализации присваивает opacity: 1, тем самым делая его видимым.

    Пролистывание элементов осуществляется плавным изменением opacity из 1 в 0 для видимого элемента и из 0 в 1 для следующего за ним невидимого элемента. Тем самым видимый элемент становится невидимым, а невидимый видимым. Плавность перехода создаёт свойство transition с длительностью 1с и функцией перехода ease-in.

    CSS
    img {
      width: 100%;  !important;
    }
    
    /* General styles */
    .sim-slider {
      position: relative;
    }
    
    .sim-slider-list {
      margin: 0;
      padding: 0;
      list-style-type: none;
      position: relative;
    }
    
    .sim-slider-element {
      width: 100%;
      transition: opacity 1s ease-in;
      opacity: 0;
      position: absolute;
      z-index: 2;
      left: 0;
      top: 0;
      display: block;
    }
    
    /* Navigation item styles */
    div.sim-slider-arrow-left,
    div.sim-slider-arrow-right {
      width: 22px;
      height: 40px;
      position: absolute;
      cursor: pointer;
      opacity: 0.6;
      z-index: 4;
    }
    
    div.sim-slider-arrow-left {
      left: 10px;
      top: 40%;
      display: block;
      background: url("sim-arrow-left.png") no-repeat;
    }
    
    div.sim-slider-arrow-right {
      right: 10px;
      top: 40%;
      display: block;
      background: url("sim-arrow-right.png") no-repeat;
    }
    
    div.sim-slider-arrow-left:hover {
      opacity: 1.0;
    }
    
    div.sim-slider-arrow-right:hover {
      opacity: 1.0;
    }
    
    div.sim-slider-dots {
      width: 100%;
      height: auto;
      position: absolute;
      left: 0;
      bottom: 0;
      z-index: 3;
      text-align: center;
    }
    
    span.sim-dot {
      width: 10px;
      height: 10px;
      margin: 5px 7px;
      padding: 0;
      display: inline-block;
      background-color: #BBB;
      border-radius: 5px;
      cursor: pointer;
    }
    


    Для того, чтобы слайдер был адаптивным к любой ширине экрана, для изображений нужно указать CSS-свойство width: 100%. Для всех блочных контейнеров (div, ul, li и пр.) также width: 100% или, если нужна ширина в числовых единицах, то только max-width или min-width.

    Стили, как обычно, подключаются в заголовке. Скрипт можно подключить по наступлению события onload или в конце HTML-разметки. Файл со скриптом слайдера может выглядеть так:

    <!DOCTYPE html>
    <html lang="ru">
    <head>
    	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    	<meta name="viewport" content="width=device-width; initial-scale=1.0">
    	<title>Simple slider</title>
    	<!-- подключение стилей -->
    	<link rel="stylesheet" type="text/css" href="sim-slider-styles.css">
    </head>
    <body>
    	…
    	<div class="sim-slider">
    		<!-- здесь ваш слайдер -->
    		…
    	</div>
    	…
    	<footer>
    	…
    	</footer>
    <!-- подключение слайдера -->
    <script src="sim-slider.js"></script>
    <!-- вызов слайдера -->
    <script>new Sim()</script>
    </body>
    </html>
    

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

    <div class="sim-slider" id="first">
    	<!-- первый слайдер -->
    	…
    <div class="sim-slider" id="second">
    	<!-- второй слайдер -->
    	…
    <script>new Sim("first"); new Sim("second");</script>
    


    Javascript
    function Sim(sldrId) {
    
    	let id = document.getElementById(sldrId);
    	if(id) {
    		this.sldrRoot = id
    	}
    	else {
    		this.sldrRoot = document.querySelector('.sim-slider')
    	};
    
    	// Slider objects
    	this.sldrList = this.sldrRoot.querySelector('.sim-slider-list');
    	this.sldrElements = this.sldrList.querySelectorAll('.sim-slider-element');
    	this.sldrElemFirst = this.sldrList.querySelector('.sim-slider-element');
    	this.leftArrow = this.sldrRoot.querySelector('div.sim-slider-arrow-left');
    	this.rightArrow = this.sldrRoot.querySelector('div.sim-slider-arrow-right');
    	this.indicatorDots = this.sldrRoot.querySelector('div.sim-slider-dots');
    
    	// Initialization
    	this.options = Sim.defaults;
    	Sim.initialize(this)
    };
    
    Sim.defaults = {
    
    	// Default options for the slider
    	loop: true,     // Бесконечное зацикливание слайдера
    	auto: true,     // Автоматическое пролистывание
    	interval: 5000, // Интервал между пролистыванием элементов (мс)
    	arrows: true,   // Пролистывание стрелками
    	dots: true      // Индикаторные точки
    };
    
    Sim.prototype.elemPrev = function(num) {
    	num = num || 1;
    
    	let prevElement = this.currentElement;
    	this.currentElement -= num;
    	if(this.currentElement < 0) this.currentElement = this.elemCount-1;
    
    	if(!this.options.loop) {
    		if(this.currentElement == 0) {
    			this.leftArrow.style.display = 'none'
    		};
    		this.rightArrow.style.display = 'block'
    	};
    	
    	this.sldrElements[this.currentElement].style.opacity = '1';
    	this.sldrElements[prevElement].style.opacity = '0';
    
    	if(this.options.dots) {
    		this.dotOn(prevElement); this.dotOff(this.currentElement)
    	}
    };
    
    Sim.prototype.elemNext = function(num) {
    	num = num || 1;
    	
    	let prevElement = this.currentElement;
    	this.currentElement += num;
    	if(this.currentElement >= this.elemCount) this.currentElement = 0;
    
    	if(!this.options.loop) {
    		if(this.currentElement == this.elemCount-1) {
    			this.rightArrow.style.display = 'none'
    		};
    		this.leftArrow.style.display = 'block'
    	};
    
    	this.sldrElements[this.currentElement].style.opacity = '1';
    	this.sldrElements[prevElement].style.opacity = '0';
    
    	if(this.options.dots) {
    		this.dotOn(prevElement); this.dotOff(this.currentElement)
    	}
    };
    
    Sim.prototype.dotOn = function(num) {
    	this.indicatorDotsAll[num].style.cssText =
                 'background-color:#BBB; cursor:pointer;'
    };
    
    Sim.prototype.dotOff = function(num) {
    	this.indicatorDotsAll[num].style.cssText =
                 'background-color:#556; cursor:default;'
    };
    
    Sim.initialize = function(that) {
    
    	// Constants
    	that.elemCount = that.sldrElements.length; // Количество элементов
    
    	// Variables
    	that.currentElement = 0;
    	let bgTime = getTime();
    
    	// Functions
    	function getTime() {
    		return new Date().getTime();
    	};
    	function setAutoScroll() {
    		that.autoScroll = setInterval(function() {
    			let fnTime = getTime();
    			if(fnTime - bgTime + 10 > that.options.interval) {
    				bgTime = fnTime; that.elemNext()
    			}
    		}, that.options.interval)
    	};
    
    	// Start initialization
    	if(that.elemCount <= 1) {   // Отключить навигацию
    		that.options.auto = false;
                    that.options.arrows = false; that.options.dots = false;
    		that.leftArrow.style.display = 'none';
                    that.rightArrow.style.display = 'none'
    	};
    	if(that.elemCount >= 1) {   // показать первый элемент
    		that.sldrElemFirst.style.opacity = '1';
    	};
    
    	if(!that.options.loop) {
    		that.leftArrow.style.display = 'none';  // отключить левую стрелку
    		that.options.auto = false; // отключить автопркрутку
    	}
    	else if(that.options.auto) {   // инициализация автопрокруки
    		setAutoScroll();
    		// Остановка прокрутки при наведении мыши на элемент
    		that.sldrList.addEventListener('mouseenter', function() {
                          clearInterval(that.autoScroll)
                    }, false);
    		that.sldrList.addEventListener('mouseleave', setAutoScroll, false)
    	};
    
    	if(that.options.arrows) {  // инициализация стрелок
    		that.leftArrow.addEventListener('click', function() {
    			let fnTime = getTime();
    			if(fnTime - bgTime > 1000) {
    				bgTime = fnTime; that.elemPrev()
    			}
    		}, false);
    		that.rightArrow.addEventListener('click', function() {
    			let fnTime = getTime();
    			if(fnTime - bgTime > 1000) {
    				bgTime = fnTime; that.elemNext()
    			}
    		}, false)
    	}
    	else {
    		that.leftArrow.style.display = 'none';
                    that.rightArrow.style.display = 'none'
    	};
    
    	if(that.options.dots) {  // инициализация индикаторных точек
    		let sum = '', diffNum;
    		for(let i=0; i<that.elemCount; i++) {
    			sum += '<span class="sim-dot"></span>'
    		};
    		that.indicatorDots.innerHTML = sum;
    		that.indicatorDotsAll =
                           that.sldrRoot.querySelectorAll('span.sim-dot');
    		// Назначаем точкам обработчик события 'click'
    		for(let n=0; n<that.elemCount; n++) {
    			that.indicatorDotsAll[n].addEventListener('click', function(){
    				diffNum = Math.abs(n - that.currentElement);
    				if(n < that.currentElement) {
    					bgTime = getTime(); that.elemPrev(diffNum)
    				}
    				else if(n > that.currentElement) {
    					bgTime = getTime(); that.elemNext(diffNum)
    				}
    				// Если n == that.currentElement ничего не делаем
    			}, false)
    		};
    		that.dotOff(0);  // точка[0] выключена, остальные включены
    		for(let i=1; i<that.elemCount; i++) {
    			that.dotOn(i)
    		}
    	}
    };
    



    Все изображения взяты из открытых источников

    Спасибо за внимание!
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 18

      +1

      Интересно бы увидеть реализации без js. Только CSS + HTML, только хардкор )))

        0
        Да, я тоже почему-то ждал в статье именно этого результата. И даже знаю, что такое возможно, так как однажды пытался, но получилось что-то слишком корявое:
        jsfiddle.net/7ocs925a

        Там, как мне кажется, нужно еще добавить стрелки влево-вправо. А вот пролистывание клавишами без JS, кажется, сделать не получится. Ну и «карусель», чтобы после последнего запускалась первая, тоже сделать непонятно как. Хотя изначально радиокнопки все это предусматривают:
        jsfiddle.net/wht6vjay/6

        В общем, много чего надо допиливать, и у меня изначально идея была другая: не галерея картинок по кругу, а «карточка»: картинка+текст, то есть они предусматривают не прокрутку, а вдумчивое изучение, поэтому там цифры, чтобы легче было ориентироваться.
          0
          А вот пролистывание клавишами без JS, кажется, сделать не получится.

          Странно. Я тоже на radio делал. У меня табом переключается.

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

              Я понял почему у меня через таб работает. Radio тут вообще не участвует. У меня слайды это ссылки и таб просто прокручивает до следующего слайда.

        +1

        А Javascript то где?

          0

          Так в конце статье же, перед фразой про открытые источники изображений.

            0

            Я подозреваю что это не всё:


            <script>new Sim(“first”); new Sim(“second”);</script>
              0
              Код Javascript, а также HTML и CSS с результатом находятся во фрейме JSFiddle перед фразой про открытые источники изображений
                0

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


                JavaScript же можно под спойлером опубликовать как и CSS. Чтоб не лезть за этим на JSFiddle.

                  +1
                  JavaScript вставил
          +1
          Автор уже опубликовал скрипт карусели, который также использует только CSS и Javascript. Теперь...

          Также вызвала вопрос эта первая фраза. Какие по-Вашему средства используют другие слайдеру? Ну и по-существу вопроса. В свое время разработал код вертикального листанция экранов. Все было очень просто. Но когда я попробовал протестировать на Андроиде ту меня ожидало разочарование. Не знаю как сейчас но на тот момент был баг андроида, который не генерировал событие при окончании touch и его пришлось реализовывать прослушиванием других событий что сразу сделало код глючным и сложным. Так что в популярный свайперах/слайдерах поддержка совместимости одно из главных преимуществ

            +1
            Имеется ввиду, что скрипт не использует библиотеки и плагины, например jQuery
              +1
              По видимому, баг исправлен. Карусель — пролистывание касанием работает устойчиво. Проверено на тел. Samsung J7, Android ver.8.1.0
                0

                У меня андроид 7 планшет leanovo первый слайд свайпится с первого раза все последующие только со второго

                  0
                  Скрипт написан только что и у автора нет большого опыта работы с мобильными устройствами, все настройки установлены “на глазок” (обработчик события touchmove). Попробуйте слегка изменить расстояние между точками касания и отпускания экрана — уменьшить до 10-12 пикс. (сейчас 15), а время прикосновения увеличить до 100-120 мс (сейчас 75). Это должно увеличить надёжность срабатывания.
              +1

              Слайдер «только на CSS и JavaScript» — это сильно. :)
              А я-то ожидал чего-то на Котлине и в докер-контейнере.

                0

                Вашим слайдером невозможно пользоваться с клавиатуры (дивы вместо кнопок), ваш код местами битый из-за типографских кавычек. Я всё больше боюсь за Хабр, после таких статей. Пожалуйста, не надо больше, ведь кто-нибудь и правда возьмёт этот код.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое