ಆಧುನಿಕ ವೆಬ್ಸೈಟ್ಗಳು ಅದ್ಭುತವಾದ ದೃಶ್ಯಗಳೊಂದಿಗೆ ಜನರ ಗಮನ ಸೆಳೆಯಲು ಪ್ರಯತ್ನಿಸುತ್ತಿವೆ. Parallax heroes ವೀಕ್ಷಣೆ ಪ್ರದೇಶಕ್ಕೆ (viewport) ಆಳವಾಗಿ ಹರಡುತ್ತವೆ. Carousels ಅತೀ ಹೆಚ್ಚು ಸ್ಕ್ರೋಲ್ ಆಗುತ್ತವೆ. Signup forms ಹಿಂದೆ ಹಿನ್ನೆಲೆ ವೀಡಿಯೊಗಳು ಆಟೋ-ಪ್ಲೇ ಆಗುತ್ತವೆ. ಡಿಸೈನ್ ಪೋರ್ಟ್ಫೋಲಿಯೋದಲ್ಲಿ ಇವುಗಳು ಆಕರ್ಷಕವಾಗಿ ಕಾಣಿಸಬಹುದು. ಆದರೆ ನಿಮ್ಮ ಪ್ರೇಕ್ಷಕರಲ್ಲಿ ಕೆಲವರಿಗೆ, ಇವು ದೈಹಿಕ ಅಸ್ವಸ್ಥತೆಯನ್ನು ಉಂಟುಮಾಡುವ ಕಾರಣಗಳಾಗಬಹುದು.
ವೆಸ್ಟಿಬ್ಯುಲರ್ ಡಿಸಾರ್ಡರ್ಸ್ (vestibular disorders) ಇರುವ ಜನರಿಗೆ ನಿರಂತರ ಚಲನೆಯ ದೊಡ್ಡ ಪ್ರದೇಶಗಳನ್ನು ನೋಡಿದಾಗ ವಾಕರಿಕೆ, ತಲೆಸುತ್ತು ಅಥವಾ ಮೈಗ್ರೇನ್ ಕಾಣಿಸಿಕೊಳ್ಳಬಹುದು. ಅವರನ್ನು ರಕ್ಷಿಸಲು, ಪ್ರತಿಯೊಂದು ಪ್ರಮುಖ ಆಪರೇಟಿಂಗ್ ಸಿಸ್ಟಮ್ ಈಗ "Reduce Motion" ಎಂಬ ಅಕ್ಸೆಸಿಬಿಲಿಟಿ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ಒಳಗೊಂಡಿದೆ. ವೆಬ್ ಬ್ರೌಸರ್ಗಳು ಆ ಆದ್ಯತೆಯನ್ನು prefers-reduced-motion ಮೀಡಿಯಾ ಕ್ವೆರಿಯ ಮೂಲಕ ತೋರಿಸುತ್ತವೆ. ಇದನ್ನು ಸುಲಭವಾಗಿ ಬಳಸಲು ಬಯಸುವ React ડેವಲಪರ್ಗಳು @reactuses/core ನಿಂದ useReducedMotion hook ಅನ್ನು ಬಳಸಬಹುದು. ಇದು OS ಆದ್ಯತೆಯನ್ನು boolean ಆಗಿ ಓದುತ್ತದೆ, ಬಳಕೆದಾರರು ಬದಲಾಯಿಸಿದರೆ ತಕ್ಷಣ ಅಪ್ಡೇಟ್ ಮಾಡುತ್ತದೆ ಮತ್ತು server-side rendering ಸಮಯದಲ್ಲಿ ಕ್ರ್ಯಾಶ್ ಆಗದಂತೆ ನೋಡಿಕೊಳ್ಳುತ್ತದೆ.
ಸ್ವತಃ ತಯಾರಿಸಿದ ಪರಿಹಾರಗಳು ಏಕೆ ವಿಫಲವಾಗುತ್ತವೆ
ನೀವು window.matchMedia('(prefers-reduced-motion: reduce)') ಬಳಸಿ ಸ್ವತಃ ಆ ಆದ್ಯತೆಯನ್ನು ಪರೀಕ್ಷಿಸಬಹುದು. ಅನೇಕ ડેವಲಪರ್ಗಳು ಹಾಗೆಯೇ ಮಾಡುತ್ತಾರೆ, ಮತ್ತು ಇದರಿಂದ ಸಣ್ಣಪುಟ್ಟ ಬಗ್ಗಳು (bugs) ಉಂಟಾಗಬಹುದು.
ಮೊದಲನೆಯದಾಗಿ, ನೀವು 'change listener' ಅನ್ನು ಮರೆಯಬಹುದು. ಕಾಂಪೊನೆಂಟ್ ಮೌಂಟ್ (mount) ಆದಾಗ ಆರಂಭಿಕ ಕ್ವೆರಿ ಒಮ್ಮೆ ಮಾತ್ರ ರನ್ ಆಗುತ್ತದೆ. ಬಳಕೆದಾರರು ನಿಮ್ಮ ಆಪ್ ತೆರೆದ ನಂತರ, carousel ನಿಂದ ತೊಂದರೆಯಾಗಿ ಸಿಸ್ಟಮ್ ಸೆಟ್ಟಿಂಗ್ಸ್ನಲ್ಲಿ Reduce Motion ಅನ್ನು ಆನ್ ಮಾಡಿದರೆ, ನಿಮ್ಮ ಕಾಂಪೊನೆಂಟ್ಗೆ ಆ ಬದಲಾವಣೆಯ ಅರಿವಾಗುವುದಿಲ್ಲ. ಮೀಡಿಯಾ ಕ್ವೆರಿ ಆಬ್ಜೆಕ್ಟ್ addEventListener ಅನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ, ಆದರೆ ಅದನ್ನು ಸರಿಯಾಗಿ ಜೋಡಿಸುವುದು, unmount ಮಾಡುವಾಗ ತೆಗೆದುಹಾಕುವುದು ಮತ್ತು ಹಳೆಯ addListener ಸಿಂಟ್ಯಾಕ್ಸ್ ಅನ್ನು polyfill ಮಾಡುವುದು ಹೆಚ್ಚು ಕೆಲಸದ ಮತ್ತು ತಪ್ಪುಗಳಿಗೆ ದಾರಿ ಮಾಡಿಕೊಡುವ ಪ್ರಕ್ರಿಯೆಯಾಗಿದೆ.
ಎರಡನೆಯದಾಗಿ, SSR ಸಮಯದಲ್ಲಿ window ಅಸ್ತಿತ್ವದಲ್ಲಿರುವುದಿಲ್ಲ. ನಿಮ್ಮ ಆಪ್ ಸರ್ವರ್ನಲ್ಲಿ ರೆಂಡರ್ ಆಗುತ್ತಿದ್ದರೆ, ಸಾಮಾನ್ಯ matchMedia ಕರೆ ರೆಫರೆನ್ಸ್ ಎರರ್ (reference error) ಉಂಟುಮಾಡಿ ರೆಂಡರಿಂಗ್ ಅನ್ನು ನಿಲ್ಲಿಸುತ್ತದೆ. ಇದರಿಂದಾಗಿ ನೀವು typeof window !== 'undefined' ಎಂಬ ಗಾರ್ಡ್ಗಳನ್ನು ಬಳಸಬೇಕಾಗುತ್ತದೆ ಮತ್ತು ಡಿಫಾಲ್ಟ್ ಮೌವ್ ಅನ್ನು ಊಹಿಸಿ, ಕ್ಲೈಂಟ್ ಹೈಡ್ರೇಶನ್ (client hydrate) ಸರಿಯಾಗಿ ಹೊಂದಿಕೆಯಾಗಲಿ ಎಂದು ಕಾಯಬೇಕಾಗುತ್ತದೆ.
ಮೂರನೆಯದಾಗಿ, ಪ್ರತಿಯೊಂದು ಅನಿಮೇಟೆಡ್ ಕಾಂಪೊನೆಂಟ್ನಲ್ಲಿ ಈ ಲಾಜಿಕ್ ಅನ್ನು ಪುನರಾವರ್ತಿಸುವುದು ನಿರ್ವಹಣೆಯ ಹೊರೆಯಾಗುತ್ತದೆ (maintenance debt). ಒಬ್ಬ ಸಹೋದ್ಯೋಗಿ ಲಿಸನರ್ ಅನ್ನು ಒಂದು ರೀತಿಯಲ್ಲಿ ಬರೆಯಬಹುದು, ಇನ್ನೊಬ್ಬ ಅದನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಬಿಡಬಹುದು ಮತ್ತು ಮೂರನೆಯವನು ಚಲನೆಗೆ ಒತ್ತು ನೀಡುವ ಡಿಫಾಲ್ಟ್ ಅನ್ನು ಹಾರ್ಡ್-ಕೋಡ್ ಮಾಡಬಹುದು. ಒಂದು hook ಈ ಗೊಂದಲವನ್ನು ಕೇಂದ್ರೀಕರಿಸುತ್ತದೆ.
useReducedMotion ಈ ಮೂರೂ ಸಮಸ್ಯೆಗಳನ್ನು ಪರಿಹರಿಸುತ್ತದೆ. ಇದು ಸರಳವಾದ boolean ಅನ್ನು ನೀಡುತ್ತದೆ. ಇದು ಸರ್ವರ್ನಲ್ಲಿ ಸುರಕ್ಷಿತವಾಗಿ ಕೆಲಸ ಮಾಡುತ್ತದೆ (no-ops). ಇದು ಲಿಸನರ್ ಅನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅಟ್ಯಾಚ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಕ್ಲೀನ್ ಅಪ್ ಮಾಡುತ್ತದೆ.
ಇದನ್ನು ಬಳಸಲು ಮೂರು ವಿಧಾನಗಳು
ಒಮ್ಮೆ ನಿಮಗೆ boolean ಸಿಕ್ಕ ನಂತರ, ಅದರ ಆಧಾರದ ಮೇಲೆ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಒಂದು ತಂತ್ರ ಬೇಕಾಗುತ್ತದೆ. ಒಂದೇ ಕಾಂಪೊನೆಂಟ್ನಿಂದ ಇಡೀ ಅಪ್ಲಿಕೇಶನ್ವರೆಗೆ ಬಳಸಬಹುದಾದ ಮೂರು ಮಾದರಿಗಳು ಇಲ್ಲಿವೆ.
1. ಅನಗತ್ಯ ಕೆಲಸವನ್ನು ತಪ್ಪಿಸಲು CSS ಕ್ಲಾಸ್ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ
ಅತ್ಯಂತ ನೇರವಾದ ವಿಧಾನವೆಂದರೆ ಭಾರೀ JavaScript ಅನಿಮೇಷನ್ ಲೂಪ್ಗಳು ಪ್ರಾರಂಭವಾಗದಂತೆ ತಡೆಯುವುದು. ಉದಾಹರಣೆಗೆ, ನಿಮ್ಮ ಬಳಿ ಒಂದು parallax ಇಮೇಜ್ ಕಾಂಪೊನೆಂಟ್ ಇದೆ ಎಂದು ಭಾವಿಸಿ, ಅದು ಸಾಮಾನ್ಯವಾಗಿ ಸ್ಕ್ರೋಲ್ ಇವೆಂಟ್ಗಳನ್ನು ಕೇಳುತ್ತದೆ ಮತ್ತು requestAnimationFrame ಲೂಪ್ ಒಳಗೆ ಲೇಯರ್ಗಳನ್ನು ಚಲಿಸುತ್ತದೆ. ಆ ಲಾಜಿಕ್ ಅನ್ನು ರನ್ ಮಾಡಿ ನಂತರ ದೃಶ್ಯ ಫಲಿತಾಂಶವನ್ನು ತಡೆಯುವ ಬದಲು, ಮೊದಲು useReducedMotion ಅನ್ನು ಪರಿಶೀಲಿಸಿ.
ಒಂದು ವೇಳೆ hook true ಎಂದು ನೀಡಿದರೆ, ಕಾಂಪೊನೆಂಟ್ ಅನ್ನು ಸ್ಟ್ಯಾಟಿಕ್ ವೇರಿಯಂಟ್ ಕ್ಲಾಸ್ನೊಂದಿಗೆ ರೆಂಡರ್ ಮಾಡಿ ಮತ್ತು ಸ್ಕ್ರೋಲ್ ಲಿಸನರ್ಗಳನ್ನು ಬೈಂಡ್ ಮಾಡುವ useEffect ಅನ್ನು ಬಿಟ್ಟುಬಿಡಿ. ಇದರಿಂದ ಬ್ರೌಸರ್ ಕಡಿಮೆ ಕೆಲಸ ಮಾಡುತ್ತದೆ. ಚಲನೆಯ ಬಗ್ಗೆ ಸೂಕ್ಷ್ಮತೆ ಇರುವ ಬಳಕೆದಾರರು ಸ್ಥಿರವಾದ ಚಿತ್ರವನ್ನು ನೋಡುತ್ತಾರೆ. ಉಳಿದವರಿಗೆ ಚಲಿಸುವ ಲೇಯರ್ಗಳು ಕಾಣಿಸುತ್ತವೆ. ಅನಿಮೇಷನ್ ಕೋಡ್ ಎಂದಿಗೂ ಇನಿಶಿಯಲೈಸ್ ಆಗದ ಕಾರಣ, ನೀವು CPU ಮತ್ತು ಬ್ಯಾಟರಿಯನ್ನು ಉಳಿಸಬಹುದು.
2. ಅನಿಮೇಷನ್ ಲೈಬ್ರರಿಗಳಿಗೆ ನೇರವಾಗಿ ಬಳಸಿ
ನೀವು Framer Motion ನಂತಹ ಲೈಬ್ರರಿಯನ್ನು ಬಳಸುತ್ತಿದ್ದರೆ, ಈ hook ಅನ್ನು ನಿಮ್ಮ prop ವ್ಯಾಖ್ಯಾನಗಳಿಗೆ ನೇರವಾಗಿ ಬಳಸಬಹುದು. Motion ಕಾಂಪೊನೆಂಟ್ಗಳು variants, transitions ಮತ್ತು gestures ಗಾಗಿ ಕಾನ್ಫಿಗರೇಶನ್ ಆಬ್ಜೆಕ್ಟ್ಗಳನ್ನು ಸ್ವೀಕರಿಸುತ್ತವೆ. ನೀವು useReducedMotion ನಿಂದ ಸಿಗುವ boolean ಅನ್ನು ಬಳಸಿ transitions ಮೇಲೆ ಕಂಡಿಷನಲ್ ಆಗಿ duration: 0 ಅನ್ನು ಸೆಟ್ ಮಾಡಬಹುದು, ಅಥವಾ
