¿El color de las cajas semitransparentes apiladas depende del pedido?

84

¿Por qué el color final de dos cajas semitranslúcidas apiladas depende del pedido?

¿Cómo puedo lograr que obtenga el mismo color en ambos casos?

.a {
  background-color: rgba(255, 0, 0, 0.5)
}

.b {
  background-color: rgba(0, 0, 255, 0.5)
}
<span class="a"><span class="b">          Color 1</span></span>
<span class="b"><span class="a">Different Color 2</span></span>

rmv
fuente
7
No sé la respuesta a la pregunta, pero sucede lo mismo en Photoshop y es algo que he aceptado durante años como parte de la teoría del color por computadora. Miraré a mi alrededor para ver si puedo encontrar más información.
YAHsaves
11
Por lo que vale, lo mismo sucede en la vida real para cualquier cosa que no sea 100% transparente y esté iluminada de frente. Más luz del objeto frontal llega a su ojo, por lo que su color tiene un mayor efecto sobre el color final, incluso si ambos tienen un 50% de transparencia.
jpa
4
@YAHsaves: El promedio de 0 y 100 es 50 (paso 1). El promedio de 50 y 150 es 100 (paso 2). Compare esto con: el promedio de 150 y 0 es 75 (paso 1). El promedio de 75 y 100 es 87,5 (paso 2). El problema es que los tres números no se ponderan correctamente. Es necesario calcular un promedio basado en todos los números al mismo tiempo; no se puede simplemente calcular de forma recursiva el promedio paso a paso. (Tenga en cuenta que el cálculo promedio es esencialmente un cálculo de transparencia del 50%. El cálculo cambia para diferentes niveles de transparencia, pero el principio sigue siendo el mismo)
Flater
2
Lecciones aprendidas: con 'mix-blend-mode: multiply' obtendré un color independiente del orden de apilamiento, ¡eso es lo que estaba buscando inicialmente! Creo que la respuesta de @Moffens es más útil para cualquier otro usuario que se enfrente al mismo problema. Pero las explicaciones de Temani Afif realmente se aplican a mi pregunta y describen por qué HTML se comporta de otra manera (imita la propagación de la luz física a través de láminas semitransparentes), por lo que la marca verde se dirige a él.
rmv

Respuestas:

101

Simplemente porque en ambos casos la combinación de colores no es la misma debido a cómo la opacidad de la capa superior afecta el color de la capa inferior .

En el primer caso, verá un 50% de azul y un 50% de transparente en la capa superior. A través de la parte transparente, ves un 50% de color rojo en la capa inferior (por lo que solo vemos un 25% de rojo en total). Misma lógica para el segundo caso ( 50% de rojo y 25% de azul ); así verás colores diferentes porque para ambos casos no tenemos la misma proporción.

Para evitar esto, debe tener la misma proporción para ambos colores.

Aquí hay un ejemplo para ilustrar mejor y mostrar cómo podemos obtener el mismo color:

En la capa superior (el tramo interior) tenemos 0.25opacidad (por lo que tenemos el 25% del primer color y el 75% de transparente) luego para la capa inferior (el tramo exterior) tenemos 0.333opacidad (por lo que tenemos 1/3 de 75% = 25% del color y el resto es transparente). Tenemos la misma proporción en ambas capas (25%) por lo que vemos el mismo color incluso si invertimos el orden de las capas.

.a {
  background-color: rgba(255, 0, 0, 0.333)
}

.b {
  background-color: rgba(0, 0, 255, 0.333)
}

.a > .b {
  background-color: rgba(0, 0, 255, 0.25)
}
.b > .a {
  background-color: rgba(255, 0, 0, 0.25)
}
<span class="a"><span class="b">          Color 1</span></span>
<span class="b"><span class="a">Different Color 2</span></span>

Como nota al margen, el fondo blanco también está afectando la representación de los colores. Su proporción es del 50%, lo que hará el resultado lógico del 100% (25% + 25% + 50%).

También puede notar que no será posible tener la misma proporción para nuestros dos colores si la capa superior tiene una opacidad mayor que 0.5porque la primera tendrá más del 50% y permanecerá menos del 50% para la segunda. uno:

El caso trivial común es cuando la capa superior tiene opacity:1el color superior con una proporción del 100%; por eso es un color opaco .


Para una explicación más precisa y precisa aquí está la fórmula utilizada para calcular el color que vemos después de la combinación de ambas capas ref :

ColorF = (ColorT*opacityT + ColorB*OpacityB*(1 - OpacityT)) / factor

ColorF es nuestro color final. ColorT / ColorB son respectivamente los colores superior e inferior. opacityT / opacityB son respectivamente las opacidades superior e inferior definidas para cada color:

El factorestá definido por esta fórmula OpacityT + OpacityB*(1 - OpacityT).

Está claro que si cambiamos las dos capas factorno cambiará (permanecerá constante) pero podemos ver claramente que la proporción de cada color cambiará ya que no tenemos el mismo multiplicador.

Para nuestro caso inicial, ambas opacidades son 0.5por lo que tendremos:

ColorF = (ColorT*0.5 + ColorB*0.5*(1 - 0.5)) / factor

Como se explicó anteriormente, el color superior tiene una proporción del 50% ( 0.5) y el inferior tiene una proporción del 25% ( 0.5*(1-0.5)) por lo que cambiar las capas también cambiará estas proporciones; así vemos un color final diferente .

Ahora bien, si consideramos el segundo ejemplo tendremos:

ColorF = (ColorT*0.25 + ColorB*0.333*(1 - 0.25)) / factor

En este caso, 0.25 = 0.333*(1 - 0.25)cambiar las dos capas no tendrá ningún efecto; por tanto, el color seguirá siendo el mismo.

También podemos identificar claramente los casos triviales:

  • Cuando la capa superior tiene opacity:0la fórmula es igual aColorF = ColorB
  • Cuando la capa superior tiene opacity:1la fórmula es igual aColorF = ColorT
Temani Afif
fuente
23
@ChrisHappy no estoy resolviendo el problema;) estoy explicando ... la explicación a veces es mejor que la solución
Temani Afif
El problema aún ocurre incluso si quita los div entre sí y coloca: absolutos para apilarlos.
YAHsaves
1
@YAHsaves el problema va a producirse incluso si utilizamos fondo múltiple o cualquier cosa que hacen los dos colores uno encima del otro (utilizando la posición absoluta o no);)
Temani Afif
5
Si desea agregar un TLDR, sería que sean multiplicativos en lugar de aditivos.
Caramiriel
2
@Caramiriel: "multiplicativo" todavía no explica por qué la operación no es conmutativa.
Eric Duminil
41

Puede utilizar la propiedad css mix-blend-mode : multiply ( compatibilidad limitada con el navegador )

.a {
  background-color: rgba(255, 0, 0, 0.5);
  mix-blend-mode: multiply;
}

.b {
  background-color: rgba(0, 0, 255, 0.5);
  mix-blend-mode: multiply;
}

.c {
  position: relative;
  left: 0px;
  width: 50px;
  height: 50px;
}

.d {
  position: relative;
  left: 25px;
  top: -50px;
  width: 50px;
  height: 50px;
}
<span class="a"><span class="b">          Color 1</span></span>
<span class="b"><span class="a">Different Color 2</span></span>

<div class="c a"></div>
<div class="d b"></div>

<div class="c b"></div>
<div class="d a"></div>

Moffen
fuente
6
Casi cualquier modo de fusión de colores de esta lista que sea "conmutativo" funcionará.
Salman A
Interesante, esto funciona con Chrome pero no con Edge (a partir de la última actualización de Windows 10).
Hong Ooi
3
@rmv ¿por qué esperaría algo más que superposición / normal? ¿Cuál es el color esperado si coloca un cuadro azul opaco frente a un cuadro rojo? Será azul en lugar de rojo o una función de azul y rojo.
Salman A
1
@Moffen Respuesta perfecta, pero ¿podría agregar una explicación de por qué esto funciona y por qué el código original no?
Bergi
1
@rmv: Lo que el modo de mezcla "normal" imita más de cerca es la mezcla de pintura. Por ejemplo, si toma un poco de pintura blanca, reemplaza la mitad con pintura roja y luego reemplaza la mitad de la pintura rosa resultante con pintura azul, terminará con un púrpura azulado (25% blanco, 25% rojo, 50% azul). Si comienza con la misma pintura blanca pero primero reemplaza la mitad con azul y luego la mitad del resultado con rojo, terminará con un púrpura rojizo (25% blanco, 25% azul, 50% rojo) en su lugar.
Ilmari Karonen
22

Está mezclando tres colores en el siguiente orden:

  • rgba(0, 0, 255, 0.5) over (rgba(255, 0, 0, 0.5) over rgba(255, 255, 255, 1))
  • rgba(255, 0, 0, 0.5) over (rgba(0, 0, 255, 0.5) over rgba(255, 255, 255, 1))

Y obtienes resultados diferentes. Esto se debe a que el color de primer plano se mezcla con el color de fondo utilizando el modo de mezcla normal 1,2 que no es conmutativo 3 . Y como no es conmutativo, el intercambio de colores de primer plano y de fondo producirá un resultado diferente.

1 El modo de fusión es una función que acepta un color de primer plano y de fondo, aplica alguna fórmula y devuelve el color resultante.

2 Dados dos colores, fondo y primer plano, el modo de fusión normal simplemente devuelve el color de primer plano.

3 Una operación es conmutativa si cambiar el orden de los operandos no cambia el resultado, por ejemplo, la suma es conmutativa (1 + 2 = 2 + 1) y la resta no (1 - 2 ≠ 2 - 1).

La solución es usar un modo de fusión que sea conmutativo: uno que devuelva el mismo color para el mismo par de colores en cualquier orden (por ejemplo, el modo de fusión de multiplicación, que multiplica ambos colores y devuelve el color resultante; o el modo de fusión de oscurecimiento, que devuelve el color más oscuro de los dos).


Para completar, aquí está la fórmula para calcular el color compuesto:

αs x (1 - αb) x Cs + αs x αb x B(Cb, Cs) + (1 - αs) x αb x Cb

con:

Cs: el valor de color del color de primer plano
αs: el valor alfa del color de primer plano
Cb: el valor de color del color de fondo
αb: el valor alfa del color de fondo
B: la función de fusión

Salman A
fuente
8

Para obtener una explicación de lo que sucede, consulte la respuesta de Temani Afif.
Como solución alternativa, puede tomar un tramo, apor ejemplo, colocarlo y darle un índice z más bajo si está dentro b. Entonces, el apilamiento será siempre el mismo: bse dibuja encima de aen la primera línea y ase dibuja debajo ben la segunda.

.a {
  background-color: rgba(255, 0, 0, 0.5);
}

.b {
  background-color: rgba(0, 0, 255, 0.5);
}

.b .a {position:relative; z-index:-1;}
<span class="a"><span class="b">     Color 1</span></span>
<span class="b"><span class="a">Same Color 2</span></span>

Señor lister
fuente