Вопрос или проблема
У меня есть автопроигрывающий, постоянно работающий и кликаемый/перетаскиваемый карусель, который я создал с использованием Keen Slider.
Это работает хорошо, однако на мобильных устройствах содержимое карусели скачет горизонтально, когда я прокручиваю страницу вниз. Это происходит только при первом скролле, после чего все в порядке. Протестировано на iPhone 15 Pro в Safari и Chrome, результат одинаковый в каждом.
После некоторых исследований похоже, что это связано с origin
, пересчитывающимся при изменении размера области просмотра. Это можно увидеть и на настольном компьютере, если уменьшить или увеличить браузер по горизонтали. Содержимое скачет, что меня не беспокоит. Но на мобильном телефоне это выглядит как ошибка, так как это просто прокрутка страницы – но я предполагаю, что это вызвано динамическим изменением размера адресной строки.
Документация по слайдам/оригинам: https://keen-slider.io/docs#slides-object–number–function–null
Я включил пример кода, где вы можете увидеть скачок/сдвиг на настольном компьютере, если вы измените размер браузера. Я знаю, что моя проблема на мобильных, но надеюсь, это поможет увидеть проблему и протестировать.
Я не уверен, что отключение этого – правильный подход, но в основном я не хочу, чтобы содержимое выравнивалось к левому краю (или в центре, что является другим вариантом) при изменении размера.
Я был бы очень признателен за помощь и идеи по лучшему способу решения этой проблемы – или, по крайней мере, сделать ее более предсказуемой.
/* Эффект ленивой загрузки */
const pixelImage = document.querySelectorAll(".pixel-load")
pixelImage.forEach(div => {
const img = div.querySelector("img")
function loaded() {
div.classList.add("loaded")
}
if (img.complete) {
loaded()
} else {
img.addEventListener("load", loaded)
}
})
/* Keen Slider */
var animation = { duration: 40000, easing: (t) => t }
new KeenSlider("#gallery-slider", {
loop: true,
mode: "free",
slides: {
perView: 1.5,
renderMode: "precision",
spacing: 8
},
breakpoints: {
'(min-width: 768px)': {
slides: {
perView: 3,
spacing: 8
}
},
'(min-width: 1024px)': {
slides: {
perView: 4,
spacing: 8
}
}
},
created(s) {
document.getElementById("gallery-slider").classList.add("loaded");
s.moveToIdx(4, true, animation);
},
updated(s) {
s.moveToIdx(s.track.details.abs + 4, true, animation);
},
animationEnded(s) {
s.moveToIdx(s.track.details.abs + 4, true, animation);
}
})
/* ==========================================================================
#BASE
========================================================================== */
html {
font-size: 62.5%;
margin: 0;
padding: 0;
}
body {
font-size: 12px;
font-family: "Arial", sans-serif;
margin: 0;
padding: 64px 0 0;
text-transform: uppercase;
}
h2 {
font-size: 12px;
font-weight: 400;
margin: 0 16px 16px;
padding: 0;
}
figure {
margin: 0;
padding: 0;
}
img {
height: auto;
width: 100%;
max-width: 100%;
}
/* ==========================================================================
#KEEN SLIDER
========================================================================== */
.keen-slider {
display: flex;
align-content: flex-start;
overflow: hidden;
position: relative;
touch-action: pan-y;
user-select: none;
width: 100%;
-webkit-tap-highlight-color: transparent;
}
.keen-slider .keen-slider__slide {
min-height: 100%;
overflow: hidden;
position: relative;
width: 100%;
}
/* ==========================================================================
#GALLERY
========================================================================== */
/**
* Мои переопределения для галереи Keen Slider.
*
* 1. Удалите `overflow: hidden` из слайдера и добавьте его к родителю. Это
* позволяет слайдеру выравниваться с сеткой, но также перекрывать края
* страницы.
* 2. Выравните контейнер с глобальной сеткой.
*/
.gallery {
margin-bottom: 64px;
overflow: hidden; /* [1] */
padding: 0 16px; /* [2] */
}
.gallery .keen-slider {
overflow: visible; /* [1] */
}
/**
* Поскольку ширины для каждого слайда устанавливаются в Javascript. Мы добавляем ширины слайдам
* до того, как `.keen-slider` загрузился, чтобы сохранить макет последовательным и помочь
* с Cumulative Layout Shift (CLS) и производительностью.
*/
.keen-slider:not(.loaded) .keen-slider__slide {
width: calc((100vw / 1.5) - 24px);
}
@media(min-width: 48em) {
.keen-slider:not(.loaded) .keen-slider__slide {
width: calc((100vw - 48px) / 3);
}
}
@media(min-width: 64rem) {
.keen-slider:not(.loaded) .keen-slider__slide {
width: calc((100vw - 56px) / 4);
}
}
/* ==========================================================================
#PIXEL LOAD
========================================================================== */
/**
* Добавьте пиксельный эффект к изображениям во время загрузки.
*/
.pixel-load {
overflow: hidden;
position: relative;
}
.pixel-load__preload img {
image-rendering: pixelated;
position: absolute;
inset: 0;
opacity: 1;
pointer-events: none;
}
.loaded .pixel-load__preload img {
animation: loaded .32s .16s steps(1, end) both;
}
@keyframes loaded {
0% {scale: 2;}
33% {scale: 1.5;}
66% {scale: 1;}
100% {opacity: 0; z-index: 1;}
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/keen-slider.min.js"></script>
<!-- Keen Slider -->
<div class="gallery">
<div id="gallery-slider" class="keen-slider">
<div class="keen-slider__slide">
<figure data-label="Hover Label 1" class="has-label">
<div class="pixel-load">
<div class="pixel-load__preload">
<img src="https://placebeard.it/18/24" width="18" height="24" loading="eager">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Слайд 1</figcaption>
</figure>
</div>
<div class="keen-slider__slide">
<figure data-label="Hover Label 2" class="has-label">
<div class="pixel-load">
<div class="pixel-load__preload">
<img src="https://placebeard.it/18/24" width="18" height="24" loading="eager">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Слайд 2</figcaption>
</figure>
</div>
<div class="keen-slider__slide">
<figure data-label="Hover Label 3" class="has-label">
<div class="pixel-load">
<div class="pixel-load__preload">
<img src="https://placebeard.it/18/24" width="18" height="24" loading="eager">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Слайд 3</figcaption>
</figure>
</div>
<div class="keen-slider__slide">
<figure data-label="Hover Label 4" class="has-label">
<div class="pixel-load">
<div class="pixel-load__preload">
<img src="https://placebeard.it/18/24" width="18" height="24" loading="eager">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Слайд 4</figcaption>
</figure>
</div>
<div class="keen-slider__slide">
<figure data-label="Hover Label 5" class="has-label">
<div class="pixel-load">
<div class="pixel-load__preload">
<img src="https://placebeard.it/18/24" width="18" height="24" loading="eager">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Слайд 5</figcaption>
</figure>
</div>
<div class="keen-slider__slide">
<figure data-label="Hover Label 6" class="has-label">
<div class="pixel-load">
<div class="pixel-load__preload">
<img src="https://placebeard.it/18/24" width="18" height="24" loading="eager">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Слайд 6</figcaption>
</figure>
</div>
<div class="keen-slider__slide">
<figure data-label="Hover Label 7" class="has-label">
<div class="pixel-load">
<div class="pixel-load__preload">
<img src="https://placebeard.it/18/24" width="18" height="24" loading="eager">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Слайд 7</figcaption>
</figure>
</div>
<div class="keen-slider__slide">
<figure data-label="Hover Label 8" class="has-label">
<div class="pixel-load">
<div class="pixel-load__preload">
<img src="https://placebeard.it/18/24" width="18" height="24" loading="eager">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Слайд 8</figcaption>
</figure>
</div>
</div>
</div>
<!-- Конец Keen Slider -->
</div>.
Ответ или решение
Проблема с горизонтальным прыжком карусели Keen Slider на мобильных устройствах при начальной прокрутке страницы может показаться незначительной, но она может негативно повлиять на пользовательский опыт. Обсудим основные аспекты, которые могут помочь в поиске решения этой проблемы.
1. Понимание проблемы
Карусели с автоматическим проигрыванием, как ваша, могут проявлять нестабильное поведение на мобильных устройствах из-за динамического изменения размеров viewport. При прокрутке страницы на мобильных устройствах адресная строка браузера может скрываться или появляться, что приводит к изменению размеров окна. Это может вызвать перерасчет начальной позиции, что и приводит к горизонтальному сдвигу содержимого карусели.
2. Причины сдвига
- Перерасчет размеров: При первой прокрутке браузера меняются размеры
viewport
, из-за чего перерассчитываетсяorigin
карусели. Это приводит к тому, что контент может изменять свои координаты. - Масштабирование: Ваша карусель настроена на автоматическое воспроизведение и может плохо реагировать на изменения в пропорциях окна, что дополнительно усиливает эффект сдвига.
3. Возможные решения
a. Отключение перерасчета origin
Если это не критично для вашего дизайна, вы можете попробовать отменить перерасчет origin
при изменении размеров viewport. Однако стоит учитывать, что это может негативно повлиять на ориентацию слайдов при изменении размеров окна.
b. Дебаунс события прокрутки
Используйте дебаунс на обработчике событий resize
для плавного изменения размеров, что может минимизировать эффект сдвига. Пример реализации:
let resizeTimer;
window.addEventListener('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
// Обновление карусели или переинициализация
slider.update();
}, 250); // Задержка в 250 мс
});
c. Использование CSS-свойства transform
Другая возможность – это использование свойства CSS transform
во время изменения размеров экрана. Это может помочь сохранить расположение слайдов в более стабильном состоянии.
.keen-slider {
transition: transform 0.3s ease-in-out; /* Плавный переход при изменении размеров */
}
d. Обновление на мобильных устройствах
Для мобильных устройств можно настроить иные правила, чтобы изменить количество отображаемых слайдов или их размеры. Например, можно адаптировать код в зависимости от ширины экрана и выставлять ширину слайдов фиксированной, чтобы избежать перерасчета:
breakpoints: {
'(max-width: 767px)': {
slides: {
perView: 1, // Указать одно отображаемое значение на мобильных
spacing: 4
}
}
}
4. Тестирование и оптимизация
Регулярное тестирование на различных устройствах и браузерах позволит выявить дополнительные проблемы и вовремя их устранить. Используйте инструменты разработчика для мониторинга производительности и поведения слайдера при изменении размеров.
Заключение
Проблема с прыжками карусели Keen Slider на мобильных устройствах может быть решена через различные подходы, включая оптимизацию обработчиков событий, настройки CSS и адаптацию логики JavaScript. Оценив ваши требования и важность пользовательского опыта, вы сможете выбрать оптимальный путь для решения данной проблемы.