I have an autoplaying, smooth carousel, which isis also draggable on desktop. To achieve this I use Keen-Slider. And this all works how I need it to when viewing in a desktop browser.
The problem I have occurs when viewing the page on my mobile device (iPhone 15). Tested on iOS in Safari and Chrome. Initially the page loads and behaves as expected and if left untouched will continue to do so.
The Problem
However as soon as I scroll down the page a pixel or two, the carousel will ‘jump’ to the edge of one of the slides within it – I assume this is the closest one to the left edge of the page. Almost like it’s snapping to the nearest slide after scroll.
The Cause
It’s taken me a bit to figure out why but I’m positive this is down to the Mobile Address Bars resizing as you begin to scroll.
This only happens on the first scroll though! After that, you can scroll up/down as much as you like with the Address Bar resizing and the carousel will continue to behave as intended. Almost like it needs that first scroll to recognise the behaviour.
So I think I’ve got to the bottom of the cause of the issue – but now I can’t find a way to fix it.
Thanks in advance and really hope someone can help with this!
/* ==========================================================================
#LAZY LOAD IMAGES
========================================================================== */
/**
* Class to animate/transition an image into view once it has been loaded.
*/
const pixelImage = document.querySelectorAll(".pixel-load")
const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
const img = document.querySelector(".pixel-load > img")
function loaded() {
entry.target.classList.toggle("loaded", entry.isIntersecting)
}
if (img.complete) {
loaded()
} else {
img.addEventListener("load", loaded)
}
if (entry.isIntersecting) observer.unobserve(entry.target)
})
},
{
threshold: 0
}
)
pixelImage.forEach(image => {
observer.observe(image)
})
/* ==========================================================================
#KEEN SLIDER
========================================================================== */
/**
* Using Keen-Slider for the infinite looping carousel, which I originally did
* in pure CSS - but I wanted to make this draggable by the user so made sense
* to use a 3rd party plug-in to do the heavy lifting.
*/
var animation = {
duration: 32000,
easing: (t) => t
}
new KeenSlider("#gallery-slider", {
dragSpeed: 1,
loop: true,
mode: "free",
slides: {
perView: 1.5,
renderMode: "performance",
spacing: 8
},
breakpoints: {
'(min-width: 768px)': {
slides: {
perView: 3,
spacing: 8
}
},
'(min-width: 1024px)': {
slides: {
perView: 4,
spacing: 8
}
}
},
created(s) {
s.moveToIdx(5, true, animation)
},
updated(s) {
s.moveToIdx(s.track.details.abs + 5, true, animation)
},
animationEnded(s) {
s.moveToIdx(s.track.details.abs + 5, true, animation)
}
})
/* ==========================================================================
#BASE
========================================================================== */
html {
font-size: 62.5%;
margin: 0;
padding: 0;
}
body {
font-size: 12px;
font-family: "Arial", sans-serif;
margin: 0;
padding: 128px 0 0;
text-transform: uppercase;
}
h2 {
font-size: 12px;
font-weight: 400;
margin: 0 16px 16px;
padding: 0;
}
p {
margin: 0 16px 128px;
}
figure {
margin: 0;
padding: 0;
}
img {
height: auto;
width: 100%;
max-width: 100%;
}
/* ==========================================================================
#KEEN SLIDER
========================================================================== */
.keen-slider:not([data-keen-slider-disabled]) {
display: flex;
align-content: flex-start;
overflow: hidden;
position: relative;
touch-action: pan-y;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
width: 100%;
-webkit-tap-highlight-color: transparent;
}
.keen-slider:not([data-keen-slider-disabled]) .keen-slider__slide {
min-height: 100%;
overflow: hidden;
position: relative;
width: 100%;
}
.keen-slider:not([data-keen-slider-disabled])[data-keen-slider-v] {
flex-wrap: wrap;
}
/* ==========================================================================
#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: 128px;
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.
*/
#gallery-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 0.32s 0.32s steps(1, end) both;
}
@keyframes loaded {
0% {
scale: 1.1;
}
64% {
scale: 1.04;
}
75% {
opacity: 0.8;
scale: 1.02;
}
100% {
opacity: 0;
z-index: 1;
}
}
<html>
<body>
<h2>Placeholder text to push content down and create vertical scroll</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat /questions/ask#non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<!-- 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">
</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">
</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">
</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">
</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">
</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">
</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">
</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">
</div>
<img src="https://placebeard.it/768/1024" width="768" height="1024" loading="lazy" />
</div>
<figcaption>Slide 8</figcaption>
</figure>
</div>
</div>
<!-- End Keen Slider -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/keen-slider.min.js"></script>
</body>
</html>