As noted in the comments, the problem seems to be that IE is firing way too many scroll events.
The general solution to such problems, as described e.g. in this Q&A thread is throttling the events to some reasonable rate, e.g. like this (using requestAnimationFrame
):
var scrollEventPending = false;
function handleScrollEvent () {
scrollEventPending = false;
// handle the event here
}
function throttleScrollEvents () {
if (scrollEventPending) return;
scrollEventPending = true;
requestAnimationFrame(handleScrollEvent);
});
window.addEventListener('scroll', throttleScrollEvents);
However, a limitation of this technique is that the throttled event handler still needs to fire in order to check whether a previously triggered event is pending. In your case, it seems like the event rate may be so high that even this trivial check can be enough to cause noticeable performance issues.
One possible solution could be to use the scroll event handler only to detect when the user starts scrolling, and to uninstall it temporarily until we detect by other means (e.g. comparing the page X and Y offsets) that the scrolling has stopped:
var lastX = window.pageXOffset, lastY = window.pageYOffset;
function runWhileScrolling () {
var currX = window.pageXOffset, currY = window.pageYOffset;
if (currX == lastX && currY == lastY) {
window.addEventListener('scroll', startScrolling);
return; // the page has stopped scrolling
}
// handle scrolling here
lastX = currX; lastY = currY;
requestAnimationFrame(runWhileScrolling);
}
function startScrolling () {
window.removeEventListener('scroll', startScrolling);
runWhileScrolling();
}
window.addEventListener('scroll', startScrolling);
Here's a simple live snippet demonstrating this technique, used here to emulate CSS fixed positioning:
var box = document.getElementById('jsfixed');
var lastX = window.pageXOffset, lastY = window.pageYOffset;
function runWhileScrolling () {
var currX = window.pageXOffset, currY = window.pageYOffset;
if (currX == lastX && currY == lastY) {
window.addEventListener('scroll', startScrolling);
return; // the page has stopped scrolling
}
box.style.top = currY + 80 + 'px';
box.style.left = currX + 10 + 'px';
lastX = currX; lastY = currY;
requestAnimationFrame(runWhileScrolling);
}
function startScrolling () {
window.removeEventListener('scroll', startScrolling);
runWhileScrolling();
}
window.addEventListener('scroll', startScrolling);
#cssfixed, #jsfixed {
box-sizing: border-box;
width: 250px; height: 50px;
padding: 15px 5px;
background: white;
}
#cssfixed {
position: fixed;
top: 20px; left: 10px;
border: 2px solid green;
}
#jsfixed {
position: absolute;
top: 80px; left: 10px;
border: 2px solid red;
}
body {
width: 3000px;
height: 3000px;
background: url(https://i.stack.imgur.com/ybp2X.png);
}
<div id="cssfixed">This box is kept fixed by CSS.</div>
<div id="jsfixed">This box is kept fixed by JS.</div>
Ideally, the two boxes shouldn't move at all with respect to each other as the page is scrolled. On Chrome 57, Opera 44 and Firefox 49, this is indeed the case. On IE 11, the red box does move and flicker noticeably while scrolling, but at least the scrolling itself is smooth and the box correctly returns to its original position after scrolling.
Note that using requestAnimationFrame
like above typically causes the scroll handler to be called about 60 times per second while the page is scrolling. If you don't need such frequent updates, you could replace it with e.g. setTimeout(runWhileScrolling, 200)
(for 5 updates per second).