CSS double transition in-out renders strangely

48 views Asked by At

I am trying to render beautiful pages transitions in my react application. I chose simple fade-in/fade-out transitions, and they work perfectly for random pages. But it happens that some pages are quite identical (just a text change), and in that case the transition is not so good (see code-pen bellow for a concrete example).

The way I understand mathematics, if I have two layers, let's say A and B, a linear fade-out of A starting above a similar linear fade-in of B should give constant pixels colors for pixels of the exact same color in both layers, isn't it? But as you can see in that codepen, it's not the case (i was hoping to have no visual effect as the two layers have the exact same color), and I don't understand why. Is there a way to obtain the desired result (for a given pixel, color B replace color A if they are different, but stay still if they are the same)?

https://codepen.io/st-phane-smirnow/pen/dyJaBPG

And here is the corresponding code - HTML:

<div class="a1">a1 div</div>
<div class="a2 hidden">a2 div</div>
<button>Switch divs<button>

CSS:

.a1, .a2 {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: red;
  transition: all .5s linear;
}
.hidden { opacity: 0; }
button {
  position: absolute;
  top: 10px;
  left: 10px;
}

JS:

window.addEventListener("load", () => {
 document.querySelector("button").addEventListener("click", () => {
   document
     .querySelectorAll("div")
     .forEach(d => d.classList.toggle("hidden"));
  });
});

EDIT: I partially solved my problem by disabling the transparency of the underlying layer. That way, the application background, whatever it is, is hidden by the second layer (opacity always to 1), and the foremost layer just fade-in the underlaying layer. I don't know if, in a perfect world, that result is really different of what I would have got of a truly functional cross-fade, but at least it give a good result at screen.

1

There are 1 answers

3
Nicolas Goosen On

It's because during the transition, they are both transparent so you're seeing the white background through them.

Here's an interesting post that shows some formulas that might help to why the resulting color isn't rgb(255,0,0) all the way through. Basically, some of the green and blue channel are being introduced.

It's reasonable to think that a 90% red + a 10% red would be a 100% red, but actually each layer is letting a little bit of 'white light' through. Here's how:

According to the post, the general formula for a 2 layer image is:

Y = p*T+(1-p)*B where...
p is the opacity 0...1 of the top layer,
T = rgb number of top layer color,
B is the rgb number of fully opaque bottom layer.
Y is the rgb number of the equivalent fully opaque color. 

So, say you have rgba(255, 0, 0, 0.9) on a white background. The resulting color is:

r = 0.9 * 255 + 0.1 * 255 = 255
g = 0.9 * 0   + 0.1 * 255 = 25.5
b = 0.9 * 0   + 0.1 * 255 = 25.5

Now let's add a rgba(255, 0, 0, 0.1) on top of that result:

r = 0.1 * 255 + 0.9 * 255 = 255
g = 0.1 * 0   + 0.9 * 25.5 = 22.9
b = 0.1 * 0   + 0.9 * 25.5 = 22.9

The extra green and blue channels are moving the color towards white.