I have a autoplaying, continuously looping and click/draggable carousel I’ve created using Keen Slider.
This works well, however on mobile the carousel content jumps horizontally when I scroll down the page. This only occurs on the first scroll and is fine after. Tested on iPhone 15 Pro in Safari and Chrome, same result in each.
After some research it looks as though this is in relation to the origin
recalculating as the viewport resizes. You can actually see this on desktop if you shrink/enlarge your browser horizontally. The content jumps, which I don’t mind. But on mobile I think this looks like a bug as it’s just a page scroll – but I imagine caused by the dynamic resizing of the URL bar.
Slides/Origin Doc: https://keen-slider.io/docs#slides-object–number–function–null
I’ve included a code example, where you can see the jump/shift on desktop if you resize your browser. I know my issue is on mobile but hopefully this helps to see the issue and test.
I’m not sure if disabling this is the correct approach but basically I don’t want the content to realign to the left edge (or centre, which is another option) on resize.
I’d really appreciate some help and ideas on the best way to resolve this issue – or at least make it more deliberate.
/* Lazy Load Effect */
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
========================================================================== */
/**
* My overrides for the Keen Slider gallery.
*
* 1. Remove `overflow: hidden` from the slider and add it to the parent. This
* allows the slider to align with the grid but also bleed off the edges of
* the page.
* 2. Align container with the global grid.
*/
.gallery {
margin-bottom: 64px;
overflow: hidden; /* [1] */
padding: 0 16px; /* [2] */
}
.gallery .keen-slider {
overflow: visible; /* [1] */
}
/**
* As the widths for each slide are set in Javascript. We add widths to slides
* before `.keen-slider` has loaded to keep the layout consistent and help with
* the Cumulative Layout Shift (CLS) and performance.
*/
.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
========================================================================== */
/**
* Add a pixelated effect to images while the 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>Slide 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>Slide 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>Slide 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>Slide 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>Slide 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>Slide 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>Slide 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>Slide 8</figcaption>
</figure>
</div>
</div>
</div>
<!-- End Keen Slider -->