I'm trying to implement a scroll based shrinking effect on on a div element. As the user scrolls, the div shrinks in height (using scale) until it finally disappears. I'm using React to render the HTML and styled-components for the CSS.
I'm having problems with the performance of this effect, specifically only with Safari, Version 13.1 (15609.1.20.111.8). In Safari, the transition effect is very janky and does not happen smoothly.
Chrome and Firefox work perfectly.
Here is the React component:
const MyComponent = React.forwardRef((_, ref) => {
const [scaleOffset, setScaleOffset] = React.useState(1)
const onScroll = React.useCallback(debounceWindowEventCallback(() => {
const paddingOffset = window.scrollY - ref.current.offsetTop
if (paddingOffset >= 0) setScaleOffset(1 - (paddingOffset / 100))
}), [ref]);
React.useEffect(() => {
if (scaleOffset <= 0) {
window.removeEventListener('scroll', onScroll)
console.log('Border has been fully shrunk')
}
}, [onScroll, scaleOffset])
React.useEffect(() => {
window.addEventListener('scroll', onScroll)
return () => window.removeEventListener('scroll', onScroll)
}, [])
return (
<RootElement ref={ref}>
<ShrinkBorderTop scaleOffset={scaleOffset} />
</RootElement>
);
});
And the relevant styled components are:
const ShrinkBorderTop = styled.div`
position: absolute;
background-color: white;
transition: transform .175s ease-out;
width: 100%;
height: 200px;
transform: ${({ scaleOffset }) => `scale(1, ${scaleOffset})`};
`
What I've tried:
- I initially thought its because my component was rendering too much (every scroll event) so I implemented the
debounceWindowEventCallbackfunction which useswindow.requestAnimationFrameto ensure that there's only a single paint per frame. Unfortunately, that didn't help. - I then tried adding
will-change: transition, transform, height, width;toShrinkBorderTop, after googling the problem. This also didn't help. - Then I tried adding
perspective: 1000; backface-visibility: hidden;toShrinkBorderTop, this also didn't work.
I'm stumped as to what could be causing this problem, in my view its quite a standard animation and I've applied all the performance boosts I'm aware of, in addition to scale being hardware accelerated by default, but the problem still persists, only in safari.
What could be causing this?