Почему окончательный цвет двух уложенных друг на друга полупрозрачных коробок зависит от порядка?
Как сделать так, чтобы в обоих случаях я получал одинаковый цвет?
.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% цвет верхней части; таким образом, это непрозрачный цвет.Для более точного и точного объяснения, вот формула, используемая для расчета цвета, который мы видим после комбинации обоих слоев 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
источник
Вы можете использовать свойство 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))
И получаешь разные результаты. Это связано с тем, что цвет переднего плана смешивается с цветом фона с использованием обычного режима наложения 1,2, который не является коммутативным 3 . А поскольку он не коммутативен, замена цвета переднего плана и фона даст другой результат.
1 Режим наложения - это функция, которая принимает цвет переднего плана и фона, применяет некоторую формулу и возвращает результирующий цвет.
2 При наличии двух цветов, фона и переднего плана, обычный режим наложения просто возвращает цвет переднего плана.
3 Операция является коммутативной, если изменение порядка операндов не меняет результат, например, сложение коммутативно (1 + 2 = 2 + 1), а вычитание - нет (1-2 ≠ 2 - 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: значение альфа цвета фона;
B: функция смешивания.
источник
Для объяснения того, что происходит, см. Ответ Темани Афиф.
В качестве альтернативного решения вы можете взять один промежуток,
a
например, расположить его и присвоить ему более низкий z-index, если он внутриb
. Тогда наложение будет всегда одинаковым: в первой строке отображается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>
источник