пятница, 22 августа 2014 г.

[вёрстка] Как сделать слайдер на CSS и HTML, без Javascript

В одной из предыдущих статей мы рассмотрели, как сделать вкладки на CSS при помощи трюка с радио-кнопками. В этой статье мы при помощи аналогичного подхода создадим симпатичный слайдер, не требующий Javascript для работы.

Слайдеры, как правило делаются с использованием Javascript. Обычно для этого задействуют библиотеку JQuery. Хотя CSS и не позволяет создать полнофункциональный слайдер с кучей возможностей, таких как анимация по таймеру, листание пальцем на тач-скрине и т.п., во многих случаях такие продвинутые возможности и не требуются.

Простой слайдер для блога гораздо проще сверстать на чистом HTML и CSS, чем задействовать для этого возможности Javascript. Во-первых, код стилей слайдера получится гораздо проще и понятнее, чем код слайдера на Javascript. Во-вторых, та часть пользователей, которая параноидально не доверяет сайтам и заходит на незнакомые сайты только с аддоном NoScript, вырезающим весь JS-код, тоже сможет воспользоваться вашим слайдером.

Поехали!

Простой слайдер с анимированным переключением кадров

Примечание: В этом примере я буду ориентироваться на самые новые возможности CSS. Код не предназначен для работы в старых браузерах.

Начнём создание слайдера с такого кода:

<div class='sliderA'>
    <input type="radio" name="slider1" id="slider1_1" checked="checked">
    <label for="slider1_1"></label>
    <div></div>

    <input type="radio" name="slider1" id="slider1_2">
    <label for="slider1_2"></label>
    <div></div>

    <input type="radio" name="slider1" id="slider1_3">
    <label for="slider1_3"></label>
    <div></div>

    <input type="radio" name="slider1" id="slider1_4">
    <label for="slider1_4"></label>
    <div></div>
</div>

Контейнер слайдера — div с классом sliderA. Каждый кадр слайдера описывается трёмя тегами:

  • Радиокнопкой (input type="radio"), отвечающей за состояние данного кадра (видно / не видно)
  • Меткой label, отвечающей за отображение кнопки перехода на данный слайдер.
  • Тегом div в котором находится содержимое кадра.

Радиокнопки внутри одного слайдера должны иметь одинаковое имя name. Также, все радиокнопки должны иметь уникальные (различные) идентификаторы id. Метка в поле for должна содержать значение id соответствующей радиокнопки. (Если вам не понятно, почему и зачем всё это делается читайте статью про вкладки. Там всё это объяснено подробно.)

Начинаем работать над стилями. Контейнер:

    .sliderA {
        width: 400px;
        height: 250px;
        border: 1px solid #888;
        position: relative;
        text-align: center;
    }

Мы задаём фиксированные размеры контейнера. Я установил их равными размеру изображений, которые я буду использовать в этом примере. Свойство position: relative необходимо, чтобы задать новую точку отсчёта позиций вложенных контейнеров. Свойство text-align: center я добавил, чтобы выровнять по центру полосу меток-кнопок, которые я буду позиционировать как inline-элементы.

Отображение радиокнопок нам не нужно, скрываем их:

    .sliderA > input {
        display: none;
    }

Оформляем метки-кнопки. Кода много, но ничего сложного нет:

    .sliderA > input + label {
        display: inline-block;
        width: 10px;
        height: 10px;
        border-radius: 8px;
        background: rgba(90, 90, 90, 0.8);
        border: 2px solid rgba(190, 190, 190, 0.8);

        cursor: pointer;

        z-index: 100;
        position: relative;

        margin-right: 4px;
        top: 90%;

        transition: background 0.8s ease-out 0s;
    }

    .sliderA > input + label:hover {
        background: rgba(250, 250, 250, 0.8);
    }

    .sliderA > input:checked + label {
        background: rgba(220, 220, 220, 0.8);
    }

Я устанавливаю свойство display: inline-block, что позволит разместить метки одной строкой и выровнять их по центру как строчные элементы, и вместе с тем задать им фиксированные размеры как блокам. Затем я задаю ширину и высоту, а также радиус скругления углов, цвет фона и цвет границы. Всё это приводит к тому, что наши метки будут отображаться в виде маленьких круглых кнопок.

Свойство cursor позволяет задать внешний вид курсора мыши при наведении на кнопку. Я установил значение pointer, т.е. вид указателя мыши будет такой же, как при наведении на ссылку («указательный палец»).

Свойство z-index необходимо для того, чтобы метки-кнопки лежали поверх кадров слайдера. Для этого же установлено свойство position: relative — иначе z-index не будет работать.

margin-right добавляет отступы между кнопками, а top: 90% сдвигает их в нижнюю часть контейнера. Можно было задать вертикальную позицию кнопок более грамотно, но здесь я ограничусь этим способом.

Также я задаю цвет фона для нажатой кнопки и кнопки, на которую наведена мышь. Свойство transition определяет анимацию для смены фона.

Также нам следовало устранить все пробелы и переводы строк между тегами слайдера, так как при использовании display: inline-block они дадут нам лишние зазоры между кнопками. Так мы поступали в предыдущей статье. Я не стал сейчас этого делать для упрощения восприятия кода HTML.

Получилась вот такая заготовка слайдера:

Добавляем стили для div-ов, в которых будет находиться содержимое кадра:

    .sliderA > div {
        position: absolute;
        top: 0px;
        left: 0px;
        right: 0px;
        bottom: 0px;
        z-index: 0;
    }

Все кадры будут занимать одно и то же положение. position: absolute позволяет изъять блоки из потока и разместить из произвольным образом. top, left, right, bottom задают координаты кадра таким образом, что кадр занимает весь контейнер слайдера целиком. z-index отправляет кадры под кнопки переключения кадров, иначем мы не сможем эти кнопки ни увидеть, ни нажать.

Теперь самая главная часть слайдера — показ и скрытие кадров в зависимости от нажатой кнопки. Традиционный подход скрытия элементов страницы с использованием свойства display: none нам не совсем подходит. Ведь для слайдера хотелось бы сделать плавное переключение кадров, но CSS не позволяет задать анимацию значения display при помощи правил transition.

Для плавного скрытия и появления кадров нам понадобятся два свойства: opacity и visibility; а также упомянутый transition.

Свойство opacity позволяет в виде десятичной дроби задать уровень прозрачности элемента страницы, от 0 (полностью прозрачный) до 1 (полностью непрозрачный). Например, opacity: 0.5 — прозрачность 50%.

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

Чтобы полностью отключить элемент и сделать его прозрачным для щелчков мышью, понадобится второе свойство: visibility: hidden. Однако visibility не позволяет задать частичную прозрачность. Элемент либо виден, либо нет.

Поэтому мы будем при помощи transition анимировать оба свойства, чтобы добиться нужного нам эффекта. Суть метода в следующем:

  • Когда пользователь переключает кадр, новый кадр появляется с visibility: visible, но с opacity: 0.
  • Затем происходит анимация значения opacity у обоих кадров. У старого кадра она плавно опускается до нуля, а у нового — плавно поднимается до единицы.
  • После завершения анимации, visibility старого кадра устанавливается в значение hidden, чтобы он не мешал щелчкам мышью по новому кадру.

Вот такой код у меня получился:

    .sliderA > div {
        visibility: hidden;
        opacity: 0;
        transition: opacity 0.8s ease-out 0.1s, visibility 0.1s ease-out 0.9s;
    }

    .sliderA > input:checked + label + div {
        visibility: visible;
        opacity: 1;
        transition: opacity 0.8s ease-out 0.1s, visibility 0.1s ease-out 0s;
    }
Также я добавил правило для тега p внутри кадра, чтобы сделать подписи к картинкам:
    .sliderA > div > p {
        position: absolute;
        top: 0px;
        left: 0px;
        right: 0px;
        text-align: center;
        color: #fff;
        text-shadow: 1px 1px 2px #000;
    }

Дописываем HTML-код слайдера для нашего примера:

<div class='sliderA'>
    <input type="radio" name="slider1" id="slider1_1" checked="checked">
    <label for="slider1_1"></label>
    <div>
        <p>Восход над островом</p>
        <img src='https://lh3.googleusercontent.com/-XGgw41OSARk/VePicTdAdgI/AAAAAAAAAS4/WeBbxp4ebQg/s400-Ic42/00099_manaisland_1920x1200.jpg' alt=''>
    </div>

    <input type="radio" name="slider1" id="slider1_2">
    <label for="slider1_2"></label>
    <div>
        <p>Озёрный край</p>
        <img src='https://lh3.googleusercontent.com/-aafAKIoTkT4/VePihWk2BHI/AAAAAAAAATA/zQVtiYD_eDc/s400-Ic42/00201_lakejipe_1920x1200.jpg' alt=''>
    </div>

    <input type="radio" name="slider1" id="slider1_3">
    <label for="slider1_3"></label>
    <div>
        <p>Закатная синева</p>
        <img src='https://lh3.googleusercontent.com/-ikbDMRhLc_I/VePkT4XLFtI/AAAAAAAAATg/qaHqQk89RAw/s400-Ic42/00744_laclahachesunset_1920x1200.jpg' alt=''>
    </div>

    <input type="radio" name="slider1" id="slider1_4">
    <label for="slider1_4"></label>
    <div>
        <p>Сельский пейзаж</p>
        <img src='https://lh3.googleusercontent.com/-BLXeHJNyOqw/VePimp_e_wI/AAAAAAAAATQ/BVw_9LFehyU/s400-Ic42/00442_pyrenees_1920x1200.jpg' alt=''>
    </div>

</div>

И получаем вот такой результат:

Восход над островом

Озёрный край

Закатная синева

Сельский пейзаж

Простой слайдер с анимированным переключением кадров, второй вариант

В слайдере можно размещать как обычные фотографии, так и любой текст, ссылки на другие страницы сайта и так далее.

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

Усовершествуем наш слайдер. В шаблон слайдера добавим по еще одной метке для каждого кадра:

<div class='sliderA' >
    <input type="radio" name="slider2" id="slider2_1" checked="checked">
    <label for="slider2_1"></label>
    <div></div>
    <label for="slider2_2"></label>

    <input type="radio" name="slider2" id="slider2_2">
    <label for="slider2_2"></label>
    <div></div>
    <label for="slider2_3"></label>

    <input type="radio" name="slider2" id="slider2_3">
    <label for="slider2_3"></label>
    <div></div>
    <label for="slider2_4"></label>

    <input type="radio" name="slider2" id="slider2_4">
    <label for="slider2_4"></label>
    <div></div>
    <label for="slider2_1"></label>
</div>

Как видите, метка идущая после первого кадра, активирует второй кадр. Метка, расположенная после второго кадра, активирует третий кадр; после третьего — чертвёртый. Последняя метка активирует первый кадр.

Метки мы расположим так, чтобы они перекрывали весь слайдер и лежали выше изображения, но ниже полосы кнопок. Метки прозрачные, поэтому сквозь них видно содержимое кадра. При показе кадра номер N вместе с ним отображается метка для перехода на кадр N + 1. (Для последнего кадра — метка перехода на первый кадр.)

    .sliderA > input + label + div + label {
        display: none;
    }

    .sliderA > input:checked + label + div + label {
        display: block;
        position: absolute;
        top: 0px;
        left: 0px;
        right: 0px;
        bottom: 0px;
        z-index: 50;
    }

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

Восход над островом

Озёрный край

Закатная синева

Сельский пейзаж


У нас получился симпатичный слайдер для фотографий с вкладочным переключением кадров. Такой слайдер отлично подойдёт, например, для публикации фотографий в блоге о путешествиях.

В следующей статье о CSS я рассмотрю другой вариант слайдера: с переключением кадров при помощи кнопок «вперёд» и «назад».

18 комментариев

Анонимный

Подскажите, получится ли прикрутить такой слайдер на http://decoacoustic.ru вместо штатного?

Анонимный

замечательно выходит!!!
Только, скажите пожалуйста, почему этот слайдер не работает при входе на сайт со смартфона?

Анонимный

Последнее сообщение моё. Приношу извинения!!! Всё работает, это были проблемы со смартфоном.

Unknown

А как зделать чтоб изображения сами переключались как слайдшоу?

Анонимный

пасибо

Абсалямов Руслан

Как буд-то не работает у меня слайдер, checked не переключает

Unknown

Возможно ли вмето инпутов использовать div ? например при наведение на блок с боку будет менятся картинка?

No name

Я все с точностью скопировала, но у меня не получился слайдер. На верху 5 точек вертикально и под ними 5 рисунков просто вставлены. Как исправить? Или может помимо этого что то писать надо?

SBTesla


напишите так в .sliderA > input + label у автора неправильно

background: rgba(90, 90, 90, 0.8) none repeat scroll 0 0;
border: 2px solid rgba(190, 190, 190, 0.8);
border-radius: 8px;
cursor: pointer;
display: block;
float: left;
height: 10px;
left: 43%;
margin-right: 4px;
position: relative;
top: 105%;
transition: background 0.8s ease-out 0s;
width: 10px;
z-index: 100;

Анонимный

Спасибо большое! Всё работает, СУПЕР!!!

Анонимный

Спасибо большое! Очень понятное объяснение даже для новичка! Все получилось!

Unknown

Хороший слайдер, скажите будет ли работать на странице html на сайте http://feoparagliding.com ?

Андрей

Прошу разъяснить: почему если не написать
.sliderA > div {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
z-index: 0;
}
то
.sliderA > input + label {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 8px;
background: rgba(90, 90, 90, 0.8);
border: 2px solid rgba(190, 190, 190, 0.8);

cursor: pointer;

z-index: 100;
position: relative;

margin-right: 4px;
top: 90%;

transition: background 0.8s ease-out 0s;
}

не будет корректно работать свойства display: inline-block не будет строить кнопки в линию
top: 80% будет выходить за границы блока родителя, хотя у sliderA position: relative;
В чем связь?

Unknown

Доработал скрипт, добавил автоматическое перелистывание на JS

var inp = document.getElementsByName('slider1');


var sliderInterval = setInterval(nextSlide, 2000);

function nextSlide(){

for( var i = 0; i < inp.length; i++){
if (inp[i].checked == true) {
i++;
if (i != inp.length) {
inp[i].checked = true;
}
else

inp[0].checked = true;

}

}
}

Анонимный

Добрый день. Помогите пожалуйста с этим слайдером. Все сделал как по инструкции - у меня получается картинки друг под другом и радиокнопки между ними.
Учел также поправку из комментария об ошибке - не помогло.
Можете дать код для вставки у кого работает?

Unknown

Спасибо большое, все понятно и просто!

Анонимный

покажите кто-нибудь весь код целиком пожалуйста!!!?

Unknown

О, симпатичный блок комментариев. Поделитесь, где взяли? ))

Отправить комментарий