堆叠的半透明盒子的颜色取决于订单?

时间:2018-05-28 23:34:41

标签: html css background background-color overlapping

为什么两个堆叠的半透明盒子的最终颜色取决于顺序?

我怎么能这样做才能在两种情况下得到相同的颜色?



.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>
&#13;
&#13;
&#13;

4 个答案:

答案 0 :(得分:82)

仅仅因为在两种情况下,由于顶部图层的不透明度会影响底部图层的颜色,颜色组合不一样。

对于第一种情况,您会在顶层看到 50%的蓝色和50%的透明度。通过透明部分,您可以在底层看到50%的红色(因此我们只看到 25%的红色)。第二种情况的逻辑相同( 50%的红色 25%的蓝色);因此你会看到不同的颜色,因为在这两种情况下我们都没有相同的比例。

为避免这种情况,您需要为两种颜色选择相同的比例。

这是一个更好地说明和展示我们如何获得相同颜色的例子:

在顶层(内部跨度),我们有0.25的不透明度(所以我们有25%的第一种颜色和75%的透明度),然后对于底层(外跨度),我们有{ {1}}不透明度(因此我们有75%的1/3 =颜色的25%,其余是透明的)。我们在两个层中都有相同的比例(25%),所以即使我们颠倒了图层的顺序,我们也会看到相同的颜色

&#13;
&#13;
0.333
&#13;
.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)
}
&#13;
&#13;
&#13;

作为旁注,白色背景也会影响颜色的渲染。它的比例为50%,这将得出100%的合理结果(25%+ 25%+ 50%)。

您可能还注意到,如果顶层的不透明度大于<span class="a"><span class="b"> Color 1</span></span> <span class="b"><span class="a">Different Color 2</span></span>,那么我们两种颜色的比例都不可能,因为第一个将超过0.5 50%,第二个仍然不到50%:

&#13;
&#13;
.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%*/
}
&#13;
<span class="a"><span class="b">          Color 1</span></span>
<span class="b"><span class="a">Different Color 2</span></span>
&#13;
&#13;
&#13;

常见的琐碎案例是顶层有opacity:1时,顶色的比例为100%;因此它是一种不透明颜色。

为了更准确和精确的解释,这里是用于计算我们在两个层 ref 的组合后看到的颜色的公式:

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

ColorF 是我们的最终颜色。 ColorT / ColorB 分别是顶部和底部颜色。 opacityT / opacityB 分别是为每种颜色定义的顶部和底部不透明度:

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

答案 1 :(得分:34)

您可以使用css属性mix-blend-mode : multiply(有限browser support

&#13;
&#13;
.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;
}
&#13;
<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>
&#13;
&#13;
&#13;

答案 2 :(得分:18)

您按以下顺序混合三种颜色:

  • 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 1 而不是commutative与背景颜色混合。由于它不是可交换的,因此交换前景色和背景色会产生不同的结果。

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:前景色的α值
Cb:背景颜色的颜色值
αb:背景颜色的alpha值 B:混合功能

答案 3 :(得分:6)

有关所发生情况的说明,请参阅Temani Afif的回答 作为替代解决方案,您可以使用一个范围a,例如,定位它,如果它在b内,则给它一个较低的z-index。然后,堆叠将始终相同:b在第一行的a之上绘制,a在第二行的b下面绘制。

&#13;
&#13;
.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;}
&#13;
<span class="a"><span class="b">     Color 1</span></span>
<span class="b"><span class="a">Same Color 2</span></span>
&#13;
&#13;
&#13;