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
Scoping CSS keyframes in emulated view encapsulation #42608
Conversation
2b1e6fa
to
45cd603
Compare
051d2ec
to
988116d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this idea!
In general I think it would provide a positive benefit to the emulated encapsulation mode.
Because of the change to the keyframes name, I think we would have to land this in a major release, since these names could be referenced in JS code - for example in an animation event handler.
We can wait for this timeframe, IMO, since the workaround is quite straightforward - even if identifying the problem may not be!
For other reviewers, I checked through the Angular animations code, which also makes use of |
988116d
to
8dda4a5
Compare
@petebacondarwin all done as you suggested, thanks a lot 😃 The only remaining thing are the quoted keyframes,I am waiting to hear from you on those 🙂 |
e54c6a4
to
a99a2e0
Compare
Thanks @dylhunn !!! 😍 Please let me know if I can help in any way 😃 |
Hey @dario-piotrowicz. We did find a bug here. In the case where the css is all minified into a single string, the regex does not work properly and results in bugs. Here is a test you can use to see the failure:
|
Hi @jessicajaniuk thanks for the test 🙂 And thank you so very much for looking into this ❤️ but, are you completely sure that this test highlights the issue? I've started looking into it and it seems like the test can be easily fixed by removing an extra space in the checks: - expect(result).toContain('-webkit-animation: host-a_slide-left .3s .05s forwards;');
- expect(result).toContain('animation: host-a_slide-left .3s .05s forwards;');
+ expect(result).toContain('-webkit-animation:host-a_slide-left .3s .05s forwards;');
+ expect(result).toContain('animation:host-a_slide-left .3s .05s forwards;'); (which to me seems correct as you can see that this is the expected behaviour in the Also by running the thing locally the keyframe animation seems to work (and be scoped) as expected: |
@dario-piotrowicz quick question: did you run the test as is or you've formatted the input string? We've noticed that the issue is reproducible with the styles written in 1 line (as we have in a test), but things seem to be working correctly when the input is formatted (which potentially hints at the fact that the RegExp added in this PR might match different things in those 2 cases). |
@AndrewKushnir I literally just copy-pasted the exact text Jessica posted in her comment, the the only difference being the removal of the spaces in the I've also rebased to the latest main to make sure that there can't be anything else different somewhere that could produce a different output 😟 |
I would suggest looking at the actual output rather than the expect line.
We were able to see in the processed css result that not everything was
scoped when the string was formatted as a single line with no spaces. I say
this because that contains line could pass since '-webkit-animation:...'
would also contain 'animation:'. So it's not a safe expect.
…On Sat, Sep 24, 2022, 2:44 PM Dario Piotrowicz ***@***.***> wrote:
@AndrewKushnir <https://github.com/AndrewKushnir> I literally just
copy-pasted the exact text Jessica posted in her comment, the the only
difference being the removal of the spaces in the toContain calls:
[image: Screenshot at 2022-09-24 22-38-27]
<https://user-images.githubusercontent.com/61631103/192119652-6f71631b-4663-450c-bb25-7a98882038c1.png>
I've also rebased to the latest main to make sure that there can't be
anything else different somewhere that could produce a different output
😟
—
Reply to this email directly, view it on GitHub
<#42608 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ARLFZ2DPHCT6TCRSJ22YSEDV75Y3BANCNFSM47AGWO2Q>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
@AndrewKushnir @jessicajaniuk sorry I actually found the issue there 😅 I've compared the result before and after: the second and the tests pass because: sorry for the confusion 🙇 😢 I now know what to look at, thanks a lot! 🙂 |
5423f14
to
f2528d1
Compare
I've just rebased to the latest main and squashed all the fixup commits, I hope you don't mind 🙂 |
@jessicajaniuk @AndrewKushnir it was a very very small issue 😅 , the regex accepted the (as you can see in my latest fixup commit) |
745e92a
to
11dc22a
Compare
Ensure that keyframes rules, defined within components with emulated view encapsulation, are scoped to avoid collisions with keyframes in other components. This is achieved by renaming these keyframes to add a prefix that makes them unique across the application. In order to enable the handling of keyframes names defined as strings the previous strategy of replacing quoted css content with `%QUOTED%` (introduced in commit 7f689a2) has been removed and in its place now only specific characters inside quotes are being replaced with placeholder text (those are `;`, `:` and `,`, more can be added in the future if the need arises). Closes angular#33885 BREAKING CHANGE: Keyframes names are now prefixed with the component's "scope name". For example, the following keyframes rule in a component definition, whose "scope name" is host-my-cmp: @Keyframes foo { ... } will become: @Keyframes host-my-cmp_foo { ... } Any TypeScript/JavaScript code which relied on the names of keyframes rules will no longer match. The recommended solutions in this case are to either: - change the component's view encapsulation to the `None` or `ShadowDom` - define keyframes rules in global stylesheets (e.g styles.css) - define keyframes rules programmatically in code.
11dc22a
to
5a6f6c9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work, as always! 👏
Thanks so much!!! 😊 |
TGP is green |
This PR was merged into the repository by commit 051f756. |
…gular#42608) Ensure that keyframes rules, defined within components with emulated view encapsulation, are scoped to avoid collisions with keyframes in other components. This is achieved by renaming these keyframes to add a prefix that makes them unique across the application. In order to enable the handling of keyframes names defined as strings the previous strategy of replacing quoted css content with `%QUOTED%` (introduced in commit 7f689a2) has been removed and in its place now only specific characters inside quotes are being replaced with placeholder text (those are `;`, `:` and `,`, more can be added in the future if the need arises). Closes angular#33885 BREAKING CHANGE: Keyframes names are now prefixed with the component's "scope name". For example, the following keyframes rule in a component definition, whose "scope name" is host-my-cmp: @Keyframes foo { ... } will become: @Keyframes host-my-cmp_foo { ... } Any TypeScript/JavaScript code which relied on the names of keyframes rules will no longer match. The recommended solutions in this case are to either: - change the component's view encapsulation to the `None` or `ShadowDom` - define keyframes rules in global stylesheets (e.g styles.css) - define keyframes rules programmatically in code. PR Close angular#42608
…gular#42608) Ensure that keyframes rules, defined within components with emulated view encapsulation, are scoped to avoid collisions with keyframes in other components. This is achieved by renaming these keyframes to add a prefix that makes them unique across the application. In order to enable the handling of keyframes names defined as strings the previous strategy of replacing quoted css content with `%QUOTED%` (introduced in commit 7f689a2) has been removed and in its place now only specific characters inside quotes are being replaced with placeholder text (those are `;`, `:` and `,`, more can be added in the future if the need arises). Closes angular#33885 BREAKING CHANGE: Keyframes names are now prefixed with the component's "scope name". For example, the following keyframes rule in a component definition, whose "scope name" is host-my-cmp: @Keyframes foo { ... } will become: @Keyframes host-my-cmp_foo { ... } Any TypeScript/JavaScript code which relied on the names of keyframes rules will no longer match. The recommended solutions in this case are to either: - change the component's view encapsulation to the `None` or `ShadowDom` - define keyframes rules in global stylesheets (e.g styles.css) - define keyframes rules programmatically in code. PR Close angular#42608
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Keyframes are not scoped for
Emulated
view encapsulated component, practically making them global and causing css leakageSince keyframes are not hierarchical I don't believe this issue can be solved without modifying the keyframes names, so the only thing possible I believe is to actually rename the keyframes using the component's scope selector,
The way I did it is by scanning the css twice, in the first scan I modified/scoped the keyframes names in the way mentioned above and in the second I updated animation rules using such keyframes
I understand that this is changing the actual names of the keyframes so it may not be what we actually want here, but I figured that opening a PR and starting a discussion would not hurt
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What is the current behavior?
Issue Number: #33885
Currently keyframes are not scoped so, if I create two different keyframe animations in two different components but with the same name, those will clash and only one of them will be applied to both components
You can see it in this example I created: demo code
What happens is that I have two different components each with a keyframes called
box-animation
which colors the component's background, as you can see the application does not behave as expected:What is the new behavior?
Keyframes are scoped so that they include the component's scope selector like so:
and this allows the keyframes to remain isolated:
Does this PR introduce a breaking change?
(at least I don't think so)
Other information
As I mentioned this will cause all the keyframes names in components with the
Emulated
view encapsulation to be modified, this is definitely not too nice/elegant but I think it's the only way to scope the keyframes and I believe that it is still better to leave them global as they are now (as that produces unwanted css leakage + it is inconsistent with what happens withShadowDom
)