CSS слайдер

    С развитием CSS3, возможности верстки растут экспоненциально. Всё больше функционала можно реализовать на «чистом» CSS. В этом посте показан процесс разработки интерактивного циклического слайдера без единой строчки JavaScript. Автоматическая ротация, выбор любого слайда с плавным переходом – на «чистом» CSS. Пример в действии




    Общая информация.


    Стандарты и префиксы

    Свойства transition, animation и transform уже давно, в том или ином виде, реализованы во всех популярных браузерах. 6 июня 2012 года W3C объявил, что эта часть разрабатываемого стандарта CSS 3.0 кардинально меняться не будет, и рекомендовал реализовать её всем браузерам уже сегодня.

    Для front-end разработчиков это означает появление стандарта, на который можно опираться. Теперь не надо бояться, что в будущем какой-либо браузер откажется от своего префиксного нестандартного свойства – ведь оно будет продублировано стандартным свойством и заменит его при необходимости.

    Устаревшие версии Internet Explorer, к которым скоро можно будет отнести даже 9 версию, не поддерживают transition, animation и transform ни в каком виде. Но их доля всё ещё превышает 10%.Для IE7-9 предлагается js-«заглушка», а эффекта плавного переключения между слайдами – ничего.

    Почему CSS, а не JS?

    Есть множество задач, которые можно решить при помощи CSS: интерактивные галереи, многоуровневые выпадающие меню, построение и анимация трёхмерных диаграмм… Зачем же использовать CSS, когда можно все сделать на JS, особенно учитывая массу готовых наработок? Основные аргументы могут быть такими:

    • В большинстве случаев, CSS эффекты работают быстрее, поскольку за их исполнением следят исключительно движки браузеров. Это особенно хорошо заметно на мобильных устройствах.
    • Для реализации задачи не требуется знание JS и вообще любых языков программирования. Правка же CSS, как правило, доступна даже рядовому пользователю. Причём «наломать дров» в CSS значительно сложнее, нежели в JS.


    Реализация


    БЭМ

    Итак, для именования CSS классов использовалась методология Блок Элемент Модификатор (БЭМ). Суть в том, что вёрстка основана на компоновке страницы из независимых блоков. Согласно БЭМ у блока могут быть элементы, но только внутри блока.

    Классы слайдера:
    .slider /* Блок, содержащий ленту изображений */
    .slider__radio /* Радиокнопка */
    .slider__item /* Слайд */
    .slider__img /* Картинка внутри слайда */
    .slider__number-list /* Контейнер с кнопками переключения */
    .slider__number /* Кнопка включения связанного с ней слайда */
    .slider__number-after /* внедрён для поддержки IE7 и IE8, которые не поддерживают псевдоэлементы :after и ::after соответственно */
    .slider_count_X /* Модификатор, определяющий количество слайдов X */
    
    


    Анимация

    Анимационная последовательность по ключевым кадрам для трёх слайдов выглядит следующим образом:
    @keyframes slider__item-autoplay_count_3
    {
    	0%{opacity:0;}
    	10%{opacity:1;}
    	33% {opacity:1;}
    	43% {opacity:0;}
    	100%{opacity:0;}
    }
    
    

    Особенность реализации слайдера в том, что всем слайдам и всем кнопкам присваивается одна и та же анимация:
    slider_count_3 .slider__item,
    slider_count_3 .slider__number-after
    {
    	-moz-animation: slider__item-autoplay_count_3 15s infinite;
    	-webkit-animation: slider__item-autoplay_count_3 15s infinite;
    	-o-animation: slider__item-autoplay_count_3 15s infinite; 
    	animation: slider__item-autoplay_count_3 15s infinite;
    }
    
    

    Такой подход позволяет серьезно сократить объем кода, ведь все анимации пока ещё приходится дублировать их префиксными версиями (@-webkit-keyframes, @-moz-keyframes и @-o-keyframes), а каждую такую «стопку» правил надо отдельно описывать для каждого требуемого (заказчиком) числа слайдов. Если отдельно описывать анимацию ещё и для каждого слайда, то объем кода может составить десятки килобайт.

    Чтобы этого избежать, но последовательно анимировать все слайды и кнопки при помощи одной анимации, достаточно расставить смещение начала анимации во времени для каждой пары слайд + кнопка:
    .slider__item:nth-of-type(2),
    .slider__number:nth-of-type(2) > .slider__number-after
    {
    	-moz-animation-delay:5s;
    	-webkit-animation-delay:5s;
    	-o-animation-delay:5s;
    	animation-delay:5s;
    }
    .slider__item:nth-of-type(3),
    .slider__number:nth-of-type(3) > .slider__number-after
    {
    	-moz-animation-delay:10s;
    	-webkit-animation-delay:10s;
    	-o-animation-delay:10s;
    	animation-delay:10s;
    }
    ...
    
    

    Для первой пары остаётся значение по-умолчанию – нулевое смещение.

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

    В итоге плавный анимированный переход между слайдами выглядит так:






    Пауза при наведении курсора

    Для случая, когда пользователь хочет задержать слайд на экране, но не хочет отключать ротацию, можно использовать режим паузы по наведению курсора над слайдом:
    .slider:hover .slider__item,
    .slider:hover .slider__number-after
    {
    	-moz-animation-play-state: paused;
    	-webkit-animation-play-state: paused;
    	-o-animation-play-state: paused;
    	animation-play-state: paused;
    }
    


    Переключение по клику

    Есть целый ряд CSS «событий», переключающих состояние html элемента. Если говорить о клике мыши, то это появление псевдоклассов :focus, :target, или :checked у одного из элементов страницы. Псевдокласс :focus может быть не более чем у одного элемента на страницу единовременно; псевдокласс :target засоряет историю браузера и требует наличие тега «a»; псевдокласс :checked запоминает состояние до ухода со страницы, плюс, в случае радиокнопок, является дискретным переключателем, когда выбран может быть только один элемент конкретной группы – то, что нужно.
    .slider__radio {стили не выбранной радиокнопки}
    .slider__radio:checked {стили выбранной радиокнопки}
    


    В селекторах ниже уровня 4 переключить состояние произвольного элемента (например, opacity слайда) можно только в связке с радиокнопкой, при помощи селекторов соседей + и ~. Переключить можно как стили соседа, так и стили потомков соседа, но в любом случае сосед должен находиться после радиокнопки.
    /* Стиль первого слайда в состоянии «не выбран» */
    .slider__radio:nth-of-type(1) ~ .slider__item:nth-of-type(1) {
    	opacity: 0.0;
    }
    /* Стиль первого слайда в состоянии «выбран» */
    .slider__radio:nth-of-type(1):checked ~ .slider__item:nth-of-type(1) {
    	opacity: 1.0;
    }
    

    Было использовано переключение opacity слайда – контейнера, который содержит картинку. Это более универсальный способ, чем переключение свойств картинки, поскольку в div-контейнер, в отличие от пустого элемента img, можно поместить любую дополнительную информацию (например, название слайда, или связанное описание, включая ссылки).
    Для слайдов указаны свойства transition, которые позволяют сделать переключение между ними плавным.
    .slider__item 
    {
    	-moz-transition: opacity 0.2s linear; 	
    	-webkit-transition: opacity 0.2s linear; 	
    	-o-transition: opacity 0.2s linear; 
    	transition: opacity 0.2s linear;
    }
    
    

    Остановка ротации при выборе слайда

    При выборе пользователем любого слайда необходимо остановить анимацию всех слайдов и кнопок. Это связано с тем, что приоритет значений свойств запущенной анимации всегда выше всех остальных значений тех же свойств (можно перебивать даже inline свойства с !important`ом).

    Поскольку анимация, пусть и одинаковая по структуре, есть у каждого слайда, а выключать надо анимацию всех слайдов (иначе в плавном переходе будут участвовать три слайда), все радиокнопки надо располагать до первого слайда.
    <input class="slider__radio" id="1" type="radio">
    <input class="slider__radio" id="2" type="radio">
    <input class="slider__radio" id="3" type="radio">
    ...
    <div class="slider__item">...</div>
    
    

    Более того, все кнопки (лейблы радиокнопок) надо группировать в отдельном блоке и помещать после радиокнопок, иначе могут возникнуть проблемы с универсальным позиционированием лейблов для произвольного числа слайдов.

    Остановка анимации всех слайдов и кнопок при выборе любого слайда задаётся следующим образом:
    .slider__radio:checked ~ .slider__item,
    .slider__radio:checked ~ .slider__number-list > .slider__number-after
    {
    	opacity: 0.0;
    	-moz-animation: none;
    	-webkit-animation: none;
    	-o-animation: none;
    	animation: none;
    }
    
    

    Произвольное число слайдов

    Сделать универсальный слайдер под любое число слайдов невозможно, потому что под каждое число требуется своя «стопка» CSS-правил анимации. Каждую такую «стопку» (если она описана) можно подключать через модификатор блока slider:
    .slider_count_X
    

    где X – число слайдов.

    Для поддержки некоторых старых браузеров первый слайд не анимируется. По этой причине контейнер первой картинки имеет opacity всегда равный 1.0. Возникает проблема: при плавном переключении двух других слайдов между собой, первый просвечивает (это может быть и background родителя блока slider). Для удаления эффекта просвечивания устанавливается задержка transition-delay для всех слайдов, кроме выбранного; для выбранного же устанавливается z-index больше, чем у всех остальных:
    .slider__item {
    	opacity: 1.0;
    	position: relative;
    	-moz-transition: opacity 0.0s linear 0.2s;
    	-webkit-transition: opacity 0.0s linear 0.2s;
    	-o-transition: opacity 0.0s linear 0.2s;
    	transition: opacity 0.0s linear 0.2s;
    }
    
    .slider__radio:nth-of-type(1):checked ~ .slider__item:nth-of-type(1),
    .slider__radio:nth-of-type(2):checked ~ .slider__item:nth-of-type(2),
    .slider__radio:nth-of-type(3):checked ~ .slider__item:nth-of-type(3),
    .slider__radio:nth-of-type(4):checked ~ .slider__item:nth-of-type(4),
    .slider__radio:nth-of-type(5):checked ~ .slider__item:nth-of-type(5){
    	-moz-transition: opacity 0.2s linear;
    	-webkit-transition: opacity 0.2s linear;
    	-o-transition: opacity 0.2s linear;
    	transition: opacity 0.2s linear;
    	z-index: 6;
    }
    

    Чтобы слайды не конфликтовали с другими элементами сайта (например, не перекрывали выпадающее меню с z-index менее или равным 6), создаём свой контекст (stacking context) для блока путём задания минимально, необходимого для видимости, z-index`а:
    .slider
    {
    z-index: 0;
    }
    

    image

    Итак


    Уже сегодня, без навыков программирования и специализированных библиотек, до своей окончательной стандартизации, CSS 3.0 позволяет реализовывать сложные и интересные задачи. Описанный интерактивный слайдер, на текущий момент, полностью работоспособно у 80% пользователей рунета. Для большей части оставшихся пользователей, а именно для пользователей браузеров IE7-9, можно использовать js-«заглушку», которая реализует основной функционал слайдера.

    Рабочий пример можно увидеть здесь.
    Поделиться публикацией

    Похожие публикации

    Комментарии 45
      +7
      какой изощренный способ обойти AdBlocker
        +6
        У вас в баннере ошибка — фирма называется Peg-Perego
          +4
          Сразу видно, у кого есть дети ))
            0
            У меня пока нету :)
            Просто я занимался детскими товарами.
            0
            А я подумал что это китайский аналог )
            +1
            у вас на сайте с рабочим примером есть особенность во взаимодействии слайдера и основного выпадающего меню (.submenu): выпадающее меню явно просит большее значение z-index (заметно после переключения слайдов вручную).
              +1
              Спасибо. Исправления требует скорее слайдер.

              Чтобы слайды не конфликтовали с другими элементами сайта (например, не перекрывали выпадающее меню с z-index менее или равным 6), создаём свой контекст (stacking context) для блока путём задания минимально, необходимого для видимости, z-index`а:
              .slider
              {
              z-index: 0;
              }
              


              Внес в статью.
              +1
              Отлично сделано: при том что у меня в файрфоксе зарезано всё что можно (и немного того, что нельзя) этот вариант всё равно работает.
                0
                Это здорово конечно, но на мой взгляд излишне. Все равно придется дублировать вся на JS для IE. Зачем делать двойную работу? Ради внутренней красоты?
                  +1
                  1) показать, что это возможно
                  2) что через годиков X можно будет жить без JS
                  3) это будет работать (если я верно понял) например для phonegap или HTML5+CSS3 only системы (интерфейс для информационного ларька например — почему нет?)
                    +1
                    3) это будет работать (если я верно понял) например для phonegap или HTML5+CSS3 only системы (интерфейс для информационного ларька например — почему нет?)

                    Будет, без тормозов. Зайдите со смартфона по той же ссылке.
                      +1
                      Зашел. Действительно без тормозов (китайский 1Ггцовый андроид)… Так что всё таки замечательно.
                  • НЛО прилетело и опубликовало эту надпись здесь
                      +3
                      Господа разработчики, сделайте свой вклад в развитие ИЕ! Не нужно дублировать все, пусть в нем работает все, но отображается попроще, поугловатее… так он сам или умрет или подтянется.
                      • НЛО прилетело и опубликовало эту надпись здесь
                          +1
                          Для ИЕ как раз реализована достаточно примитивная заглушка, пользователь несведущий в JS может её не трогать и оставлять в ИЕ все как есть, но при этом он имеет возможность вносить значительные изменения в поведение слайдера посредством только CSS. Разве это не прекрасно? :)

                          Назло как раз действует ИЕ, ставя разработчиков в неудобную позу, когда они вынуждены отказываться от новых технологий в пользу консервативного браузера. Действительно, не дублировать же все для остальных браузеров.
                          • НЛО прилетело и опубликовало эту надпись здесь
                              0
                              Очень полезное свойство transition например.

                              IE10 именно пытается, кроме того он еще долго будет вытеснять свои младшие версии.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                  0
                                  Довольно часто эффект плавного появление/исчезновения просто необходим для привлечения внимания. Вот тут и придется городить скрипты для пользователей ИЕ, а раз уж они (скрипты) есть, зачем городить CSS для каких-то там остальных :) браузеров.

                                  ИЕ8 и ИЕ9 вместе составляют более 10% — это существенно, а ИЕ10 даже на горизонте еще не видно.
                                  • НЛО прилетело и опубликовало эту надпись здесь
                                      0
                                      Привлечение внимания важно не только в маркетинге, но и в юзабилити интерфейса, и тот же transition с этой задачей хорошо справляется, во всех браузерах, на всех устройствах, причем на мобильных значительно лучше JS. Можно даже сказать, что на мобильных устроуствах JS плохо справляется, а в каких-то случаях вообще не справляется с этой задачей.

                                      Какой предлагаете выход?
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                          0
                                          Транзишны (читаем анимация) — это не только украшение и проектировать интерфейс и «с ними» и «без них» может быть или накладно или неэффективно или неудобно для пользователя. С ними гораздо удобнее и понятнее, так почему их не использовать… потому, что ИЕ? :)
                                          • НЛО прилетело и опубликовало эту надпись здесь
                                              0
                                              Например уведомление об успешном выполнении действия можно показать ненавязчиво сверху/сбоку, не перекрывая интерфейс, при этом его нужно анимировать, чтобы оно было заметно. А можно без анимации — тогда посередине окна, поверх интерфейса, т.с. модально.
                                                0
                                                Вот еще пример — хабрапанель справа, представьте, что она меняет скроллинг без анимации, не сразу сообразишь в какую часть беседы попал. Пусть это не кажется критичным, но если к этому привык, без этого уже сложно.
                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                    0
                                                    Юзеры ИЕ, как правило — заложники корпоративной службы безопасности или лицензионной политики, они запросто могут привыкнуть к современным интерфейсам на домашнем компьютере, планшетах, смартфонах и т.п.
                      +1
                      В CSS версии ниже 4.0 переключить состояние...

                      O_O неужели я так много сегодня проспал?
                        +1
                        У меня для вас еще одна новость — CSS4 просто не существует.
                        • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            Пардон, ориентир был на этот драфт: www.w3.org/TR/2012/WD-selectors4-20120823/
                            • НЛО прилетело и опубликовало эту надпись здесь
                                0
                                Да, корректнее сказать: селекторы 4го уровня.

                              • НЛО прилетело и опубликовало эту надпись здесь
                                • НЛО прилетело и опубликовало эту надпись здесь
                                +2
                                При наведении курсора, когда меняется слайд, наблюдаем такую картину:

                                image
                                  0
                                  Это же пауза при наведении.
                                    0
                                    Да, слайдер ставится на паузу, но при наведении курсора, когда меняется слайд, анимация до конца не срабатывает, останавливается изменение opacity.
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                        0
                                        Есть мнение, что лучше было бы дать переходу «доиграть» до логического завершения и застыть уже в этой фазе.
                                        Скорее всего и это можно реализовать, подождем автора.

                                        Попутно вопрос — а может правильнее вернуть предыдущий слайд? :) Ведь пользователь скорее всего вёл мышь на него.

                                        А сейчас у пользователя есть выбор, открыть предыдущий слайд или следующий, обе кнопки подсвечены, оба слайда видны.
                                        • НЛО прилетело и опубликовало эту надпись здесь
                                            0
                                            Абсолютно верно замечено.
                                    0
                                    Подскажите, а как создать переключатель не на определенный слайд, а просто на следующий?

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

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