Please run the code snippet...
I'm building a horizontal scroll menu. I've added left and right buttons (arrow icons) to allow user to move through the menu. So the user can move either by swiping/scrolling or by tapping the arrow icons.
So far so good. Next I added CSS's scroll-snap-type, which works nicely, improving UX when user is moving the scollbar by swiping.
But than scroll-snap conflicts with jQuery's .animate( { scrollLeft: "+=200"}, 500), which is triggered when user clicks on either arrow. This makes the control buttons broken.
To fix this, I tried to remove the scroll-snap-type css class while the scrollLeft jQuery animation is running, and add it back once it's done.
This seems to work pretty good in all devices when run inside dev-tools simulation, including iPhone devices. Live testing with Android 10 browsers (Chrome/Firefox) works good too, but doesn't work on iOS (tested on iOS 14.2 with latest Safari, Firefox and Chrome).
On iOS, when clicking on either Right/Left arrow btn, the animation runs, but than the menu scroll position suddenly snaps back to the first item, making the controls broken.
jQuery(document).ready(function($) {
/* Controls for horizontal scrolling */
var leftPaddle = $( ".left-paddle" );
var rightPaddle = $( ".right-paddle" );
// scroll to right
$(rightPaddle).on('click', function(event) {
event.preventDefault();
$('#snappylist').removeClass('scroll-snap-type');
$('#snappylist').animate({
scrollLeft: "+=250"
}, 500)
.promise()
.done(() => {
$('#snappylist')
.addClass("scroll-snap-type")
});
});
// scroll to left
$(leftPaddle).on('click', function(event) {
event.preventDefault();
$('#snappylist').removeClass('scroll-snap-type');
$('#snappylist').animate({
scrollLeft: "-=250"
}, 500)
.promise()
.done(() => {
$('#snappylist')
.addClass("scroll-snap-type")
});
});
});
.list {
margin-top: 50px;
background-color: gray;
display: flex;
overflow-x: auto;
gap: 0.25rem;
-webkit-overflow-scrolling: touch;
max-width: 300px;
}
.scroll-snap-type {
scroll-snap-type: x mandatory;
}
.list-item {
scroll-snap-align: center;
display: inline-flex;
min-width: 80px;
height: 50px;
justify-content: center;
align-items: center;
color: white;
}
.paddle {
position: absolute;
top: 50px;
bottom: 0;
width: 20px;
border: none;
background-color: red;
padding: 0;
max-height: 50px;
}
.left-paddle {
left: 0;
color: yellow;
background: red;
}
.right-paddle {
left: 300px;
color: yellow;
background: red;
}
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="module" src="https://unpkg.com/ionicons@5.2.3/dist/ionicons/ionicons.esm.js"></script>
<script nomodule="" src="https://unpkg.com/ionicons@5.2.3/dist/ionicons/ionicons.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"></script>
<ul id="snappylist" class="list scroll-snap-type">
<li class="list-item">
<ion-icon size="large" name="construct-outline"></ion-icon>
</li>
<li class="list-item">
<ion-icon size="large" name="flower-outline"></ion-icon>
</li>
<li class="list-item">
<ion-icon size="large" name="game-controller-outline"></ion-icon>
</li>
<li class="list-item">
<ion-icon size="large" name="git-compare-outline"></ion-icon>
</li>
<li class="list-item">
<ion-icon size="large" name="eye-outline"></ion-icon>
</li>
<li class="list-item">
<ion-icon size="large" name="earth-outline"></ion-icon>
</li>
<li class="list-item">
<ion-icon size="large" name="extension-puzzle-outline"></ion-icon>
</li>
<li class="list-item">
<ion-icon size="large" name="bus-outline"></ion-icon>
</li>
</ul>
<div class="paddles">
<button class="left-paddle paddle">
<ion-icon name="arrow-back-outline"></ion-icon>
</button>
<button class="right-paddle paddle">
<ion-icon name="arrow-forward-outline"></ion-icon>
</button>
</div>
However, if I leave the animation as-is, without removing it onclick:
// scroll to right
$(rightPaddle).on('click', function(event) {
event.preventDefault();
$('#parent-div').animate( { scrollLeft: "+=150"}, 500)
});
// scroll to left
$(leftPaddle).on('click', function(event) {
event.preventDefault();
$('#parent-div').animate( { scrollLeft: "-=150"}, 500)
});
This way everything seeme to work fine on iOS mobile, but than I'm back to the broken animation in other os/browsers.