w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 664 forks source link

Split CSS event bindings from application #4343

Open scottkellum opened 5 years ago

scottkellum commented 5 years ago

It would be ideal to have animations handle more arbitrary units. Such as units other than time like length, as an input. Inputs might be handled from some sort of event API within CSS. There are ways, by using animation delays, to hack this feature, but there are ways to make things more elegant that would make life easier both in animations and outside of animations.

  1. Similar to gradient stops, keyframes that take arbitrary units not just %. So if you want to trigger something 300px down the page, you set the keyframe at 300px.
  2. Expose scroll position as a CSS unit or function. This would be handy for numerous things people add event listeners in JS to, not just scroll.
  3. Allow binding to increments other than time. Having an animation duration in a length value would have the animation run across length, not time.

What this might look like for scroll:

.newspaper {
  animation: progress 100px linear;
  animation-timeline: scroll(element(#body), vertical, "0px", "100px");
}
@keyframes {
  0px {
    opacity: 0;
    transform: rotate(-720deg);
  }
  100px {
    opacity: 1;
  }
}

This also frees you up to bind to other things, like viewport width, element width, device orientation, ambient light, video progress, range sliders, etc…

What is the output of scroll functions and how can they be isolated from animations?

with something like this: scroll(element(#container), vertical, "300px", "500px")

Can this be used outside of a timeline? For example, could I attach this to a property inside of calc() and at 400px have it return .5? What are the advantages of making this a new thing vs attaching these bindings to animation delay? I see a lot of value here for things beyond animations and animations themselves can already handle rebinding of timeline. The timeline syntax is much nicer but I’m curious if there are going to be conflicts within the animation value.

Binding keyframes to scroll in today’s CSS:

It’s exciting to see this spec as I have prototyped a lot of this functionality in today’s CSS. Here is what scroll depth would look like with animation: keyframes 1s linear 1 calc(-1s*var(--depth)/var(--max-depth)) paused;

And this library surfaces JS events to CSS so you can feed them into things like the animation above: https://github.com/scottkellum/momentum

typetura.js binds to the viewport, and with a slight modification it can bind to scroll depth: https://github.com/typetura/typetura.js#starting-with-the-basics

birtles commented 5 years ago

Thanks for your feedback. I think it would be a little more easy to process, however, by describing the particular use cases that are problematic.

Also, in the sample code, it seems like there are three places (animation-duration, scroll() and @keyframes) specifying the same 100px range so I'm a bit unclear what they each represent.

scottkellum commented 5 years ago
  1. The thing I find most confusing when working with remapped animations is that they now measure length, not time. A value like 1s becomes irrelevant to the animation. I was trying to illustrate how you might convert time based and percentage based units so something more representational of where the keyframes fall. I think the gradient stop syntax might be a good model to reference.
  2. There are numerous bindings other than scroll depth that would be valuable. I mostly use viewport or element width. I can imagine device orientation, cursor position, etc might be valuable bindings for animation. At a simpler level, they might be valuable functions outside of animation as well. The scroll timeline doesn’t need to be tied to an animation, it could be width: calc(scroll(element(#body)) / height(element(#body))) * 1%. Having these bindings as generic CSS functions would be valuable for simpler styling.
  3. If these timeline functions were more generic, what is the outputted value? Can I feed in my own value? This is useful for specifying where an animation is positioned and allows you to extend what you bind that animation to. You could even pass an arbitrary value into this animation to emulate something like Sass color mixing functions.

There are numerous ideas in this thread, sorry it’s probably confusing. I couldn’t figure out how to break them down more. Hopefully this makes sense though?

scottkellum commented 5 years ago

Here’s a quick example of CSS keyframes bound to scroll with today’s CSS: https://codepen.io/scottkellum/pen/WWeXab?editors=1100

I think this spec makes it a little easier to achieve the code above. That said, having played with this technique for a while I’ve found

  1. The time + percentage based metaphor within animations is confusing when animations are bound to spacial inputs.
  2. binding to values other than scroll. I’ve found this to be incredibly useful with width.
flackr commented 2 years ago

Thanks for all of the details here.

  1. Similar to gradient stops, keyframes that take arbitrary units not just %. So if you want to trigger something 300px down the page, you set the keyframe at 300px.

Issue #7575 proposed this idea as well as a way of bringing back scroll offsets to the API. I think this could be reasonable. I propose we keep the discussion there since there are a few other issues in this one.

  1. Expose scroll position as a CSS unit or function. This would be handy for numerous things people add event listeners in JS to, not just scroll.

I don't think this part would be part of the scroll-animations-1 spec. While possible, this would implicitly create animations through direct style values, which would likely be difficult for engines to optimize (e.g. it's less clear if used in a calc whether a scroll change can be directly mapped to output style). Though you can still do this more explicitly by animating a custom property with a scroll linked animation and using that custom property in other calculations, and in this case there is an explicit animation running.

  1. Allow binding to increments other than time. Having an animation duration in a length value would have the animation run across length, not time.

This seems reasonable. We have already moved away from time and are currently using percentages, but there's some discussion in #4342 about this and would play well with the plan in #7044 to allow specifying delay and end delays relative to phases (we could add lengths).

scottkellum commented 2 years ago

Thanks for the updates @flackr!

Some more notes on this from other angles as things have progressed in the past 3 years elsewhere:

The language seems to be moving away from “animation” to the more appropriately abstracted “interpolation”. IE “Interpolation timelines”

sources: https://css.oddbird.net/rwd/interpolation/ https://wiki.csswg.org/ideas/timelines