I’m utilizing Intersection Observer API to hide the website header logo when it’s not over (or close to being over) a background image.
Works well on Google Chrome, other chromium browsers and Safari (at the least mobile version) but the CSS animations play extremely laggy and sometimes delayed on Firefox. In fact sometimes it doesn’t even trigger, it just freezes.
The CSS animations display fine when it’s not triggered by Intersection Observer adding a class. (i.e.: the blue box in the example below has the fade-in class by default and the animation plays smoothly when you refresh the page and it fades in.)
I’m using Firefox 132.0.1 (64-bit).
I’ve asked others to test the website and the results were the same across.
Here is a sample page I made replicating the issue with a blue square as the header logo and red rectangle as the background image region:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scroll Test for StackOverflow</title>
<style>
.header-background{
height: 500px;
background-color:red;
}
.logo-container{
position: fixed;
top:2%;
left: 50%;
transform: translate(-50%, 0);
width: 80px;
height: 80px;
background-color: blue;
}
.logo.logo-container{
position: absolute;
}
.container{
height: 2000px;
}
@keyframes fade-in{
from{opacity:0;}
to{opacity: 1;}
}
@keyframes fade-out{
from{opacity: 1;}
to{opacity: 0;}
}
.fade-in{
opacity: 0;
animation-name: fade-in;
animation-duration: 0.4s;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
}
.fade-out{
opacity: 1;
animation-name: fade-out;
animation-duration: 0.2s;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
}
</style>
</head>
<body>
<div class="container">
<div class="headerhide" id="headerhide">
<div class="logo-container">
<div class="logo"></div>
</div>
</div>
<div class="header-background" id="region"></div>
</div>
<script>
const header = document.getElementById("headerhide");
const region = document.querySelector(".header-background");
const observer = new IntersectionObserver(([entry]) =>{
header.classList.toggle("fade-out", !entry.isIntersecting);
header.classList.toggle("fade-in", entry.isIntersecting);
},
{
threshold: 0.2,
}
)
observer.observe(region)
</script>
</body>
</html>
(edit: also on JSFiddle: https://jsfiddle.net/ob2t6wn3/3/)
(the CSS and js is normally in different files but for the example’s sake I put them all in the html)
Things I’ve tried:
Checking if it’s a Firefox settings issue, I ruled out the privacy.fingerprintingProtection flag in about:config and Firefox Sync because disabling either or both did not solve the issue. I couldn’t think of any other setting that could be causing this.
Adding will-change: opacity;
to the CSS class, didn’t work.
Adding a slight transform animation to trigger hardware acceleration but didn’t work, adding a translateZ(0)
also didn’t work.
Adding debounce to the JavaScript function didn’t work (although I’m not entirely sure if I did it correctly, I’ve started learning JavaScript 3 days ago.)
Using 2 observers to toggle the different classes, didn’t work.
edit: I tried using CSS transitions instead of keyframes but that didn’t fix it either.
Thanks in advance.