¿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>
Respuestas:
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.25
opacidad (por lo que tenemos el 25% del primer color y el 75% de transparente) luego para la capa inferior (el tramo exterior) tenemos0.333
opacidad (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.5
porque la primera tendrá más del 50% y permanecerá menos del 50% para la segunda. uno:Mostrar fragmento de código
.a { background-color: rgba(255, 0, 0, 1) /*taking 40% even with opacity:1*/ } .b { background-color: rgba(0, 0, 255, 1) /*taking 40% even with opacity:1*/ } .a > .b { background-color: rgba(0, 0, 255, 0.6) /* taking 60%*/ } .b > .a { background-color: rgba(255, 0, 0, 0.6) /* taking 60%*/ }
<span class="a"><span class="b"> Color 1</span></span> <span class="b"><span class="a">Different Color 2</span></span>
El caso trivial común es cuando la capa superior tiene
opacity:1
el 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
factor
está definido por esta fórmulaOpacityT + OpacityB*(1 - OpacityT)
.Está claro que si cambiamos las dos capas
factor
no 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.5
por 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:
opacity:0
la fórmula es igual aColorF = ColorB
opacity:1
la fórmula es igual aColorF = ColorT
fuente
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>
fuente
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).
Mostrar fragmento de código
$(function() { $("#mode").on("change", function() { var mode = $(this).val(); $("#demo").find(".a, .b").css({ "mix-blend-mode": mode }); }); });
#demo > div { width: 12em; height: 5em; margin: 1em 0; } #demo > div > div { width: 12em; height: 4em; position: relative; top: .5em; left: 4em; } .a { background-color: rgba(255, 0, 0, 0.5); } .b { background-color: rgba(0, 0, 255, 0.5); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <select id="mode"> <optgroup label="commutative"> <option>multiply</option> <option>screen</option> <option>darken</option> <option>lighten</option> <option>difference</option> <option>exclusion</option> </optgroup> <optgroup label="non-commutative"> <option selected>normal</option> <option>overlay</option> <option>color-dodge</option> <option>color-burn</option> <option>hard-light</option> <option>soft-light</option> <option>hue</option> <option>saturation</option> <option>color</option> <option>luminosity</option> </optgroup> </select> <div id="demo"> <div class="a"> <div class="b"></div> </div> <div class="b"> <div class="a"></div> </div> </div>
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
fuente
Para obtener una explicación de lo que sucede, consulte la respuesta de Temani Afif.
Como solución alternativa, puede tomar un tramo,
a
por ejemplo, colocarlo y darle un índice z más bajo si está dentrob
. Entonces, el apilamiento será siempre el mismo:b
se dibuja encima dea
en la primera línea ya
se dibuja debajob
en 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>
fuente