Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set CSS variables with data-animation #13

Open
ec-propaganda opened this issue Oct 29, 2024 · 12 comments
Open

Set CSS variables with data-animation #13

ec-propaganda opened this issue Oct 29, 2024 · 12 comments

Comments

@ec-propaganda
Copy link

It would be super helpful to be able to set CSS variables instead of just properties using data-animation (or some other data attribute, if needed).

The use for this, in my case, is to be able to set a variable on a div for a rotation value to be used in a transform on a child element. We're handling all the animations on the parent div because they need to be in sync with each other, but they don't all hit the viewport at the same time, so they can't be set on the individual children. Unfortunately, we need to rotate one of the child elements, and we can't do that on the parent and have it trickle down to the children like we can with some other CSS properties (like stroke-dashoffset).

I'm sure there are some technical limitations I haven't considered, and I know this repo is pretty dormant, but I figured I'd put this here just in case it's ever revived.

@michaelrafailyk
Copy link
Owner

michaelrafailyk commented Oct 29, 2024

Hello. Did you tried the built-in feature called "data-classes"? Set up it the same way, but instead of animation, here you can add/remove CSS classes separated by space character. It works like this:

<div data-classes="25vh: {add: class1}, 50vh: {add: class2 class3, remove: class1}, 75vh: {remove: class2 class3}"></div>

@ec-propaganda
Copy link
Author

Hi! Dang, thank you for the quick response!

Yes, we've used data-classes to handle some other things like showing/hiding child elements at specific steps, but for the element that needs to rotate, it has to happen smoothly as the user scrolls, dependent on their scroll position. For more context, we have an SVG with a circle and a line going from the center of the circle to the edge (like a watch hand)—we want to smoothly rotate the line as the user scrolls. Is there a way to do that on a child element with the existing functionality?

@michaelrafailyk
Copy link
Owner

michaelrafailyk commented Oct 29, 2024

I understood. Do you mean "child element" is a subelement inside SVG?

@ec-propaganda
Copy link
Author

ec-propaganda commented Oct 29, 2024

By "child element" I mean a variety of elements—one is an SVG, several others are DIVs. I'll see if I can get a demo up somewhere so you can see what we're working with. Ultimately I think it's going to require some DOM restructuring so we can apply the animations on the child DIVs/SVG themselves instead of the parent, but I'm not quite sure how we'll do that yet. Here's a rough idea of the structure we have so far, though:

<div class="parent sticky" data-sticky="...">
    <div class="non-animated-child">
        <p>Some text. Could be very long, could be very short, 
        we'll never know because the client can change this.</p>
    </div>
    <div class="child-wrapper">
        <svg class="watch">
            <circle ...></circle>
            <path class="watch-hand" ...></path>
        </svg>
        <div class="step1">...</div>
        <div class="step2">...</div>
        <div class="step3">...</div>
        <div class="step4">...</div>
    </div>
</div>

Our goal with the above is that once the .parent div is fully in the viewport, we start animating the watch hand to go smoothly around, and then at 25vh intervals, steps 1-4 will be toggled. We're already handling the step toggling using data-classes on the .parent div, but trying to sync up the animation on the .watch-hand element doesn't work right if we put data-animation on the SVG or the PATH elements because the VH positions don't match up with the parent's due to the .non-animated-child displacing it. If we use 25vh on the .parent div in data-classes, and we use 25vh on the .watch or .watch-hand element in data-animation, those don't fire at the same time despite being the same value, which I believe is due to the top of them being positioned differently in the viewport.

@michaelrafailyk
Copy link
Owner

michaelrafailyk commented Oct 29, 2024

because the VH positions don't match up with the parent's due to the .non-animated-child displacing it

Oh I finally see what you mean. The synchronization between elements. It really requires some sandbox with +- real code for tests. Did your child-wrapper has position: relative (or absolute depending on layout) set in CSS? Try it please.

Just in the case you can't apply data-animation to subelements of SVG, you need to disable IntersectionObserver detection and use scroll event detection instead, I described it in another comment.

@ec-propaganda
Copy link
Author

Did your child-wrapper has position: relative (or absolute depending on layout) set in CSS? Try it please.

I will try this—thank you!

you need to disable IntersectionObserver detection and use scroll event detection instead.

Gotcha, I will do this too.

I'll try to follow up with a code sample if needed after doing the above.

@ec-propaganda
Copy link
Author

Here's the section we're working on (copied and pasted into CodePen) so you can see the current structure and how we've tried to set it up to keep the animations in sync: https://codepen.io/cfoster19/pen/poMpybg

@michaelrafailyk
Copy link
Owner

Thanks! So, one more time, to be sure I understand you correctly. You need to set data-animation to some element but sync it with the other element. Let's say to make element2 start his animation like if it located where element1 is located, in other words using top coordinates of element1. Is it correct?

@ec-propaganda
Copy link
Author

Yes, exactly!

@michaelrafailyk
Copy link
Owner

michaelrafailyk commented Oct 31, 2024

Nuances of working with SVG

First of all, regarding working with SVG's subelements that have data-animation or data-classes attribute.

Issue 1. IntersectionObserver in some browsers can't detect SVG (it is a known issue) so the animation may not fire. I added the parameter to quickly disable the IntersectionObserver (now you don't have to remove a bunch of code like I suggested before) – just change true to false on line 537 in the stickymate.js file (get updated version first). And after you set it to false, the scroll event will be used instead of IntersectionObserver.

Issue 2. There are a problem with getting correct position of subelements of SVG's in DOM. I haven't researched it yet but vertical position of subelements return 0 for some reason. Perhaps because SVG has its own inner body and html but not sure about that. Anyway, if you have any unexpected behavior on subelements of svg, just specify the new attribute data-sync-with I provided in this update (read a section below) and simply sync it with any other element on the same position (maybe a parent or wrapper or just svg itself). This is a workaround for now, and later I will see how to calculate it correctly.


New attribute data-sync-with

And finally, I added the new functionality you requested to stickymate.js so you need to redownload a new version.

  1. Specify the leader element which should be responsible for the synchronization. It should have some unique id that will be used as reference in follower(s) element(s).
    <div data-animation="..." id="leader"></div>

  2. Add data-sync-with="id: ..." attribute to any follower element that should follow the leader element. Specify the leader's id here instead of ....
    <div data-animation="..." data-sync-with="id: leader"></div>

Here's an example where two different followers (div and line) synchronize their virtual top position to the leader element, just like they are vertically located exactly where the leader is located, so their animations will fire simultaneously. That is, when the leader's top touches the top of the viewport, it will be 0vh for him and for all of the followers too.

<div data-animation="..." id="leader">Hey, sync with me!</div>

<div data-animation="..." data-sync-with="id: leader"></div>

<svg>
    <line data-animation="..." data-sync-with="id: leader"></line>
</svg>

Here's how it works in action

Screen.Recording.2024-10-31.at.11.33.59.mov

@ec-propaganda
Copy link
Author

You're a life saver—thank you so much! We will download a new version ASAP and put this to work. I really appreciate your help and super quick response!

@michaelrafailyk
Copy link
Owner

You are welcome! Please take your time, test it and let me know if everything works as expected.

And just in case, please download the latest version from this repository on GitHub and not from npm package (if you use npm) because I temporarily stopped to update the package on npm for a various of reasons.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants