CSS3-эффект «колоды карт» для изображений

Будь в курсе

subscrible
Скидка 5%
по подписке
Автор
Куликов
Александр
веб-программист
Все великое начинается с малого

Довольно часто в интернете можно встретится с интересными эффектами на сайте и многие из них нацелены на то, чтобы сфокусировать на себе интерес пользователя и задержать его на сайте как можно дольше (Youtube: «10 часов с гипно-жабой»).

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

Идея

С разработкой одного из таких эффектов довелось столкнуться нашей команде технической поддержки. Клиент — довольно прогрессивный дизайнер, работающий на зарубежный рынок, и ему было важно, чтобы работы, представленные на его сайте могли заинтересовать не только визуальным содержимым, но и функциональным. Таким образом было составлено тех. задание, на эффект «зависания изображений», словно привет из 2000-х когда в Windows после победы в косынке мы наблюдали следующее:

Идея эффекта в том, чтобы прокручивая страницу изображения оставляли за собой плавный «хвост» из своих копий, буд-то сдвинута колода карт.

ГОТОВЫЙ ПРИМЕР

Как это работает

Чтобы реализовать данный эффект необходимо было сперва создать несколько копий изображений и поместить их под главное изображение. Для этого используем метод .clone(), и забегая вперед скажу, что нам понадобится знать количество изображений поэтому мы объявим один раз переменную для количества изображений и будем ее использовать. Создаем простейший цикл создания копий изображений:

 var img_count = 4; $('.img-block').each(function(){ for (i = 1; i <= img_count; i++) { $(this).find('img:last-child') .clone() .addClass("newImg"+i) .prependTo(this); }}); 

 

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

img[class^="newImg"]{ position: absolute; transition: 0.2s; } 

 

Теперь необходимо добавить смещение при скроллинге. Для этого создадим 3 функции: для скроллинга вверх, вниз и для возвращения картинок назад. Для смещения будем использовать css стиль translate3d, чтобы мы могли позиционировать картинки как нам необходимо не изменяя базовые стили положения изображений:

 function moveBtm(img_count, current){ for (var i = 2; i <= img_count; i++) { j = i+i; $('.newImg'+i).css('transform','translate3d(0, '+current*j+'px, 0)'); } } 

 

В функцию добавляем цикл обхода каждого изображения. В смещении будем использовать разницу положения страницы от начала скроллинга до конца, за это отвечает переменная current. Таким образом мы получим разное расстояние смещения при разной силе скролла. А чтобы еще больше усилить эффект смещения мы умножим его на порядковый номер изображения, таким образом картинки не будут складываться в единый блок и будут смещаться друг за другом. С помощью такой манипуляции j = i+i (где i — порядковый номер изображения) мы можем регулировать отступы картинок друг за другом и они будут иметь визуально правильную разницу отступа. Цикл стартуем со второго изображения, поскольку нам необходимо, чтобы первая картинка была неподвижной.

 

Тоже самое делаем и для скролла вниз:

function moveTop(img_count, current){ for (var i = 2; i <= img_count; i++) { j = i+i; $('.newImg'+i).css('transform','translate3d(0, -'+current*j+'px, 0)'); } } 

 

С той лишь разницей, что по оси Y мы делаем смещение в минус.

Далее нам необходимо сбросить стиль translate3d иначе картинки не будут возвращаться назад до конца:

function clear(img_count){ for (var i = 2; i <= img_count; i++) { $('.newImg'+i).css('transform','translate3d(0, 0, 0)'); } }

Проблемы

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

К тому же при таком скроллинге картинки будут грубо скакать и добиться плавности будет очень сложно.

Решение с помощью js плагинов

Чтобы это исправить подключим плагин Smooth Scrollbar и реализуем плавную прокрутку на странице. Также сразу добавим плагин Overscroll, входящий в состав данного расширения, и когда пользователь прокрутит страницу до конца она не будет резко упираться в край экрана.

var Scrollbar = window.Scrollbar; Scrollbar.use(window.OverscrollPlugin) const scrollbar = Scrollbar.init(document.querySelector('body'), { damping: 0.08, plugins: { overscroll: { effect: 'bounce', } }, });

 

После подключения плагина Smooth Scrollbar стандартный метод scroll() будет выдавать нам пустое значение, это особенность работы плагина, но разработчики плагина продумали это и добавили собственный метод для прослушивания скролла. Добавляем переменную для записи в нее значения текущей позиции страницы и слушаем дальнейшие действия пользователя с помощью метода scrollbar.addListener():

CurrentScroll = 0; scrollbar.addListener(() => { var offset = scrollbar.offset.y; var NextScroll = offset; if ((NextScroll > CurrentScroll) && (offset != 0)){ current = NextScroll - CurrentScroll; moveBtm(img_count, current); } else if (offset != 0) { current = CurrentScroll - NextScroll; moveTop(img_count, current); } CurrentScroll = NextScroll; setTimeout(function(){ clear(img_count); }, 400); });

 

Поскольку scroll() не работает, то в плагине также присутствует метод для отслеживания позиции страницы scrollbar.offset. С его помощью вычисляем наш current по простой формуле:

 current = NextScroll - CurrentScroll - если крутим вниз current = CurrentScroll - NextScroll - если крутим вверх 

 

Чтобы понять в какую сторону скроллится страница просто сравниваем прошлое положение и новое:

 если NextScroll > CurrentScroll - то крутится вниз, иначе вверх 

 

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

$(document).ready(function(){ var img_count = 4; $('.img-block').each(function(){ for (i = 1; i <= img_count; i++) { $(this).find('img:last-child').clone().addClass("newImg"+i).prependTo(this); } }); function moveBtm(img_count, current){ for (var i = 2; i <= img_count; i++) { j = i+i; $('.newImg'+i).css('transform','translate3d(0, '+current*j+'px, 0)'); } } function moveTop(img_count, current){ for (var i = 2; i <= img_count; i++) { j = i+i; $('.newImg'+i).css('transform','translate3d(0, -'+current*j+'px, 0)'); } } function clear(img_count){ for (var i = 2; i <= img_count; i++) { $('.newImg'+i).css('transform','translate3d(0, 0, 0)'); } } var Scrollbar = window.Scrollbar; Scrollbar.use(window.OverscrollPlugin) const scrollbar = Scrollbar.init(document.querySelector('body'), { damping: 0.08, plugins: { overscroll: { effect: 'bounce', } }, }); CurrentScroll = 0; scrollbar.addListener(() => { var offset = scrollbar.offset.y; var NextScroll = offset; if ((NextScroll > CurrentScroll) && (offset != 0)){ current = NextScroll - CurrentScroll; moveBtm(img_count, current); } else if (offset != 0) { current = CurrentScroll - NextScroll; moveTop(img_count, current); } CurrentScroll = NextScroll; setTimeout(function(){ clear(img_count); }, 400); }); }); 
Добавить комментарий