Safari 15.4 scrollBy bug
Demo of a Safari Bug
by dsnvs
HTML
<main>
<h1>Issue: element.scrollBy is broken when using behavior: 'smooth'</h1>
<p>It seems like the problem only happens when a <code>element.ScrollBy</code> with
<code>behavior: 'smooth'</code> is used on an element with CSS attribute <code>overflow</code> (or
<code>overflow-x</code>) set to <code>hidden</code></p>
<h3>Confirmed on: </h3>
<ul>
<li>Safari for macOS Version 15.4 (17613.1.17.1.13)</li>
</ul>
<section class="broken">
<h2>scrollBy when using the <code>behavior: 'smooth'</code> and <code>overflow: hidden</code></h2>
<div class="scroller" id="smooth">
<div class="scroll-item item-1"></div>
<div class="scroll-item item-2"></div>
<div class="scroll-item item-3"></div>
</div>
<div class="scroller-controls">
<button data-action="prev" data-scroller="smooth" data-behavior="smooth">Prev</button>
<button data-action="next" data-scroller="smooth" data-behavior="smooth">Next</button>
</div>
</section>
<section>
<h2>scrollBy when using the <code>behavior: 'smooth'</code> and <code>overflow: scroll</code></h2>
<div class="scroller scroller-with-scrollbar" id="smooth-2">
<div class="scroll-item item-1"></div>
<div class="scroll-item item-2"></div>
<div class="scroll-item item-3"></div>
</div>
<div class="scroller-controls">
<button data-action="prev" data-scroller="smooth-2" data-behavior="smooth">Prev</button>
<button data-action="next" data-scroller="smooth-2" data-behavior="smooth">Next</button>
</div>
</section>
<section>
<h2>scrollBy when using the <code>behavior: 'instant'</code> and <code>overflow: hidden</code></h2>
<div class="scroller"...
CSS
body {
font-family: 'Helvetica', 'Arial', sans-serif;
}
main {
max-width: 800px;
margin: 0px auto;
}
section {
border-radius: 8px;
padding-top: 5px;
}
section h2 {
margin: 15px;
text-align: center;
}
button {
padding: 10px;
border-radius: 5px;
}
footer {
max-width: 800px;
margin: 30px auto 50px auto;
padding: 20px 10px;
border-radius: 8px;
background-color: rgb(239, 239, 239);
}
a, a:active, a:visited, a:hover {
color: blue;
}
.broken {
background-color: rgb(239, 239, 239);
}
.scroller {
max-width: 780px;
margin-left: auto;
margin-right: auto;
white-space: nowrap;
overflow-x: hidden;
}
.scroller-with-scrollbar {
overflow-x: scroll;
}
.scroll-item {
display: inline-block;
width: 500px;
height: 300px;
border-radius: 10px;
}
.item-1 {
background-color: rgb(225, 225, 225);
}
.item-2 {
background-color: rgb(110, 110, 110)
}
.item-3 {
background-color: rgb(66, 66, 66)
}
.scroller-controls {
text-align: center;
margin-top: 10px;
}
JavaScript
let buttons = document.querySelectorAll('button');
buttons.forEach((button) => {
button.addEventListener('click', (e) => {
let scroller = document.getElementById(e.currentTarget.attributes['data-scroller'].value);
let direction = e.currentTarget.attributes['data-action'].value == "next" ? 1 : -1;
let behavior = e.currentTarget.attributes['data-behavior'].value;
scrollElement(scroller, direction, behavior);
})
})
function scrollElement (scroller, direction, behavior) {
scroller.scrollBy({left: 800 * (direction), behavior: behavior})
}