w3c / csswg-drafts

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

[scroll-animations-1][css-animations-2] Out-of-range range offsets #8578

Closed fantasai closed 1 year ago

fantasai commented 1 year ago

Currently animation-range-start/end take <length-percentage> values to indicate a position on the timeline. By allowing <length> values in #7575, we made it possible to choose positions outside the declared range; and unless we restrict the percentages to [0%,100%], that can be done with percentages also.

The question here is, what do we do about such out-of-range values?

I think the last one makes the most sense. See also https://github.com/w3c/csswg-drafts/issues/8405#issuecomment-1464810166

bramus commented 1 year ago

We resolved on this in https://github.com/w3c/csswg-drafts/issues/8552#issuecomment-1476442986, no?

fantasai commented 1 year ago

@bramus That applies to keyframes, this is about animation-range.

flackr commented 1 year ago

I agree we should allow all values and not clamp them. This will allow authors to define animations that start just before or end just after particular ranges.

bramus commented 1 year ago

So they should not expand the attachment range and simply get clamped?

flackr commented 1 year ago

When you say clamped what do you mean? I just said I don't think we should clamp the values :-)

Note that currently if you try to animate beyond the cover range we will clip the animation to the cover range just as we clip keyframes outside of 0-100% to the active range. Update: After testing this seems to work fine in the chromium implementation - demo

bramus commented 1 year ago

Ugh. Read/wrote too fast. Clipping is what I intended.

So, by accepting all values and not clamping, would that stretch out the animation-range or would it clip?

flackr commented 1 year ago

It will stretch out the animation range. The thing you're specifying in animation-range is a start and end point on the timeline. There's nothing special about the specified range-name especially since the start and end range-name can be different and cross other ranges. (e.g. entry and exit).

ydaniv commented 1 year ago

@flackr @fantasai the clamped flow is also very important for many use-cases, e.g: effects that happen to appear on first/last folds, could happen with authoring tools or when shuffling layouts on different breakpoints.

It's good that by default we don't clamp, but it's very important that author can also choose to opt-in to respecting the effect playing from start to end regardless of layout.

If we could have something that behaves like min(0px, entry 0%) that would allow this clamping, but this depends on what we resolve in #8672. If we allow <length-percentage> to resolve to an absolute offset then we could allow authors to achieve that without any additional syntax.

ydaniv commented 1 year ago

Another issue with something like using min(entry 0%, contain 100%) for start in first fold, for example, is that it will just choose the lowest between the two, and not really interpolate and map the 0% progress to the actual starting point of the range.

So my use case is, if something has an effect that should run from 0% to 100% progress, regardless of layout, but it happens to load inside the viewport in first fold, then there's no range that the author can set and guarantee that it will happen.

flackr commented 1 year ago

If we could have something that behaves like min(0px, entry 0%) that would allow this clamping, but this depends on what we resolve in #8672.

Does it depend on #8672? Can't you specify all possibilities using the longhands?

If we allow <length-percentage> to resolve to an absolute offset then we could allow authors to achieve that without any additional syntax.

Using absolute offsets is already supported by spec using the non-named-range <length-percentage> version of animation-range on a scroll timeline. https://www.w3.org/TR/scroll-animations-1/#animation-range-start

There's an open bug to get this working in chromium's implementation.

Maybe we should revisit the range of view-timeline and make it so that it can reference ranges over the entire scroll which I think would directly support your use case, e.g.

.target {
  /* Animate from initial scroll position to exit. */
  animation-range-start: 0px;
  animation-range-end: exit 100%;
}

Or if we want to allow for the start phase to be later than 0px,

.target {
  /* Animate from initial scroll position to exit. */
  animation-range-start: max(0px, entry 0%);
  animation-range-end: exit 100%;
}

Another issue with something like using min(entry 0%, contain 100%) for start in first fold, for example, is that it will just choose the lowest between the two, and not really interpolate and map the 0% progress to the actual starting point of the range.

If the keyframes are not specified in terms of range attachment points, they will map to the entire range name, so a 0% keyframe will occur at the result of this range calculation.

ydaniv commented 1 year ago

Does it depend on https://github.com/w3c/csswg-drafts/issues/8672? Can't you specify all possibilities using the longhands?

If <percentage> without a range name is not computed differently, i.e. expanded to a <name> + <percentage>, then maybe it doesn't depend on #8672, but I was assuming that for view-timelines a <length-percentage> will always be expanded that way.

Using absolute offsets is already supported by spec using the non-named-range version of animation-range on a scroll timeline. https://www.w3.org/TR/scroll-animations-1/#animation-range-start

There's an open bug to get this working in chromium's implementation.

Yes, we support <length> for attaching to an absolute offset on scroll-timelines, but I was hoping we could use existing syntax to also limit effects and mapping their progress to the given layout.

Maybe we should revisit the range of view-timeline and make it so that it can reference ranges over the entire scroll which I think would directly support your use case, e.g.

.target {
/* Animate from initial scroll position to exit. */
animation-range-start: 0px;
animation-range-end: exit 100%;
}

Yes, that could be useful. But I realize this should be on a separate issue (:


Back to the issue at hand, if I understand it correctly, the question is: "do we allow range offset values that correspond to outside the entire cover range", correct?

So regarding @flackr's comment:

I agree we should allow all values and not clamp them. This will allow authors to define animations that start just before or end just after particular ranges.

This is specifically the case with effects like:

@keyframe parallax {
  from {
    transform: translateY(-500px);
  }
  to {
    transform: translateY(500px);
  }
}

.parallaxed {
  animation: parallax both view();
  animation-range: cover 0% cover 100%;
}

Because we ignore the transforms, the animation will actually start when the element is 500px above cover 0% and end when the element is 500px below cover 100%. Now, there are 3 ways to tackle this:

  1. Extend the effective scrollport with view-timeline-inset: -500px.
  2. Allow negative values like suggested here, and set: animation-range: entry -500px exit 500px or with calc()'s: calc(entry 0% - 500px) calc(exit 100% + 500px), but I assume these are equivalent, right?
  3. Use a named view-timeline on a different element that's 1000px higher and the .parallaxed element is centered inside it.

Same can be said for effects where the animated element is offset from the view-timeline subject and or extends beyond it.

I think option 3 requires an extra element, so having to resort to that is a less desirable solution.

So, if my conclusion is correct, it's either we clamp for simplicity's sake, or we allow offsets that are out-of-range? I think we can allow out-of-range if that makes more sense to authors, no particular reason why not to allow it also.

flackr commented 1 year ago

Because we ignore the transforms, the animation will actually start when the element is 500px above cover 0%

Technically the element isn't 500px above cover until the animation starts 😉

I think that either options 1 or 2 should work. Note that the range name can't go inside the calc. Option 2 would be animation-range: entry -500px exit calc(100% + 500px);. exit 500px is equivalent to exit calc(0% + 500px) which is 500px after the start of the exit range which isn't what you want in your use case.

So, if my conclusion is correct, it's either we clamp for simplicity's sake,

I don't think we should clamp. It results in animations which behave differently if the animated element is near the top/bottom of the document versus further down.

or we allow offsets that are out-of-range? I think we can allow out-of-range if that makes more sense to authors, no particular reason why not to allow it also.

Yes, I think we should allow out-of-range values.

Note I tested this and it seems the chromium implementation already supports this (requires a very recent version e.g. >=115.0.5767.0): https://jsbin.com/hitegay/edit?html,css,js,output

ydaniv commented 1 year ago

@flackr SGTM.

Another use-case for explicitly clamping, the following can work for ensuring something animates from entry, even if in some screen/layout it appears in first fold, and in others it's below:

.target {
  animation-range-start: max(100vh, entry 0%);
  animation-range-end: contain 50%;
}

Regarding negative values, if we'll use absolute values without a range name to refer to the entire scroll range, then negative values become practically useless. Perhaps we should consider again using these to specify offsets from the end of the scroll range?

flackr commented 1 year ago

Another use-case for explicitly clamping, the following can work for ensuring something animates from entry, even if in some screen/layout it appears in first fold, and in others it's below:

.target {
  animation-range-start: max(100vh, entry 0%);
  animation-range-end: contain 50%;
}

I suspect it would be hard to support range names within the calc. Maybe it could be done - since the entry 0% effectively turns into a proportion of the timeline range which is comparable with 100vh - but I think this could get complex.

Regarding negative values, if we'll use absolute values without a range name to refer to the entire scroll range, then negative values become practically useless. Perhaps we should consider again using these to specify offsets from the end of the scroll range?

I think negative values are still useful when associated with a range name, e.g.

.target {
  /* Start 50px before the contain phase */
  animation-range-start: contain -50px;
}

While we could do something different when no range name is given, I worry that it would be very magical, and also make it harder to work with calcs. E.g. imagine your calc sometimes produces a negative value - it shouldn't suddenly flip to the end of the range.

ydaniv commented 1 year ago

D'oh! I messed up the example, took screen end instead of start, should be:

.target {
  animation-range-start: max(0%, entry 0%);
  animation-range-end: contain 50%;
}

I suspect it would be hard to support range names within the calc. Maybe it could be done - since the entry 0% effectively turns into a proportion of the timeline range which is comparable with 100vh - but I think this could get complex.

I guess this requires transforming range names into functions, and then they could be simply parsed as <length>, right? Is there another option?

I think negative values are still useful when associated with a range name, e.g.

.target {
  /* Start 50px before the contain phase */
  animation-range-start: contain -50px;
}

Yes of course, it's useful for names in that way, but useless for absolute values.

While we could do something different when no range name is given, I worry that it would be very magical, and also make it harder to work with calcs. E.g. imagine your calc sometimes produces a negative value - it shouldn't suddenly flip to the end of the range.

Yep, that's a real concern. I guess this is something that can be added later if demand arises.

bramus commented 1 year ago

Looking at the original issue, this was about allowing values greater than 100% and less than 0%. Maybe we should split off the min/max functionality to a separate issue?

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [scroll-animations-1][css-animations-2] Out-of-range range offsets, and agreed to the following:

The full IRC log of that discussion <TabAtkins> flackr: This is about whether we allow animation-range offsets outside the 0-100% range, and if so what we do with them
<TabAtkins> flackr: I propose we do allow them, and we have the animation-range account for that range (so the animation conceptually begins before the timeline start). This is already well-defined.
<TabAtkins> flackr: Also fairly consistent with the way we allow keyframe offsets outside the animation active interval.
<TabAtkins> (Also consistent with gradients.)
<TabAtkins> flackr: I think it's also useful to have negative values so you can define an animation portion as starting before some other range.
<TabAtkins> +1
<ydaniv> q+
<miriam> ack ydaniv
<TabAtkins> ydaniv: Is there weirdness with non-named ranges, having values outside the range?
<TabAtkins> flackr: Why is that weird
<TabAtkins> ydaniv: With named ranges you may still have more scroll range
<TabAtkins> ydaniv: when you use the entire scroll range there's nothing outside of 0-100
<TabAtkins> flackr: That's not true with view timelines, because their complete range is "cover" but they do produce values outside of 0-100
<TabAtkins> flackr: But even so, having implicit clipping at the scroll limit is alreayd part of the API in terms of how keyframes work, and how named ranges work if you can't scroll to that full range. So I think it's consistent.
<TabAtkins> miriam: So if the value is outside 0-100 and there's no way to get to there, it's clipped?
<TabAtkins> flackr: It's implicitly clipped - if you have an animation start at -20%, when the animation actually starts it'll actually have already gone thru 20% of the animation.
<TabAtkins> flackr: Proposed resolution is allow timeline ranges outside of 0-100% range, and use them as-is for existing animation start-time and duration calculations.
<TabAtkins> miriam: Objections?
<TabAtkins> RESOLVED: allow timeline ranges outside of 0-100% range, and use them as-is for existing animation start-time and duration calculations.