为什么两个堆叠的半透明盒子的最终颜色取决于订单?
我怎么能这样做才能在两种情况下得到相同的颜色?
.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>
仅仅因为在两种情况下,由于顶层的不透明度如何影响底层的颜色,颜色的组合是不同的。
对于第一种情况,您会在顶层看到50%的蓝色和50%的透明。通过透明部分,您可以在底层看到50%的红色(因此我们只看到25%的红色)。第二种情况的逻辑相同(50%的红色和25%的蓝色);因此你会看到不同的颜色,因为在这两种情况下我们没有相同的比例。
为避免这种情况,您需要为两种颜色选择相同的比例。
这是一个更好地说明和展示我们如何获得相同颜色的示例:
在顶层(内跨)我们有不透明度的0.25
(所以我们有25%的第一种颜色和75%的透明)然后对于底层(外跨度)我们有0.333
不透明度(所以我们有1 / 3%的75%= 25%的颜色,其余是透明的)。我们在两个层中具有相同的比例(25%),因此即使我们颠倒了层的顺序,我们也会看到相同的颜色。
.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>
另外,白色背景也会影响颜色的渲染。它的比例为50%,这将产生100%的合理结果(25%+ 25%+ 50%)。
您可能还注意到,如果顶层的不透明度大于0.5
,那么我们的两种颜色都不可能具有相同的比例,因为第一个将具有超过50%的百分比,并且它将保持小于50%第二个:
.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>
常见的琐事是顶层有opacity:1
,其顶部颜色的比例为100%;因此它是一种不透明的颜色。
为了更准确和精确的解释,这里是用于计算我们在两个layersref组合后看到的颜色的公式:
ColorF = (ColorT*opacityT + ColorB*OpacityB*(1 - OpacityT)) / factor
ColorF是我们的最终颜色。 ColorT / ColorB分别是顶部和底部颜色。不透明度/不透明度分别是为每种颜色定义的顶部和底部不透明度:
factor
由此公式OpacityT + OpacityB*(1 - OpacityT)
定义。
很明显,如果我们切换两个层,factor
将不会改变(它将保持不变)但我们可以清楚地看到每种颜色的比例将改变,因为我们没有相同的乘数。
对于我们最初的情况,两个不透明度都是0.5
所以我们将:
ColorF = (ColorT*0.5 + ColorB*0.5*(1 - 0.5)) / factor
如上所述,顶部颜色的比例为50%(0.5
),底部颜色的比例为25%(0.5*(1-0.5)
),因此切换层也会切换这些比例;因此我们看到了不同的最终颜色。
现在,如果我们考虑第二个例子,我们将:
ColorF = (ColorT*0.25 + ColorB*0.333*(1 - 0.25)) / factor
在这种情况下,我们有0.25 = 0.333*(1 - 0.25)
所以切换这两层将没有任何影响;因此颜色将保持不变。
我们还可以清楚地识别琐碎的案例:
opacity:0
时,公式等于ColorF = ColorB
opacity:1
时,公式等于ColorF = ColorT
添加css属性mix-blend-mode : multiply
.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>
您按以下顺序混合三种颜色:
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))
你会得到不同的结果。这是因为使用不是normal blend mode的commutative1将前景色与背景色混合。由于它不是可交换的,因此交换前景色和背景色会产生不同的结果。
1混合模式是一种接受前景色和背景色的功能,应用一些公式并返回结果颜色。
解决方案是使用可交换的混合模式:以任何顺序为同一对颜色返回相同颜色的模式(例如,乘法混合模式,它将两种颜色相乘并返回结果颜色;或者变暗混合模式,返回两种颜色较深的颜色)。
$(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>
为了完整性,这里是计算合成颜色的公式:
αs x (1 - αb) x Cs + αs x αb x B(Cb, Cs) + (1 - αs) x αb x Cb
有:
Cs:前景色的颜色值 αs:前景色的alpha值 Cb:背景颜色的颜色值 αb:背景颜色的α值B:混合函数
有关发生的事情的解释,请参阅Temani Afif的回答。
作为替代解决方案,您可以采用一个跨度,例如a
,如果它位于b
内,则将其定位并给它一个较低的z指数。然后堆叠将始终是相同的:b
在第一行的a
上绘制,而a
在第二行的b
下面绘制。
.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>