csswg-drafts icon indicating copy to clipboard operation
csswg-drafts copied to clipboard

[css-animations-2] Scoping keyframe names between UA and developer styles.

Open khushalsagar opened this issue 2 years ago • 2 comments

Currently there is no way to scope keyframe names declared in styles in user-agent origin vs author rules. For example, consider the following declaration in a user agent stylesheet, used here

@keyframes page-transition-fade-in {
  from { opacity: 0; }
}

::page-transition-incoming-image {
    animation: page-transition-fade-in 0.25s both;
  }
}

This has 2 problems:

  • If the author declares a keyframe with the same name for a different animation, it will incorrectly override the keyframe selected for the rule in the user-agent stylesheet.
  • If the keyframe with the same supplied by the author is missing, the declaration in the user-agent stylesheet will be used incorrectly.

We need a way to scope keyframe names between styles in the user-agent origin vs author styles. A couple of options are:

  • Come up with a prefix which is reserved for UA rules. It will be an error for author keyframes to use this prefix. This will have compat issues to figure out the right prefix.

  • Keep a separate list of keyframes declared in user-agent stylesheets vs author stylesheets. The list chosen when selecting the animation-name depends on where the resolved animation-name came from. This means if the animation-name was specified in a UA stylesheet but overridden by an author style (possibly with the same name), the look up is in author keyframe names.

    One of the caveats with this is script APIs like AnimationEvent include animation-name and which keyframe it corresponds to would be ambiguous. We could add another field to such APIs (bool isUASource) specifying the namespace for the rule.

@flackr @vmpstr @jakearchibald

khushalsagar avatar Aug 02 '22 21:08 khushalsagar

Yeah, this seems like a reasonable thing to do. I'd be fine with reserving the single-dash set of names (already used for vendor prefixes), or we could add a function that namespaces an ident, like ua(page-transition-fade-in)

tabatkins avatar Aug 17 '22 17:08 tabatkins

I'm happy with either of those

jakearchibald avatar Aug 18 '22 13:08 jakearchibald

@tabatkins do you have a preference for a function/prefix vs implicit scoping based on which stylesheet the declaration is in? With the prefix/function every keyframe declaration in a UA stylesheet should have ua(foo) and no keyframe in author stylesheets should have that. So the implicit approach seems more straightforward.

The only downside of implicit is that author stylesheets can not use a keyframe declaration in UA stylesheets but we don't have a use-case for that anyway.

khushalsagar avatar Aug 25 '22 17:08 khushalsagar

Carrying around implicit source information that isn't textually reflected in any way isn't great. We ended up doing it for shadow-scoped names, for example, and while I think we ended up on the best overall solution, it's still not great that a no-op that set the current style to itself can actually change the meaning of the style (by changing the tree that you're looking up the reference in).

I'd personally strongly prefer a textual mechanism to differentiate the two. That also avoids problems with scripting APIs, as you listed in the OP, which would need to carry the source data out-of-band.

tabatkins avatar Aug 25 '22 21:08 tabatkins

Let me try to clarify the details for the explicit proposal:

  • Each keyframe declaration in the UA stylesheet will have a CSS function to scope it:

      @keyframes ua(fade-in) {
        from { opacity: 0; }
      }
    
      div {
        animation: ua(fade-in);
      }
    

    I'd be fine with reserving the single-dash set of names (already used for vendor prefixes)

    I think you meant -fade-in instead of ua(fade-in) but turns out that a single dash is valid syntax for custom idents today. I thought we could do --fade-in but double dash is for custom properties. Open to other suggestions though.

  • If the same keyframe declaration is used in any stylesheet other than user-agent origin it will rejected at parsing time. This includes both @keyframe and when applying the keyframe to the animation-name property. I'm flexible on the last one though. The limitation avoids the keyframes being used for cases other than what the UA generated them for.

I'm ok with this option too.

khushalsagar avatar Aug 30 '22 21:08 khushalsagar

Each keyframe declaration in the UA stylesheet will have a CSS function to scope it:

We don't necessarily need to tag the @keyframes name specially. I was envisioning ua(foo) just referring to a @keyframes foo in a UA-origin style sheet. But either way works.

I think you meant -fade-in

Yes, in that part I was referring to just using a custom-ident with a single-dash prefix, rather than a function.

but turns out that a single dash is valid syntax for custom idents today

It is, yeah, tho I'm not sure what existing usage is. We could potentially ban this naming pattern from the production, or perhaps just a -ua- prefix for use here.

If the same keyframe declaration is used in any stylesheet other than user-agent origin it will rejected at parsing time.

If we went with a special naming convention in the @keyframes rule, then yes, it would be invalid to write @keyframes ua(foo) {...} anywhere but a UA style sheet.

This includes both @Keyframe and when applying the keyframe to the animation-name property.

Sure. As you say, it's not strictly necessary to ban it from being used in animation-name outside a UA style sheet, but doing so makes it less likely that pages can depend on precise details of the animation, thus allowing us some freedom to tweak it in the future.

tabatkins avatar Aug 30 '22 23:08 tabatkins

The CSS Working Group just discussed Scoping keyframe names in UA stylesheet, and agreed to the following:

  • RESOLVED: Name UA-defined @keyframes rules with a -ua- prefix (and presumably use this pattern elsewhere as needed)
  • RESOLVED: The -ua- names *are* usable in author/user stylesheets.
The full IRC log of that discussion <TabAtkins> Topic: Scoping keyframe names in UA stylesheet
<TabAtkins> github: https://github.com/w3c/csswg-drafts/issues/7560
<TabAtkins> khush: Came up in impl for Shared Element Transitions, where the browser is making keyframes and using in the UA stylesheet
<TabAtkins> khush: Per spec right now, those @keyframes names can collide with author keyframes
<TabAtkins> khush: Issue has two proposals
<TabAtkins> khush: First is implicitly carrying source information around, so a UA 'animation-name' rule will look in the UA sheet first for keyframes
<TabAtkins> khush: Main issue with this is there's a bunch of script APIs which provide the keyframe name, and it becomes difficult for authors to tell which @keyframes is being referred to
<TabAtkins> khush: Alternate is making a syntax for keyframes names that can only be used in the UA stylesheet
<TabAtkins> khush: Tab's suggestion was `@keyframes ua(foo) {...}`
<flackr> q+
<TabAtkins> khush: Could be implicit or explicit, but would be `animation-name: ua(foo)`
<emilio> q+
<TabAtkins> khush: Also an issue if author stylesheets are allowed to explicitly use the value. Prefer not, it gives us more flexibility to change.
<TabAtkins> khush: I suggest we take TAb's suggestion of a ua() function
<Rossen_> q?
<Rossen_> ack fantasai
<fantasai> ua(name-of-animation)
<fantasai> -name-of-animation
<fantasai> -ua-name-of-animation
<TabAtkins> fantasai: Tab has several proposals. One is a function, another is a single-dash prefix, which isn't generally used, or specifically a `-ua-` prefix.
<TabAtkins> fantasai: Just wanted to point out several options.
<fantasai> s/options/options in the issue/
<TabAtkins> khush: I think single-dash can be used in an author stylesheet, so there's some compat risk.
<TabAtkins> flackr: The author stylesheets might refer to these for SET, right?
<fantasai> SET=Shared Element Transitions
<TabAtkins> flackr: My issue with scoping to the stylesheet (not allowing usage in author stylesheets) is authors might want to specify overrides for the proeprties that still use SET animation names
<Rossen_> ack flackr
<TabAtkins> khush: This can be done without overriding animation-name, by setting the longhang properties specifically.
<TabAtkins> khush: Just not a fan of allowing using it in a different context from where it's intended
<TabAtkins> flackr: That does prevent author from using the shorthand, tho
<TabAtkins> khush: yeah
<TabAtkins> flackr: So I have a slight preference for just using a naming convention, not putting a usage restriction
<Rossen_> ack emilio
<TabAtkins> emilio: I don't know if SET - it seems we want to expose the animatino to authors in some way
<TabAtkins> emilio: We have other at-rules in the UA sheet that we don't expose tho, like a @font-face
<TabAtkins> emilio: We just don't expose that in scripting APIs
<TabAtkins> emilio: Is that an option?
<TabAtkins> emilio: Otherwise I tend to lean to just using a naming convention.
<Rossen_> q?
<TabAtkins> emilio: There are use-cases for overriding animation names in user stylesheets, for example
<fantasai> TabAtkins: When you don't expose the name in scripting APIs, the name is still exposed in properties?
<fantasai> TabAtkins: If the author defines something of the same name, it would take precedence, right?
<fantasai> emilio: We chose -moz- prefixed things, since supposed to be internal implementation detail
<fantasai> emilio: naming convention, especially if we use -ua-, would allow user to override internal if they wanted
<fantasai> emilio: so that's what I meant, there may be a use case for users to adjust animations
<TabAtkins> fantasai: I think a naming convention is nice. Can decide if we want it to expose to the author or not for tweaking, but it allows that possibility. Seems usable/used in other places where we've run into similar problems.
<TabAtkins> khush: So is there a preference for one of the naming conventions?
<TabAtkins> fantasai: If it's author-exposed, I think -ua-foo is clear and fits into the syntaxes we might use it pretty easily.
<fantasai> s/easily/easily anywhere we need such a thing/
<TabAtkins> emilio: Agreed. No new syntax and it's reusable for other features.
<bradk> +1 for -ua- for reasons already mentioned
<TabAtkins> Rossen_: So sounds like a -ua- prefix is getting the most likes
<TabAtkins> Rossen_: Can we resolve?
<TabAtkins> khush: So consensus on -ua- prefix for UA-defined keyframes rules.
<TabAtkins> khush: And a second question about whether this can be used in author stylesheets or not, I'm not clear if there's objections on that yet.
<TabAtkins> Rossen_: So let's take those separately.
<TabAtkins> Rossen_: First, the prefix naming. Any objections to -ua- prefix?
<TabAtkins> RESOLVED: Name UA-defined @keyframes rules with a -ua- prefix (and presumably use this pattern elsewhere as needed)
<TabAtkins> Rossen_: Second, expose them to be usable in author stylesheets?
<TabAtkins> No opinion here
<TabAtkins> RESOLVED: The -ua- names *are* usable in author/user stylesheets.
<bradk> Hopefully auto prefixers will not start adding-ua- to everything.

css-meeting-bot avatar Aug 31 '22 16:08 css-meeting-bot