imarc / boilerplate

Responsive CSS, HTML and JavaScript front-end starting point, plus components!
https://imarc-boilerplate.netlify.app/
8 stars 10 forks source link

Use reduced motion #75

Open tspears1 opened 2 years ago

tspears1 commented 2 years ago

@khamer - This is my first go at this - based loosely on the useReducedMotion in the React animation library Framer Motion: https://github.com/framer/motion/blob/1d973ba962963192b230b7200a3861b1170dc892/packages/framer-motion/src/utils/use-reduced-motion.ts

Its working fine except I'm not sure if there is a way for useReducedMotion to be reactive. Right now it only registers a change if the page is reloaded. However, I have consoled to see that the event listener is being added and firing on change. Any thoughts?

Working Demo: https://tinyurl.com/2uc26ez9

Also included:

tspears1 commented 2 years ago

@TristanMNorton - simplified the composable. Also here's a working example using the reactive state to play/pause the animation based on reduced motion changing in the OS: https://codesandbox.io/s/fancy-darkness-7u2gb3?file=/src/components/animation.vue

TristanMNorton commented 2 years ago

@tspears1 so check this out: https://codesandbox.io/s/inspiring-cache-nnuriy?file=/src/components/animation.vue

This is kind of what I was getting at. This works the exact same way, without the need for a reactive variable. This isn't something that would ever need to "live update" some aspect of the DOM since it's only a value ever really used programmatically in JS. It's more or less redundant to wrap something in a ref or reactive if it's never going to bind to anything in the DOM. That's why it doesn't really make sense to make it a composable.

The best case I can think of is with a css modifier, but even then, we natively have the css media query that will update styles on demand anyway. (I.E., setting transition lengths to css properties and setting them to 0 within a prefers-reduced-motion media query).

Either way, I definitely think we should have some kind of module/constructor that abstract some things away or add some nicities, and an example use-case built in to BPC to encourage devs to be thoughtful about respecting user preferences.

I know I say all this and I still left the anime instance itself in a ref, lol, I think there's a better practice there as well to use an actual ref and nextTick(). Although it's still bound to the DOM in some theoretical way... (stares off in to outer space)

tspears1 commented 2 years ago

@TristanMNorton hmmm so my understanding of a vue 3 composable is its a function of reusable stateful code. Ref and Reactive are how we create state regardless of DOM manipulation. In this way it sounds like a perfect fit for a composable. Yes, your demo does the same thing but its the same basic function I was using deconstructed into the actual component logic. I guess im still not understanding what this non-vue module would look like and still reactively affect change if prefers reduced motion were to change. This useMedia composable is very similar to what I'm after. Its tidy, reactive and easy to implement: https://logaretm.com/blog/my-favorite-5-vuejs-composables/#usemedia

khamer commented 2 years ago

So I agree with Tristan about it being unnecessary, but not necessarily the reasons he gave. Tim your example is pretty good, I might tweak a thing or two, but it's close to what I would have written IF I was going to make a composable: example

But that said, I don't think we'd use a composable here because I think the right implementation would be more like this: example

I don't think it makes sense to do things like, load up all of animejs and then pause it for reduced motion visitors. I think it's safe to check the value of reduced motion only on load and then base what animations/JS we're going to run based on that. Reduced Motion is probably just as likely to be for the computer's sake as for the user's, so places where we can avoid initializing animations, loading videos, onscroll effects, transitions etc are going to be better than loading those libraries and trying to write our code to stop/restart them on the fly.

tspears1 commented 2 years ago

@khamer @TristanMNorton okay I still think I disagree and would prefer to have the option for any "in-flight" animations to halt or reset if the user updated their settings without a page load. As I said before, any CSS animations and transitions are immediately responsive to the change, so I feel like the same should be true with JS and the composable feels like a quick and elegant way to implement it.

BUT its not a hill I need to die on so, I guess, what are next steps? We don't want a composable so I'm not sure what if anything we do need - @TristanMNorton not sure if you want to take this over and build the module you were talking about? Or we could just close the ticket.

TristanMNorton commented 2 years ago

@tspears1 I know we're getting lost in the technical weeds, we all agree here that the main goal is to encourage devs to respect user preference. I'm just trying to think about what's actually needed "functionally", but I agree there's a case to be made in terms of organization and consistent convention. (Including other stuff I'm probably not thinking of).

We're all still learning Vue 3, but I just want to make sure we're being super thoughtful about how we use it.

Here's what I think we should do: Let's just go ahead with a composable, as long as we update other components (like the slider) to utilize it. We can reevaluate after real-world usage if it still makes sense.