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

[scroll-animations-1] Bring back Scroll Offsets #7575

Closed
bramus opened this issue Aug 4, 2022 · 38 comments
Closed

[scroll-animations-1] Bring back Scroll Offsets #7575

bramus opened this issue Aug 4, 2022 · 38 comments
Labels
Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. scroll-animations-1 Current Work

Comments

@bramus
Copy link
Contributor

bramus commented Aug 4, 2022

One of the things that did not make it into the scroll-animations rewrite is the ability to animate as a scroller scrolls for a fixed distance. This used to be covered by the scroll-offsets.

There are some use-cases, such as this cover page that transforms to a header bar as you scroll over a distance of 90vh.

One could use use a ViewTimeline here, but not on the cover/header element itself because it is sticky and therefore never exits. Instead, one would have to look at the succeeding element.

This, however, is only possible if all of these apply:

  1. There is a succeeding element
  2. That succeeding element is not in view at the start of the animations, so you can watch it enter
  3. The ViewTimeline can be seen by the preceding header

The first 2 conditions might not always be the case, but the author could work around that if they rearrange some things in their markup. The 3rd condition is not possible, since we decided in #7047 to have “timeline search look at preceding siblings and ancestors”.

Therefore I think we should reintroduce the Scroll Offsets.

@ydaniv
Copy link
Contributor

ydaniv commented Aug 7, 2022

Isn't it what we have ScrollTimeline for? Isn't that simply a use-case for that?
Or, if the author prefers using ViewTimeline, then it makes sense they have a revealing element that holds the timeline, and the header is simply the target of the animation. Which should be straightforward using the current API, or did I miss something and it's not?

@ydaniv
Copy link
Contributor

ydaniv commented Aug 7, 2022

Ok, just checked and we did lose that ability on SctollTimeline. We definitely need to have offset and duration defined by <length>s, same as ViewTimeline can define those using phases.
So @bramus I guess this was the intention here?

@bramus
Copy link
Contributor Author

bramus commented Aug 8, 2022

I’ve given this some thought over the weekend, and could think of a few possible scenarios to tackle this:

  1. Bring back the old scroll-offsets as scroll-timeline-offsets

    This seems like a straightforward thing, but is too limiting. For example:

    body {
      scroll-timeline: body-tl block;
      scroll-timeline-offsets: 0 90vh; /* 👈 */
    }
    
    @keyframes shrink {
      from { height: 100vh; }
      to { height: 10vh; }
    }
    
    #coverheader {
      position: sticky;
      top: 0;
      animation-name: shrink;
      animation-timeline: body-tl;
    }

    By defining the offsets on the ScrollTimeline itself, the entire ScrollTimeline is limited to the range 0 - 90vh. What if the authors want to animate on scroll outside of that range (e.g. from 90vh to 100%)? This is not possible with this approach, unless authors are able to define multiple ScrollTimelines on the same element.

  2. Allow scroll as a (faux) phase with <length-percentage>

    Following the way ViewTimeline phases are defined, a scroll phase could be introduced. That way there still is 1 set of keyframes and 1 ScrollTimeline. In the keyframes, authors can target several parts of the timeline by prefixing that phase to the keyframe offsets.

    body {
      scroll-timeline: body-tl block;
    }
    
    @keyframes shrink {
      scroll 0 { height: 100vh; }  /* 👈 */
      scroll 90vh { height: 10vh; }  /* 👈 */
    }
    
    #coverheader {
      position: sticky;
      top: 0;
      animation-name: shrink;
      animation-timeline: body-tl;
    }

    Authors would need to explicitly target the (faux) scroll phase if they want to use it with a ScrollTimeline. Instead of accepting only <percentage>s as the keyframe offset, <length>s would now also be valid here.

    One of the cool things about the whole scroll-linked animations concept is that you can use regular keyframes without needing to target any phase. If wanted, maybe, it could be so that “no phase implies the scroll phase” when used with a ScrollTimeline?

    @keyframes shrink {
      0 { height: 100vh; } /* When used linked to a ScrollTimeline, this would imply the scroll phase */
      90vh { height: 10vh; } /* When used with a DocumentTimeline animation, this would be invalid as it’s no <length> */
    }
  3. Introduce animation-timeline offsets

    A third option would be to introduce the scroll-offsets on the animation-timeline level. There would be two properties: animation-timeline-start and animation-timeline-end, with a <length-percentage> as their allowed value.

    body {
      scroll-timeline: body-tl block;
    }
    
    @keyframes shrink {
      from { height: 100vh; }
      to { height: 10vh; }
    }
    
    #coverheader {
      position: sticky;
      top: 0;
      animation-name: shrink;
      animation-timeline: body-tl;
      animation-timeline-offsets: 0 90vh;  /* 👈 */
    }

    This approach keeps the ability to define 1 ScrollTimeline on a an element and also to target parts of it when linking an animation. However, authors would need to attach two animations/keyframes when targeting various offsets.

    #coverheader {
      animation-name: shrink, otheranimation;  /* 👈 */
      animation-timeline: body-tl, body-tl;  /* 👈 */
      animation-timeline-offsets: 0 90vh, 90vh 100%;  /* 👈 */
    }

    One of the key things that ViewTimeline introduced, was the ability for authors to define 1 set of keyframes which can target all different phases if needed. This approach with animation-timeline-offsets does not offer this.

  4. Something else?

@bramus bramus added the scroll-animations-1 Current Work label Aug 8, 2022
@flackr
Copy link
Contributor

flackr commented Aug 9, 2022

This feels very similar to issue #7296 though I like some of the suggestions to handle this in a way similar to the way enter/exit phases are handled for ViewTimeline (See #7044). Following that thread, I think rather than offsets we could use whatever we decide the new shorthand for specifying start and end delay to set the range of the animation, e.g.

#coverheader {
  animation-delay: 0 90vh, 90vh 100%; /* Same as setting startDelay to 0 and 90vh respectively and endDelay to 90vh and 0 respectively. */
}

@ydaniv
Copy link
Contributor

ydaniv commented Aug 9, 2022

Yes, since we already decided, at least for now, that these are properties of the animation, and not of the timeline. So these should go, as @flackr said above, on the animation property as startDelay and duration/endDelay.

Though this still makes @bramus's no. 2 suggestion valid, at least conceptually, with regard to the @keyframes extension.

@bramus
Copy link
Contributor Author

bramus commented Aug 9, 2022

The extra added phase would leave the path for future additions open. Say a HoverTimeline were to be added, then it’s only a matter of adding a hover phase.

When no explicit phase is defined in the keyframes, the phase could be implied from the usage: adding non-phased keyframes to a ScrollTimeline? Use those “regular” keyframes. Adding keyframes that have a scroll phase to a ScrollTimeline? Use those scroll keyframes, ignoring the non-phased keyframes.

@bramus
Copy link
Contributor Author

bramus commented Sep 21, 2022

Some authors who have been playing around with the polyfill have raised similar issues, asking about offsets no longer being available.

  1. ScrollTimeline offsets are no longer respected after last update. flackr/scroll-timeline#64
  2. scrollOffset not working anymore flackr/scroll-timeline#76

The recent Motion One scroll library that enables JS-based Scroll-Linked Animations also offers this ability.

As @flackr suggested above, it could be achieved by having animation-delay-start and animation-delay-end accept lengths as their value.

  • animation-delay-start = [ <time> | <timeline-range-name> <percentage> | <length> ]
  • animation-delay-end = [ <time> | <timeline-range-name> <percentage> | <length> ]

@flackr
Copy link
Contributor

flackr commented Sep 27, 2022

FWIW I was thinking allowing lengths or percentages for ranges would allow greater flexibility:

animation-delay: [ <time> | <timeline-range-name>? [<percentage> | <length>]]+

Then you could use calculations within ranges, e.g.

/* Starts 10px after entering until 10px before done entering. */
animation-delay: enter 10px enter calc(100% - 10px);

@bramus
Copy link
Contributor Author

bramus commented Sep 27, 2022

Oh yes, great tweak! I like it!

@bramus
Copy link
Contributor Author

bramus commented Sep 28, 2022

@fantasai Could we get input from you on this before the spec goes to FPWD? Would love to get this back in there before the spec moves forward.

@meyerweb
Copy link
Member

FWIW I was thinking allowing lengths or percentages for ranges would allow greater flexibility:

Then you could use calculations within ranges, e.g.

I like the idea of adding length-percentages to animation-duration and animation-delay, particularly since viewport units could then be used.

@fantasai
Copy link
Collaborator

A few questions:

  • When a length delay or duration is applied to a time-based animation, what does it resolve to?
  • When a time delay is applied to a length-based animation, what happens? Do we create lag in the animation or ignore it or...?
  • If an offset applied to a range is outside the range (outside 0%-100%), do we clamp it or not?

@ydaniv
Copy link
Contributor

ydaniv commented Nov 2, 2022

  • When a length delay or duration is applied to a time-based animation, what does it resolve to?
  • When a time delay is applied to a length-based animation, what happens? Do we create lag in the animation or ignore it or...?

I don't think this use-case is relevant to consider. As I suggested in #7944, time for delay and duration only make sense for time-based animations and length makes no sense there. And vice versa, if the animation has a timeline which isn't time-based, duration is irrelevant (since it's always 100%), and time for delay makes no sense.
So we could ignore delay in this case and only parse the ranges (or use default values for ranges).

If an author wants to include both in @keyframes to be used for either case they could write it as follows:

@keyframes fade-in {
  0%, enter 20% {
    opacity: 0;
  }
  100%, enter 100% {
    opacity: 1;
  }
}

@fantasai
Copy link
Collaborator

fantasai commented Nov 2, 2022

I don't think this use-case is relevant to consider.

It doesn't matter if it's a use case or not, the behavior needs to be defined.

@ydaniv
Copy link
Contributor

ydaniv commented Nov 2, 2022

It doesn't matter if it's a use case or not, the behavior needs to be defined.

Yes, what I mean is that IMO these cases, where length is applied to time-based animations and time applied to length-based animations, should be treated as invalid and ignored.

  • If the animation has a timeline that's length-based then it should only accept length values - ignore duration and delay and only accept ranges.
  • If the animation is time-based, i.e. animation-tlmeline resolved to auto, then it should only accept time values as it does now, and ignore ranges.

This should also remove ambiguity from animation-delay and resolve the confusion with animation-range which currently only serves as an alias.

@fantasai
Copy link
Collaborator

fantasai commented Nov 7, 2022

@ydaniv We can't make property parsing conditional on the value of another property. :) So we have to do something different, either zeroing out the mistyped values or treating the properties as having their initial value or something.

@fantasai
Copy link
Collaborator

fantasai commented Nov 7, 2022

To summarize, I think we've got the following proposals up for debate:

  • Add <length-percentage> to animation-delay and animation-duration
  • Length delays resolve to 0s when applied to time-based animations and vice versa. (Percentage components are maintained intact.)
  • Length-based durations are ignored (treated as initial value) when applied to time-based animations, and vice versa.
  • Offset values are not clamped within their declared range.

@birtles Interested in your take on this discussion!

@birtles
Copy link
Contributor

birtles commented Nov 19, 2022

To summarize, I think we've got the following proposals up for debate:

  • Add to animation-delay and animation-duration

  • Length delays resolve to 0s when applied to time-based animations and vice versa. (Percentage components are maintained intact.)

  • Length-based durations are ignored (treated as initial value) when applied to time-based animations, and vice versa.

  • Offset values are not clamped within their declared range.

@birtles Interested in your take on this discussion!

Thanks for including me and sorry for the delay (I was away last week and forgot to update my GitHub status).

I'm afraid I haven't been following the scroll animation discussion very closely so my input is probably not particularly valuable. Two very high-level notes, however:

  1. An Animation is intended to be the vehicle that maps a static effect onto a timeline so extending the animation as in option 3 from the original list of options would be the most natural fit from an architectural point of view.

    Because animation-delay maps onto an effect it feels a little misaligned to me (i.e. the effect was supposed to be a "dumb", static, stateless thing agnostic of how it is used), but see the next point.

  2. When we started out with scroll-linked animations, we were under the assumption that it would be desirable to dynamically switch between a time-based timeline and a scroll-based one (e.g. when the scroll passed some threshold, the author would use JS to swap out the timeline to a time-based one, letting the animation run to completion).

    Introducing different units to animation-delay and animation-duration such that some units are ignored depending on the type of timeline doesn't seem to be compatible with that assumption (or with the notion that effects are independent of how they are used), but maybe we've determined it's no longer an important use case?

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [scroll-animations-1] Bring back Scroll Offsets, and agreed to the following:

  • RESOLVED: Add length % to animation-range to be used as offsets
The full IRC log of that discussion <flackr> q+
<dael> Rossen_: Let's see if we can resolve on this one
<dael> flackr: Given that animation-range specifies the range the animation runs in, if we add length as well I think it solves use case and don't need lengths added to delay
<Rossen_> ack flackr
<birtles> q+
<dael> birtles: I think that's good. Good to push it down the road and consider how it interacts with group effects
<dael> fantasai: Prop: Add length % to animation-range to be used as offsets
<dael> Rossen_: Objections?
<dael> RESOLVED: Add length % to animation-range to be used as offsets
<birtles> ("Pushing it down the road" here refers to adding lengths to animation-delay)

@ydaniv
Copy link
Contributor

ydaniv commented Feb 3, 2023

A question regarding the resolution above, does it mean that the value of animation-range can be :

  1. <animation-range-name> <length-percentage>?
  2. <animation-range-name> <percentage> OR <length-percentage>?

If it's 1 then we have an ambiguity issue here.

FYI @fantasai @flackr

@bramus
Copy link
Contributor Author

bramus commented Feb 22, 2023

I was under the impression we decided that <length-percentage> can be added to a <animation-range-name> (for use with ViewTimeline), but that it could also be use without a <animation-range-name> (for use with ScrollTimeline). So yeah, needs some clarification to see what exactly we resolved on.

@ydaniv
Copy link
Contributor

ydaniv commented Feb 23, 2023

@bramus unless I'm missing something, but from what I can see range names have no use with ScrollTimeline. ScrollTimeline should be using simple <length-percentage> for duration and/or offsets, which we resolved on using ranges instead of delays - since delays have time values.

@bramus
Copy link
Contributor Author

bramus commented Mar 2, 2023

My original request for this issue was to be able to run a scroll-driven animation over a certain distance (in case of the header example: as you scroll the page from 0 to 90vh). The way I interpret the resolution, is that it would now be possible to do this as follows:

@keyframes shrink {
  from { height: 100vh; }
  to { height: 10vh; }
}

#coverheader {
  position: sticky;
  top: 0;
  animation-name: shrink;
  animation-timeline: scroll(); /* 👈 Will find the root scroller */
  animation-range: 0 90vh; /* 👈 Animation will run when scrolling from 0vh to 90vh */
}

If that’s incorrect, then the resolution from #8298 (comment) might offer a solution, as it calculates the timeline ranges differently now. IUC correctly, the combined outcome would allow this:

@keyframes shrink {
  from { height: 100vh; }
  to { height: 10vh; }
}

#coverheader {
  position: sticky;
  top: 0;
  animation-name: shrink;
  animation-timeline: view(self); /* 👈 Track myself */
  animation-range: exit 0 exit 90vh; /* 👈 This works because of #8298 */
}

Maybe @flackr or @fantasai can clarify?

@ydaniv
Copy link
Contributor

ydaniv commented Mar 2, 2023

If the header is stuck at top: 0 then the way I see it is:

In the first example:

#coverheader {
  position: sticky;
  top: 0;
  animation-name: shrink;
  animation-timeline: scroll();
  animation-range: 0 90vh;
}

Will start the animation at scrollY=0 and continue until scrollY=90vh.

In the second example:

#coverheader {
  position: sticky;
  top: 0;
  animation-name: shrink;
  animation-timeline: view(self);
  animation-range: exit 0 exit 90vh;
}

Regarding the range start, animation won't start running while the header is stuck, because it's still in contain range.
Only when it starts exiting, it starts shrinking.
As for the range end, I'm not sure we have a clear definition of what exit 90vh means? Is that the same as exit 0% + 90vh? - 90vh?
I think we need to resolve on #8054 to answer that.

@flackr
Copy link
Contributor

flackr commented Mar 10, 2023

@bramus you are correct, the intent is to allow both with or without an animation-range as an alternative to a percentage on non-time based timelines. i.e. your first example should work.

@flackr
Copy link
Contributor

flackr commented Mar 10, 2023

As for the range end, I'm not sure we have a clear definition of what exit 90vh means? Is that the same as exit 0% + 90vh? - 90vh? I think we need to resolve on #8054 to answer that.

exit 90vh is equivalent to exit calc(0% + 90vh).

@ydaniv
Copy link
Contributor

ydaniv commented Mar 10, 2023

@flackr great! But then I think we have an ambiguity here, see #7575 (comment). Should I open a new issue for this?

@flackr
Copy link
Contributor

flackr commented Mar 10, 2023

Sorry perhaps I'm just a bit slow today but can you explain the ambiguity? What's an example? Happy to see a new issue for that if you don't mind filing it.

fantasai added a commit that referenced this issue Mar 11, 2023
* Add <length> offsets to timeline range offsets
* Add <length-percentage> values referencing the whole timeline
* Tighten up definitions
@fantasai
Copy link
Collaborator

Fixed in 43b12e4 ; @bramus @flackr, let me know if I missed anything.

@ydaniv
Copy link
Contributor

ydaniv commented Mar 11, 2023

@fantasai I've added comments in the commit on specific lines.

@fantasai
Copy link
Collaborator

@ydaniv Replied. OK to close the issue?

@ydaniv
Copy link
Contributor

ydaniv commented Mar 14, 2023

@fantasai yes, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. scroll-animations-1 Current Work
Projects
None yet
Development

No branches or pull requests

7 participants