Faced up with problem, shown in this article: https://remysharp.com/2012/05/24/issues-with-position-fixed-scrolling-on-ios#scrolling--unusable-positionfixed-element in Mobile Safari.
I'd caught this bug while coding the footer. My code structure is:
<div>
...
<div className="wrap">
<div className="footer">
{ ... content of tabs }
</div>
</div>
</div>
And the styles:
.wrap {
display: block;
width: 100%;
height: 60px;
position: relative;
z-index: 100;
}
.footer {
position: fixed;
bottom: 0;
left: 0;
height: 60px;
width: 100%;
z-index: 200;
display: flex;
background: #f2f2f7;
border-top: 1px solid #f0f0f0;
}
Wanna say about solution. Maybe it will be helpful for someone.
I've tried solutions from the issues:
But it didn't look good and my footer was flickering. Sometimes (using very-very slow scroll) bug happened again.
I've also tried use "sticky" styles instead of "fixed", for wrapper or footer, but it also didn't work.
Finally, I found the solution:
- I added listener on scroll event by js and changed styles. The idea is: until the scrolling ends, I add "sticky" class to the parent; when the scrolling ends, I remove it. I've seen similar issue with header here: React: Sticky header flickers in iOS Safari
- I added "will-change: auto" styles to the wrapper. I found this idea from the comment: https://stackoverflow.com/a/51940706/22479266
The magic is that these fixes don't work on their own, only using them both.
The final solution looks like:
const ref = useRef(null);
const handleScroll = useCallback(() => {
if (ref.current) {
if (ref.current.getBoundingClientRect().bottom > window.innerHeight) {
if (!ref.current.classList.contains("sticky")) {
ref.current.classList.add("sticky");
}
} else {
ref.current.classList.remove("sticky");
}
}
}, []);
useEffect(() => {
document.addEventListener('scroll', handleScroll);
return () => {
document.removeEventListener('scroll', handleScroll);
}
}, [handleScroll]);
return <div className="wrap" ref={ref}>
<div className="footer">
{ ... content of tabs }
</div>
</div>
And the styles are:
.wrap {
display: block;
width: 100%;
height: 60px;
position: relative;
z-index: 100;
will-change: auto;
}
.footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 60px;
width: 100%;
z-index: 200;
display: flex;
background: #f2f2f7;
border-top: 1px solid #f0f0f0;
}
If anyone understands why this helps, please, tell me.