-
Notifications
You must be signed in to change notification settings - Fork 51
Fix the backdrop-filter order of operations to get opacity right #361
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
base: main
Are you sure you want to change the base?
Conversation
With the previous description, opacity was implicitly included in the final set of filters applied to all content. But that's incorrect, at least according to expectation and behavior. Opacity is special here - it needs to be separately applied to the filtered backdrop, because if it is applied only at the end, the fully-opaque contents of B will have already painted over the filtered backdrop. There won't be any show-through of the backdrop, even though the expectation is to see it, given that opacity is less than 1. While that change is being made, I've also copied the other effects and clips to the backdrop-filtered image as well. These could possibly be defined to only apply once at the end, but the resulting image will be identical or nearly-so, and in practice, the implementation is typically closer to this new definition.
@cbrewster Thanks for the suggestions here. Let me know what you think of this draft. |
This looks like a good clarification to me; the new steps are much more in line with my work in progress implementation in Firefox. I also agree with the removal of the inverse-transform step which seemed tricky to implement properly in perspective transform cases. It would also be good to clarify in steps 3 and 7 the order in which transforms, effects, clips, etc, should be applied. |
Huh. This change is the opposite of what my expectations are with respect to opacity. I would expect @mfreed7, here's what you wrote in #53 (comment):
I very much agree with that sentence, and I'm curious what caused your change of heart. |
@mstange with this change, the filtered backdrop would still be invisible if opacity is set to 0. The main difference is that opacity is applied to the filtered backdrop and the element separately and then they are composited together. The current steps state that the filtered backdrop and the contents of the element should be composited together first and then have effects like opacity applied afterwards. |
Oh, I see. That's better, but still not what I would expect. I would expect group opacity, where the filtered backdrop and the element's foreground are part of the same group. Here's an example: https://codepen.io/mstange/pen/wVzKEW (Incidentally, the "with-background-color" element in that testcase seems to display an unrelated rendering bug in my Chrome build when I hover it and the animation stops...) |
@mstange I see the point you're making here, that in some cases it's confusing that a partial region of your element that is fully-opaque shows through the backdrop-filtered effect when opacity is applied. However, I would submit that the more common case, which would also cause confusion if this were implemented the other way, is for the entire background to be an opaque color, with opacity<1 applied to "see through" it to the filtered backdrop. In that case, people will not be able to see any of the backdrop-filtered content. Seems like the lesser of two evils. The core issue is that the backdrop-filtered content lives somewhere in between the element and the backdrop. @cbrewster Thanks for the comments. I'll see what I can do about clarifying the order of transform, effect, clip. If you have particular suggestions for that, let me know! |
I see. I don't know if that'll be the more common case, as it's also incompatible with Safari's current implementation. In Safari you can't see the filtered backdrop if you use opacity on opaque foreground. |
@mstange, hmm, you're right about Safari's current behavior. Opaque layers (even with opacity) do not show the backdrop. I don't know why, but this just feels weird to me. Putting opacity on an element should let you see through that element. Putting backdrop-filter on an element should paint a filtered copy of the backdrop behind it. Putting these two together, backdrop-filter with opacity should let you see the filtered backdrop. (Of course, I see how it could be defined that way, I'm just saying I'm not sure which way is more intuitive for developers.) I'm not sticking to this position very strongly, but I would like to get it resolved one way or the other soon. I'm not sure which causes more compat issues at this point - changing Chrome to match Safari here, or leaving it as is and making sure the spec is right. But the sooner this is nailed down, the better. |
I still prefer the approach where the element rendering and the filtered backdrop are part of the same opacity group. My justification at this point is mostly Safari compat. Arguing via intuition / what feels right doesn't seem fruitful because there seem to be at least two different intuitions and we don't know which one is shared by the majority of authors, or if there even is such a thing as a shared intuition among authors about this behavior. Actually, scratch that, I will try to justify my intuition one more time: I expect fractional opacity values to interpolate between the rendering at opacity:0 and the rendering at opacity:1. If the element foreground is opaque, the filtered backdrop isn't visible at either 0 or 1. So as I modulate my opacity value between those two extremes, I don't expect the filtered backdrop to become partially visible for in-between values. |
@mstange, I can see your point about Safari compat. However, there is already a bigger compat issue there, w.r.t. the Backdrop Root concept, so I'm not sure the nuances of opacity are as important here. Though clearly we should try to get all of this right, as much as there is a "right". And I can understand your intuition about expecting fractional opacity to interpolate. But I would disagree about which parts of the behavior matter more for intuition. Your point is that while animating between two opacity values, there could be a tinge of partially filtered content visible. Perhaps I'm wrong, but that seems like a very subtle difference. My concern is that there will be confusion about why the effect isn't working at all, when opacity is used. Or there will be confusion about why a background with animated alpha behaves differently from animated opacity on the element. See, e.g., the description given on the MDN page for backdrop-filter, or our recent blog post on the feature. Both refer to either making the background transparent, or making the element transparent (with opacity) to "see through" it to the backdrop-filtered content. This seems to indicate that the "default" intuition is that backdrop-filter modifies/filters the "backdrop" of the element, not the element itself. I.e. you're looking through the element to see the backdrop-filtered content behind it. So you just need to make the element transparent somehow, to see through it. Breaking this symmetry between background alpha and element opacity seems not great. I will definitely concede that the metaphor is imperfect already, as filters and opacity applied to the element also affect the backdrop-filtered content. But I think the points above about the transparency intuition still hold. As for effect nodes, I think that is implementation dependent. The Chromium implementation still has a single effect node for opacity in this case. In the case of an element with both opacity and backdrop-filter, there will still be only a single effect node, containing both the backdrop-filter list and the opacity value. The filtered backdrop content is drawn as a separate intermediate step after rendering the element's content, and before compositing it into the backdrop surface. |
With the previous description, opacity was implicitly included in the final set of filters applied to all content. But that's incorrect, at least according to expectation and behavior. Opacity is special here - it needs to be separately applied to the filtered backdrop, because if it is applied only at the end, the fully-opaque contents of B will have already painted over the filtered backdrop. There won't be any show-through of the backdrop, even though the expectation is to see it, given that opacity is less than 1.
While that change is being made, I've also copied the other effects and clips to the backdrop-filtered image as well. These could possibly be defined to only apply once at the end, but the resulting image will be identical or nearly-so, and in practice, the implementation is typically closer to this new definition.