DEV Community

Cover image for Proper cross-fade in CSS
Ayc0
Ayc0

Posted on

Proper cross-fade in CSS

In https://www.youtube.com/watch?v=PYSOnC2CrD8, @surma and @jakearchibald talked about what a proper crossfade is, why it is complicated to do with the current technologies. And at the end of the video, they mentioned that they just proposed this to the CSS working group.

What is a proper cross fade?

If we want to transition from a text A to a text B, the easiest is to vary the opacity from 1 to 0 on A, and from 0 to 1 on B.

The main issue with this method is that, for instance, during the middle of the animation, both will have a 50% opacity. Due to how CSS composes layers, we'll still have a color with 75% opacity. But in cross fade, the opacity should always be 100% as we are animating from the start to the end, without any notion of "this is on top of the other".

Here you can see the difference between improper and proper cross fade:

Incorrect 75% opacity Fixed version
double 0.5 opacity double 0.5 opacity with proper cross fade

How to achieve this

The way to do it is to add mix-blend-mode: plus-lighter on the second text, so that CSS knows how to blend this layer with the other ones.

In addition to setting the mix-blend-mode, we should add isolation: isolate on the container so that CSS knows that the composition operation should only be computed within this element, and that we shouldn't also apply it with the full background.

Here is the MDN article on mix-blend-mode: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode.

Top comments (3)

Collapse
 
david263 profile image
David Spector

I learned something new, thanks. But after looking at your demo several times, in practice I prefer the simple (incorrect) method of cross-fading, for two reasons: first, it makes the fact that a transition is happening clearer by doing at least a 25% overall fadeout of whatever is displayed. Second, the "correct" method fails to make any change at all to that part of the text or images that is identical. This looks very strange, that just part of the overall content seems to cross-fade, but not all of it: it is not good from a psychological point of view because in the middle of the crossfade identical content looks like it isn't changing. You want to see that all of the content is changing, not have your attention abnormally drawn to the part that is not changing.

Collapse
 
ayc0 profile image
Ayc0 • Edited

Second, the "correct" method fails to make any change at all to that part of the text or images that is identical.

That is expected, the goal of this article was mention how to do this operation in CSS now that the feature has been shipped.
The video I linked at the beginning really highlights what this tries to achieve.

When I wrote "proper", I didn't mean to say "this should be how things should be done", but as a "a correct cross-fade, from a mathematical point of view".

I think that the use case of this cross fade may be more visible on content with different colors (I'm gonna use examples from this video):

  • with "regular" cross fades, depending on if you cross fade from blue to red, or red to blue, you don't have the same in between (the order matters), which is correct for layers, but not for a cross-fade
  • with this cross fade on the opposite, the order doesn’t matter and you have the same color when its red on top of blue and vice-versa

Collapse
 
david263 profile image
David Spector

That is a very interesting point, and a subtle one. It is correct as far as it goes. But the truth is that cross-fading polychrome images is going to generate many false colors during the transition. This is similar to the fact that during a cross-fade, text will display incorrectly as strange unreadable glyphs, regardless of method.

So the difference between your method and mine is that you insist that the z-order matters and I insist on the reasons I gave above, and here. And, considering your method, if the transition colors must be "incorrect" anyway, why does it matter which incorrect colors are displayed? It doesn't matter at all.

And one more subtle point: if you consider that the eye actually sees an image in grayscale at very low illumination/brightness levels, my method above (the usual naive cross-fade) works better for humans than your very sophisticated one.

To summarize, both cross-fading methods can produce lots of false colors between the beginning and end keyframes. But only my method succeeds when considering just the equivalent monochromatic brightness levels. The z-order of rendering doesn't matter to human perception, while allowing a brightness increase (a fade) across the entire image during the cross-fade does.