Skip to content

[scroll-animations-2] Allow named ranges to be used with math functions #8852

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

Open
ydaniv opened this issue May 18, 2023 · 16 comments
Open

[scroll-animations-2] Allow named ranges to be used with math functions #8852

ydaniv opened this issue May 18, 2023 · 16 comments

Comments

@ydaniv
Copy link
Contributor

ydaniv commented May 18, 2023

Currently the spec treats <timeline-range-name> as an <ident> and a named range is specified as <timeline-range-name> <length-percentage>.

A range can also be simply a <length-percentage> without a name for use with ScrollTimelines, and there's a suggestion for allowing the same for ViewTimelines, for attaching to the entire scroll range.

However, there are some use-cases, which are currently not addressed, more specifically: clamping a scroll range at the edges of the scroll container, so the effect, for example, will always start at 0% progress or end at 100% progress, regardless of layout.

Example could be an element that has the following animation:

@keyframes fadeIn {
  from {
    opacity: 0;
  }
}

.target {
  animation: fadeIn auto both view();
  animation-range: entry;
}

But when the page loads the target is already partially visible in the viewport. So it will present on load as semi-transparent.

One way to address these could be but can be done if we could use named ranges inside math functions, so authors could write it as:

@keyframes fadeIn {
  from {
    opacity: 0;
  }
}

.target {
  animation: fadeIn auto both view();
  animation-range: max(0%, entry 0%) entry 100%;
}

So questions are:

  • can we make it possible?
  • does this require syntax changes? Or just spec changes to how these types interact?

cc @fantasai @flackr @bramus

@tabatkins
Copy link
Member

Unfortunately that's not currently possible. It would be a pretty decent syntax and processing change to allow arbitrary values like that. It's something we'd certainly like to do eventually, especially for things like this where the keyword converts directly into a numeric value and doesn't otherwise change the behavior of the property (unlike, say, width, where a bunch of things care whether the value is definite, content-based, or indefinite).

The best way to hack this in would be via a special function, valid in animation-range, that took a keyword+percentage pair and resolved it to a %. It would be a no-op when used on its own, but it would allow math functions to just treat it like a percentage, which is well-defined.

@tabatkins tabatkins added the scroll-animations-1 Current Work label May 18, 2023
@fantasai
Copy link
Collaborator

fantasai commented Jun 2, 2023

@ydaniv I'm not sure I understand your use case. You want the element to be fully opaque as soon as it's visible, right? So why would it have a fade-in animation during entry?

@ydaniv
Copy link
Contributor Author

ydaniv commented Jun 3, 2023

Since we resolved on not clamping timeline ranges by default, I still want to allow it as opt-in.
So my use case is an element with an entry animation that should play from 0% progress. Now, either that element is out of the first fold and a timeline from entry 0% can play from it's beginning, or on a specific screen it may load inside first fold and will appear as semi transparent.
It's also important for authoring tools where effects are generic but a consistent experience is desired by the user.

I guess we can achieve this opt-in in other methods, but this one seemed the most simple one.

@fantasai
Copy link
Collaborator

fantasai commented Jun 5, 2023

@ydaniv so, for a fade-in animation, if the element is 10% on screen, you want the animation to be equivalent to entry 10% entry 100%, i.e. fully transparent until the user starts scrolling?

@ydaniv
Copy link
Contributor Author

ydaniv commented Jun 6, 2023

@fantasai correct. The idea is to allow author to opt-in to the UA respecting the full effect progress from 0% to 100% (same in end of scroll container), what we called before "clamping".

@fantasai
Copy link
Collaborator

fantasai commented Jun 6, 2023

@ydaniv Do you want the same effect if that image is 90% above the fold? Should it still be fully transparent at that point?

@ydaniv
Copy link
Contributor Author

ydaniv commented Jun 6, 2023

@fantasai of course at some point the range may become ridiculously short. In some cases it would make sense to disable that effect completely. Assuming this is a case that happens mostly in an authoring tool, then disabling the effect would be even preferred.
But the main use-cases are on the edges, where an element can't start from 0% or end at 100%.

@bramus
Copy link
Contributor

bramus commented Jun 13, 2023

Another use-case would be this one right here:

image

The bottom right image reveals itself from cover 25% to cover 50% but is never fully revealed as we’re at the bottom of the page.

Setting the animation-range-end to the fictitious min(100%, cover 50%) would fix that, by shortening the animation scroll distance. Side-effect is that it runs “faster”.

The best way to hack this in would be via a special function, valid in animation-range, that took a keyword+percentage pair and resolved it to a %.

Would that be something like min(resolve(100%), resolve(cover 50%)), or more like min-range(100%, cover 50%)?

@ydaniv
Copy link
Contributor Author

ydaniv commented Jun 13, 2023

Thanks @bramus! Yep, that's the use-case for animations at end of scroller.

The best way to hack this in would be via a special function, valid in animation-range, that took a keyword+percentage pair and resolved it to a %.

Would that be something like min(resolve(100%), resolve(cover 50%)), or more like min-range(100%, cover 50%)?

If we use min() it's resolved as a <length-percentage> and then used as offset from cover's 0%.
So perhaps the latter, that can be resolved to a "range attachment", or something that's neither a name+length or a length.

@bramus
Copy link
Contributor

bramus commented Jun 15, 2023

Just had another related request where someone wanted to run an animation from exit 100% + 30px to exit 100% - 30px. That way the animation would run during “the last 60px of exiting”.

Relying on percentages to run the animation – e.g. from exit 95% to exit 100% – wasn’t an option, as some of the elements are much more taller then others, resulting in values from as low as 40px distance up to 180px.

Right now they are working around it by injecting a sentinel div of 60px height at the bottom of the element, which they are then tracking.

@ydaniv
Copy link
Contributor Author

ydaniv commented Jun 15, 2023

@bramus they should be able to specify exit calc(100% - 30px) exit calc(100% + 30px), though not calc(exit 100% + 30px) as this issue suggests

@bramus
Copy link
Contributor

bramus commented Jun 15, 2023

@bramus they should be able to specify exit calc(100% - 30px) exit calc(100% + 30px), though not calc(exit 100% + 30px) as this issue suggests

Oh wow! Didn’t know that worked. Works like charm (demo), thanks!

@ydaniv
Copy link
Contributor Author

ydaniv commented Jul 12, 2023

GSAP just added this via new clamp() function: https://twitter.com/greensock/status/1674434131021926400

@flackr
Copy link
Contributor

flackr commented Nov 2, 2023

This use case also requires that we have a way to specify the non-subject range for a view timeline as currently we have defined that a bare value refers to the cover range. e.g. maybe we add it a new scroll range name.

@flackr
Copy link
Contributor

flackr commented Nov 8, 2024

Adding a scroll range name was resolved in #9367.

I propose that we move this to scroll-animations-2, lacking a particular way this could work right now.

@flackr flackr added the Agenda+ label Nov 8, 2024
@astearns astearns moved this to FTF agenda items in CSSWG January 2025 meeting Jan 22, 2025
@astearns astearns moved this from FTF agenda items to Regular agenda items in CSSWG January 2025 meeting Jan 22, 2025
@astearns astearns moved this from Regular agenda items to Friday afternoon in CSSWG January 2025 meeting Jan 28, 2025
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [scroll-animations-1] Allow named ranges to be used with math functions, and agreed to the following:

  • RESOLVED: Add mechanism so that you can use values from animation ranges in math functions, details at editor’s discretion, in L2
The full IRC log of that discussion <emilio> ydaniv: there's a desire to use animation ranges with math functions, but currently not allowed by the syntax
<emilio> ... this requires new syntax
<emilio> ... there are other proposals in other issue
<emilio> ... wrapping the entire range with another function that allows you to resolve to a <length-percentage>
<emilio> ... defer this to L2 is the proposal
<emilio> ... fine for me
<bramus> q+
<astearns> ack bramus
<bramus> https://github.com//issues/8852#issuecomment-1588794640
<emilio> bramus: an example where this is needed is...
<emilio> ... where you have view timelines and you scroll all the way to the bottom of the page
<emilio> ... ?? until it gets to the middle of the scrollport
<emilio> ... but it can never reach that position
<emilio> ... so you scroll down and the image is mid-way the animation
<emilio> ... you can hack around this by adding block padding at the bottom
<emilio> ... allowing the ranges in math functions would solve this
<emilio> ... you'd be able to do something like animation-range: end min(scroll 100%, cover 50%)
<emilio> ... that way you take the min of those
<emilio> ... the animation would be a bit fast because you target smaller scroll distance
<emilio> ... but content will be fully visible
<emilio> ... which is better for users
<bramus> s/animation-range: end min(scroll 100%, cover 50%)/animation-range-end: min(scroll 100%, cover 50%)
<emilio> PROPOSED: Put this in scroll animations L1
<emilio> s/L1/L2
<emilio> emilio: we do something similar for colors already
<emilio> astearns: so proposal is figuring out the syntax
<emilio> bramus: syntax is there right?
<emilio> astearns: so why L2?
<emilio> ydaniv: Maybe flackr remembers issues
<astearns> s/why L2/what goes in L2/
<emilio> bramus: more like making min() take view-timeline-range
<emilio> ydaniv: there was another proposal
<emilio> flackr: not sure if there's a reason not to have the original proposal, not sure if adding the names everywhere they need to will have ambiguity or something
<ydaniv> like `offset(cover 50%)`
<emilio> bramus: we could bring this back if we need to add something else
<emilio> astearns: so we need to add anything to the spec?
<emilio> flackr: this isn't in the spec
<emilio> ... probably affects values-5
<emilio> astearns: perhaps we add an example to the spec
<emilio> ... to point out that we have the intent that they should work?
<emilio> q+
<emilio> astearns: if we come up with issues in the examples we figure out if we need ??
<emilio> astearns: have a hard time figuring out which change is being asked for
<bramus> emilio: change that is being asked for putting this to the spec
<bramus> … proably needs to got into values
<bramus> … this is definitely possible. do the same for anchor()
<bramus> … adding these keywords seems fine
<bramus> … definitely more work than a syntax like the one ydaniv suggested
<bramus> … so depending on the extent of this whole calc stuff
<bramus> q+
<astearns> ack emilio
<bramus> … offset() imple wise is simpler
<flackr> Maybe wrapping it in a function like range(<name>, %) would simplify parsing it?
<bramus> … but that’s not an objection
<bramus> … because all calc() is generally more generic for this stuff
<astearns> ack bramus
<emilio> bramus: was gonna suggest to support `offset()`
<emilio> ... adding a function that returns back the computed pixel value for the range you give it
<emilio> ... and we circumvent the whole complication
<emilio> q+
<astearns> ack emilio
<bramus> emilio: dont think that ??
<bramus> … you dont want this conversion to happen at computed value time
<bramus> … it does not matter if you rpeserve it aas keywords when you resolve them
<bramus> ; the idea is to use this offset fn inside calc and it returns the px value … that is more complicated …
<bramus> … amount of effort you need is similar
<bramus> … dont see a reason to do that, unless the identifiers are unambiguous
<kizu> q+
<bramus> … e.g. all color component stuff
<bramus> … can do something like this much like we do color component stuff
<flackr> q+
<bramus> … just need to … thought the proposal was some standalone fn that would offset the thing when you do offset(50%)
<bramus> … for the case you gave it seems like what you want ti to
<bramus> … supporting identifiers in calc is fine and less complicated
<bramus> … you”re suppporting an identifier that resolves to a ???
<astearns> ack kizu
<emilio> kizu: +1 to emilio
<emilio> ... mostly because if we add it as an offset() it'd work only inside these ranges
<emilio> ... having stuff like this can be confusing or frustrating, you'd want to use it in other places
<emilio> ... I think you want to use it in the ?? function
<emilio> q+
<emilio> qq+ to reply
<emilio> kizu: in anchor-positioning you already need to be careful of where anchor() is allowed
<emilio> ... it'd be nice to avoid that complexity
<emilio> ack emilio
<Zakim> emilio, you wanted to react to kizu to reply
<bramus> emilio: to be clear, i still we think we need to limit where this applies to
<bramus> … cant add it random length-percentages
<bramus> … bc you dont know the scroll ranges when computing the widdth
<bramus> … can prolly add to more things as needed, but would be mostly about the range properties initially
<astearns> ack flackr
<emilio> q'
<emilio> q-
<emilio> flackr: probably range props and keyframe offsets
<emilio> ... a range is 2 values, start and end
<emilio> ... that might complicate it being a single keyword
<emilio> ... but I'm sure we can work that out
<emilio> q+
<astearns> ack emilio
<bramus> emilio: i dont see why that would be an issue
<bramus> … these keywords would only appear inside calc or on their own
<bramus> flackr: yes, we only have a single keyword for contain for example
<bramus> … but contain 0% and contain 100% are both values that authors might need to reference
<bramus> emilio: oh, i see
<bramus> … so you dont want just … i thought the scroll keyword would do the whole range
<bramus> … and then you multiply
<bramus> … it would have a keywrod that resolves the px value of the offset
<bramus> … if you need to ref the keyword %, then you need some syntax … then maybe yeah you need a fn
<bramus> … can figure out the details
<bramus> flackr: or a pair of keywords
<bramus> … no strong feelings
<bramus> emilio: can figure out the details
<bramus> … proposal would be to add something that you can use in match functions for animation ranges that eventually resolves to pixels
<bramus> … details tbd
<bramus> astearns: and this will go into L2
<bramus> PROPOSED: Add mechanism so that you can use values from animation ranges in match functions, details at editor’s discretion, in L2
<bramus> s/match/math
<bramus> RESOLVED: Add mechanism so that you can use values from animation ranges in math functions, details at editor’s discretion, in L2

@ydaniv ydaniv changed the title [scroll-animations-1] Allow named ranges to be used with math functions [scroll-animations-2] Allow named ranges to be used with math functions Feb 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Friday afternoon
Development

No branches or pull requests

6 participants