Chrome Browser Bug: Scroll Wheel Randomly Stops Working In Overflow Container
I'm currently in the middle of building out a proof-of-concept for InVision that uses a flexbox layout with some "overflow:auto" scrollable areas. And, as I've been coding this feature, I've noticed that the Chrome browser occasionally stops responding to the scroll wheel on my Logitech Mouse. At first, I thought maybe this was an issue in the way I was using flexbox. But, when I tried to switch from flexbox to "position:absolute", the problem persisted. As it turns out, this is a known bug in Chrome. I wanted to share this problem (and a video of the reproduction steps) in case it was driving anyone else nuts. It's not your fault. It's a browser bug.
Run this demo in my JavaScript Demos project on GitHub.
View this code in my JavaScript Demos project on GitHub.
In the discussion forum linked above, people state that this happens with any Chrome tab; however, I personally have only experienced the issue with an overflow container - not with the parent page. That said, here is the demo code for the reproduction, as seen in the above video:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>
Chrome Browser Bug: Scroll Wheel Randomly Stops Working In Overflow Container
</title>
<style type="text/css">
html {
box-sizing: border-box ;
}
*, *:before, *:after {
box-sizing: inherit ;
}
/* BEGIN: Layout-A - It uses FLEXBOX and Overflow. */
.layout-a {
border: 2px solid #cccccc ;
display: flex ;
flex-direction: column ;
height: 500px ;
margin: -250px 0px 0px 0px ;
position: absolute ;
right: 51% ;
top: 50% ;
width: 300px ;
}
.layout-a__top-panel {
flex: 1 1 auto ;
overflow: auto ;
}
.layout-a__bottom-panel {
border-top: 1px solid #cccccc ;
flex: 0 0 auto ;
height: 100px ;
padding: 20px 20px 20px 20px ;
}
/* END: Layout-A. */
/* BEGIN: Layout-B - It uses POSITION ABSOLUTE and Overflow. */
.layout-b {
border: 2px solid #cccccc ;
height: 500px ;
left: 51% ;
margin: -250px 0px 0px 0px ;
position: absolute ;
top: 50% ;
width: 300px ;
}
.layout-b__top-panel {
bottom: 100px ;
left: 0px ;
overflow: auto ;
position: absolute ;
right: 0px ;
top: 0px ;
}
.layout-b__bottom-panel {
border-top: 1px solid #cccccc ;
bottom: 0px ;
height: 100px ;
left: 0px ;
padding: 20px 20px 20px 20px ;
position: absolute ;
right: 0px ;
}
/* END: Layout-B. */
.content p {
margin: 0px 0px 0px 0px ;
padding: 25px 20px 22px 20px ;
}
.content p:nth-child( even ) {
background-color: #f0f0f0 ;
}
</style>
</head>
<body>
<h1>
Chrome Browser Bug: Scroll Wheel Randomly Stops Working In Overflow Container
</h1>
<!-- BEGIN: Layout-A. -->
<section class="layout-a">
<div class="layout-a__top-panel">
<div class="content">
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
</div>
</div>
<div class="layout-a__bottom-panel">
Using <strong>Flexblox</strong>
</div>
</section>
<!-- END: Layout-A. -->
<!-- BEGIN: Layout-B. -->
<section class="layout-b">
<div class="layout-b__top-panel">
<div class="content">
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
</div>
</div>
<div class="layout-b__bottom-panel">
Using <strong>Position Absolute</strong>
</div>
</section>
<!-- END: Layout-B. -->
<script type="text/javascript">
// Theoretically, the "wheel" event and the "scroll" event should go hand-in-hand
// as long as there is room to scroll the content of a container. However, in
// Chrome, the scrolling of the mouse-wheel will suddenly stop working (at least
// as of Chrome/70.0.3538.102). In that case, we can see the "wheel" event being
// logged without a corresponding "scroll" event.
window.addEventListener(
"wheel",
function handleWheelEvent( event ) {
var direction = ( event.deltaY >= 0 )
? "DOWN"
: "UP"
;
console.log( "Event: wheel,", direction, event.target );
},
true
);
window.addEventListener(
"scroll",
function handleScrollEvent( event ) {
console.log( "Event: scroll" );
},
true
);
</script>
</body>
</html>
As you can see, I have some "overflow: auto" containers, one using flexbox and one using "position: absolute". I'm also logging the "wheel" and "scroll" events (using the capture phase of the event life-cycle). These two events should go hand-in-hand as long as there is content to scroll. However, it is not that hard to reproduce a case in which the "wheel" indicates an "UP" event, but there is no corresponding "scroll" event (because Chrome isn't scrolling the overflow container):
As you can see, I can easily get to a point where I am moving the mouse wheel up and down and I am seeing no subsequent scrolling of the overflow container. Then, if I pause for a second or two, and try the mouse wheel again, things will start working as expected.
So, this is a Chrome bug. It's not your fault.
Hopefully this helps maintain the sanity of anyone else who runs into this problem. And, if you have any suggestions on how to work-around the bug, please let us know!
Want to use code from this post? Check out the license.
Reader Comments
@All,
So, Sean Roberts - head of the Web Performance here at InVision - has a good theory about this behavior. He believes that the browser is trying to figure out which container is supposed to be receiving the scroll event. As you may know, when you scroll in the browser, it the targeted container runs out of "scrollable content", the browser will start walking up the DOM tree to find parent containers with scrollable content; and, if possible, apply the
wheel
event said container. This is why, in the past, I've created an Angular directive trap scrolling in a given container:www.bennadel.com/blog/3365-prevent-scrolling-in-a-parent-element-using-directives-in-angular-4-4-6.htm
But, the theory is, the
wheel
event doesn't look like its being applied to the embedded container because the browser is - at that moment - trying to apply it to thebody
, which has no scrollable content.So, the browser is trying to figure out how to provide the best user experience; but, in this case, isn't making the best choice.
@All,
So, I went back and played around with the
wheel
event. Specifically with preventing the default behavior of thewheel
event when the overflow container runs out of scroll room. And, it appears to have a positive impact on this bug:www.bennadel.com/blog/3544-trapping-the-wheel-event-may-prevent-chrome-browser-bug-in-which-the-scroll-wheel-stops-working-in-overflow-container.htm
It's hard to "prove" that it's fixed. But, what I can say is that I can very easily and consistently reproduce the problem in a "control case"; but, I have yet to reproduce the issue when I intercept and manipulate the
wheel
event.there is a fix here
https://bugs.chromium.org/p/chromium/issues/detail?id=797708&desc=2#c121
I wonder if there is a fix that is explained as if it were to a 5 year old? I don't understand anything you all are saying and I am self diagnosed as "Tech-Tarded". Any help is much appreciated.
@Jimmy,
My attempt at a non-techie answer: Have you have seen someone from across the street and they wave at you. So you wave back; only to realize a moment later that they are actually waving at someone behind you?
That's kind of like what is happening here. When I move my scroll-wheel, it's like I'm "waving" at one of the containers on page. Except, the wrong container is "waving back" (by attempting-and-failing to scroll). And I want to say, "No, not you -- the other guy!"
Not sure if that made any sense :D
@Haroon,
I am not sure that approach would work. It looks like it is, essentially, adding a "cover" Div to the entire browser. Because this Div is "fixed" position, and lower in the DOM tree, it would stack above the content before it, making the content inaccessible to clicks and other mouse interactions.
Unless I am missing something obvious.
It seems that adding
overscroll-behavior: none
to the overflow containers fixes this. https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior@Derek,
OH CHICKENS! This is awesome!! It's not in all the browsers; but it's in Chrome and Firefox! I will definitely be playing around with this a bit more. Outstanding :D
@Derek,
This morning, I did a little experimentation with the
overscroll-behavior
CSS property:www.bennadel.com/blog/3698-using-css-overscroll-behavior-to-prevent-scrolling-of-parent-containers-from-within-overflow-containers.htm
This is awesome! Thank you so much for pointing this out to me. This is huge. I'm gonna be shipping changes for this today to my production app.
It was a pretty exciting discovery for me too! Glad it helped.
using will-change: transform fixed scrolling for me
In a Fixed overflow sidebar div with dynamic loaded content that randomly stopped scrolling in Chrome Version 78.0.3904.108
@Knud,
Wow many thanks, can't believe it solved our scroll issue
@Knud, @Shagrath,
You might be interested in a follow-up post that uses
overscroll-behavior
to "fix" this problem in modern browsers:www.bennadel.com/blog/3698-using-css-overscroll-behavior-to-prevent-scrolling-of-parent-containers-from-within-overflow-containers.htm
@Ben Nadel
could you please go with more information as solution provided by @Knud works extremely fine.
so please let me know the reason why to use overflow behaviour
and what is the advantage of it over will-change property.
@Srishti,
At the end of the day, whatever works for you is "good". That said, the reason that I like the
overscroll-behavior
option is that it is solving the root problem, rather than simply getting the browser to do what you want. Meaning, the root issue here is that the user-scroll-event is getting sent to the wrong container element (which is why the scrolling stops working). So, when you useoverscroll-behavior
, you are explicitly telling the browser how you want the scroll events to be handled. It feels more "correct" to me.But, that's just my opinion.
@Knud,
I was also having this issue in Chrome 78 and your solution works. Many thanks.
@Knud,
Could you share a refence code for this fix.
It will use full for me.
@Rajeshkumar,
I saw reference to using "will-change: transform" on a post on stackoverflow to fix some other issue and when I used it, it also seemed to fix my scrolling issue. But whatever I search for now I can't find it again. I only posted here because using overscroll-behavior didn't fix the issue in my situation. I think because the div I needed to scroll was updated via AJAX and was in a Fixed position. I've looked now for half an hour and can't find the post again.
@knud
I also tried to find the reference, but i cant. Anyway thank you for your time support. I will try to implement this one "will-change: transform" .
Since Chrome update 79, I can't reproduce that bug anymore... Did the update solve the issue ? What about you guys ?