@@ -3,6 +3,7 @@ import AnimationManager from "./AnimationManager";
3
3
import useGetImageHeight from "./hooks/useGetImageHeight" ;
4
4
import useGetTransitionValue from "./hooks/useGetTransitionValue" ;
5
5
import useIntersectionObserver from "./hooks/useIntersectionObserver" ;
6
+ import useReducedMotion from "./hooks/useReduceMotion" ;
6
7
import { SimpleParallaxProps } from "./types" ;
7
8
8
9
const SimpleParallax : React . FunctionComponent < SimpleParallaxProps > = ( {
@@ -26,7 +27,8 @@ const SimpleParallax: React.FunctionComponent<SimpleParallaxProps> = ({
26
27
const [ transformCSS , setTransformCSS ] = useState ( "" ) ;
27
28
const [ transitionCSS , setTransitionCSS ] = useState ( "" ) ;
28
29
const [ shouldApplyTransition , setShouldApplyTransition ] = useState ( false ) ;
29
-
30
+
31
+ const prefersReducedMotion = useReducedMotion ( ) ;
30
32
const [ imageRef , imageHeight , isLoaded ] = useGetImageHeight ( src ) ;
31
33
const [ elementRef , isVisible ] = useIntersectionObserver < HTMLDivElement > ( {
32
34
root : null ,
@@ -43,7 +45,7 @@ const SimpleParallax: React.FunctionComponent<SimpleParallaxProps> = ({
43
45
} ) ;
44
46
45
47
const updateParallax = useCallback ( ( ) => {
46
- if ( ! isVisible && isInit ) return ;
48
+ if ( ( ! isVisible && isInit ) || prefersReducedMotion ) return ;
47
49
48
50
if ( window . scrollY !== viewportTop || ! isInit ) {
49
51
const boundingClientRect = imageRef . current ?. getBoundingClientRect ( ) ;
@@ -52,43 +54,53 @@ const SimpleParallax: React.FunctionComponent<SimpleParallaxProps> = ({
52
54
}
53
55
if ( ! isInit ) {
54
56
setIsInit ( true ) ;
57
+ // We'll enable transitions after the first calculation
55
58
setTimeout ( ( ) => {
56
59
setShouldApplyTransition ( true ) ;
57
60
} , 50 ) ;
58
61
}
59
62
setViewportTop ( window . scrollY ) ;
60
63
}
61
- } , [ viewportTop , isVisible , imageRef , isInit ] ) ;
64
+ } , [ viewportTop , isVisible , imageRef , isInit , prefersReducedMotion ] ) ;
62
65
63
66
useEffect ( ( ) => {
67
+ if ( prefersReducedMotion ) {
68
+ setTransformCSS ( "" ) ;
69
+ return ;
70
+ }
71
+
64
72
let transform = `translate3d(${ transitionValue } )` ;
65
73
if ( ! overflow ) {
66
74
transform += ` scale(${ scale } )` ;
67
75
}
68
76
setTransformCSS ( transform ) ;
69
- } , [ transitionValue , scale , overflow ] ) ;
77
+ } , [ transitionValue , scale , overflow , prefersReducedMotion ] ) ;
70
78
71
79
useEffect ( ( ) => {
72
- if ( ! transition || ! delay || ! shouldApplyTransition ) {
80
+ if ( ! transition || ! delay || ! shouldApplyTransition || prefersReducedMotion ) {
73
81
setTransitionCSS ( "" ) ;
74
82
return ;
75
83
}
76
84
setTransitionCSS ( `transform ${ delay } s ${ transition } ` ) ;
77
- } , [ transition , delay , shouldApplyTransition ] ) ;
85
+ } , [ transition , delay , shouldApplyTransition , prefersReducedMotion ] ) ;
78
86
79
87
useEffect ( ( ) => {
80
- AnimationManager . register ( updateParallax ) ;
88
+ // Only register for animation if reduced motion is not preferred
89
+ if ( ! prefersReducedMotion ) {
90
+ AnimationManager . register ( updateParallax ) ;
91
+ }
92
+
81
93
return ( ) => {
82
94
AnimationManager . unregister ( updateParallax ) ;
83
95
} ;
84
- } , [ updateParallax ] ) ;
96
+ } , [ updateParallax , prefersReducedMotion ] ) ;
85
97
86
98
const clonedChild = React . isValidElement ( children )
87
99
? React . cloneElement ( children as React . ReactElement , {
88
100
style : {
89
101
...( ( children as React . ReactElement ) . props . style ?? { } ) ,
90
102
transform : transformCSS ,
91
- willChange : "transform" ,
103
+ willChange : prefersReducedMotion ? "auto" : "transform" ,
92
104
transition : transitionCSS ,
93
105
} ,
94
106
ref : imageRef ,
0 commit comments