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

Parse full animation-range syntax #251

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

johannesodland
Copy link
Contributor

@johannesodland johannesodland commented Feb 18, 2024

Implements parsing the full animation-range syntax to fix #236

Changes:

  • Implement parsing of animation-range in parseAnimationRange()
    • Extract common parsing functionality into consumeRange()
  • Additional typed-css-om functionality and fixes to be able to validate length-percentage:
    • Implement add two types from css-typed-om (needed for validating length-percentage)
    • Make create a type case insensitive
  • Change how <length-percentage> in rangeStart/End is stored and returned:
    • from CSS.percent(0)
    • to { rangeName: 'none', offset: CSS.percent(0)}
  • Add vitest for unit-tests
  • Write unit tests for
    • CSSNumericType.type()
    • Parsing animation-range

The tests for animation-range are not strictly unit tests and tests the implementation through the internal parseAnimationRange() function. The functionality is currently only exposed through css parsing which makes it difficult to test. We could expose the parsing partly through CSSStyleValue.parse('animation-range', value) but then we would have to proxy that method in all browsers.

@johannesodland johannesodland force-pushed the parse-full-animation-range-syntax branch 9 times, most recently from f4fd31f to 81c36cb Compare February 25, 2024 09:30
@johannesodland johannesodland force-pushed the parse-full-animation-range-syntax branch from 81c36cb to 7afa913 Compare February 25, 2024 09:47
@johannesodland johannesodland marked this pull request as ready for review February 25, 2024 10:06
Copy link
Collaborator

@bramus bramus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a (very) quick pass, left some remarks.

@@ -40,11 +40,11 @@ const unitGroups = {
},
// https://www.w3.org/TR/css-values-4/#absolute-lengths
absoluteLengths: {
units: new Set(["cm", "mm", "Q", "in", "pt", "pc", "px"]),
units: new Set(["cm", "mm", "q", "in", "pt", "pc", "px"]),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you lowercased this here, yet in test/unit/cssom/css-numeric-value-type.test.js the unit is uppercase

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I lower-cased the units here, as the units should be case insensitive. (Both new CSSUnitValue(5, 'Q').type() and new CSSUnitValue(5, 'q').type() should return {length: 1}.)

Q was the odd unit out, and I think its better to keep the representation of the units in lower case, in stead of changing the case om the fly when checking units.

The upper-case Q in the test is copy paste from before the unit was lower cased.
Come to think of it, the unit tests should probably test the units with both upper and lower case 🤔.

Talking about units, we have some case sensitivity issues in the cssom polyfill if you create a CSSUnitValue() or run CSSNumericValue.parse() with upper-case units. Units are then stored and serialized in uppercase, while Safari and Chrome will return them in lowercase. It should be simple to fix, but I'll save it for another PR :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added tests for both upper and lower case units when creating a CSSUnitValue and checking its type in 326fc3b.

The spec (and webkit) seems to require lower case 'number' and 'percent' unit, while blink supports both casings. Aligned with webkit and the spec.

@@ -1126,7 +1134,7 @@ export class ProxyAnimation {
effect: null,
// The animation attachment range, restricting the animation’s
// active interval to that range of a timeline
animationRange: isScrollAnimation ? parseAnimationRange(timeline, animOptions['animation-range']) : null,
animationRange: isScrollAnimation ? parseAnimationRange(animOptions['animation-range']) : null,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the things that was present in the previous implementation is that it checked whether the passed in range made sense for the type of timeline or not. E.g. passing incover 20% does not make sense for a regular ScrollTimeline.

With this functionality removed here now, do we check it elsewhere before it’s actually used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it, the syntax allows for both <length-percentage> and <timeline-range-name> <length-percentage>? which makes sense since animation-range is a property of the animation and not the timeline.

The values are checked when used.

When <length-percentage> is defined on a view-timeline, the offset corresponds to a specified point on the view-timeline. animation-range: 0% 100% is then treated similarly to cover 0% cover 100% and normal.

<length-percentage>
The animation attachment range starts at the specified point on the timeline measuring from the start of the timeline.

When <timeline-range-name> <length-percentage>? is used on a scroll-timeline, only the offsets are used. entry 0% entry 100% is treated similarly to 0% 100% and normal.

This seem to correspond well with Chrome, as far as I have tested. Specify animation-range: cover 20% on an animation with a scroll-timeline, and rangeStart will return {rangeName: 'cover', offset: CSS.px(20)}.

I don't see how we can validate a specified cover 20% for a ScrollTimeline, as the timeline might be changed to a ViewTimeline afterwards.

@@ -940,7 +940,7 @@ function getNormalStartRange(timeline) {
}

if (timeline instanceof ScrollTimeline) {
return CSS.percent(0);
return { rangeName: 'none', offset: CSS.percent(0) };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that none is not mentioned in the spec and that it is something that Chrome uses to indicate if the range only has an offset.

There is some discussion to introduce scroll as a range name in w3c/csswg-drafts#9367, which would allow renaming none to scroll as I mentioned in w3c/csswg-drafts#9367 (comment).

Would leave it at how it is right now, but might need a comment linking to the WG Issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'll leave a comment linking to the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documented the use of 'none' as range name in stead of null in 96c567c.

@calinoracation
Copy link
Contributor

calinoracation commented Apr 17, 2024

Edit: Nevermind, our atomic css parser split the rules out so it couldn't parse it correctly.

@bramus @johannesodland Any chance of landing this? We're trying to use some code like this and it's not parsing at the moment. In Chromium it works great.

    animation-duration: 1ms;
    animation-fill-mode: forwards;
    animation-name: overflow-visible;
    animation-range-start: entry 70%;
    animation-range-end: entry 100%;
    animation-timeline: --carousel-scroller;
    view-timeline-name: --carousel-scroller;

    @keyframes overflow-visible {
      from {
        opacity: 1;
      }
      to {
        opacity: 0;
      }
    }

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

Successfully merging this pull request may close these issues.

Parse more animation-range values
3 participants