Колір укладених напівпрозорих коробок залежить від замовлення?


84

Чому кінцевий колір двох напівпрозорих коробок, що укладаються один від одного, залежить від замовлення?

Як я міг зробити так, щоб я отримав однаковий колір в обох випадках?

.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>


7
Я не знаю відповіді на запитання, але те саме відбувається в фотошопі, і це те, що я роками визнавав просто частиною комп'ютерної теорії кольорів. Я озирнуся навколо, чи не зможу знайти більше інформації.
YAHзберігає

11
Наскільки це варте, те саме відбувається в реальному житті з будь-чим, що не є на 100% прозорим і освітлене спереду. Більше світла від переднього предмета потрапляє у ваше око, отже його колір має більший вплив на кінцевий колір, навіть якщо обидва мають 50% прозорості.
jpa

4
@YAHsaves: Середнє значення 0 і 100 - 50 (крок 1). Середнє значення 50 і 150 - 100 (крок 2). Порівняйте це з: середнє значення 150 та 0 дорівнює 75 (крок 1). Середнє значення 75 і 100 становить 87,5 (крок 2). Проблема в тому, що три цифри не зважені правильно. Середнє значення потрібно розрахувати, виходячи з усіх чисел одночасно; ви не можете просто рекурсивно розрахувати середнє покроково. (Зверніть увагу, що середня оцінка - це, по суті, 50% -ний розрахунок прозорості. Розрахунок змінюється для різних рівнів прозорості, але принцип залишається незмінним)
Флатер

2
Вивчені уроки: за допомогою “mix-blend-mode: multiply” я отримаю колір, який не залежить від порядку укладання - це те, що я спочатку шукав! Я думаю, що відповідь @Moffens є найбільш корисною для будь-якого іншого користувача, який стикається з такою ж проблемою. Але пояснення Temani Afif насправді стосуються мого запитання та описують, чому HTML поводиться по-іншому (він імітує фізичне розповсюдження світла через напівпрозорі фольги), тому зелений галочку йде до нього.
rmv

Відповіді:


101

Просто тому, що в обох випадках поєднання кольорів неоднакове через те, як непрозорість верхнього шару впливає на колір нижнього шару.

У першому випадку ви бачите 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% один:

Поширений тривіальний випадок, коли верхній шар має, 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

23
@ChrisHappy я не вирішую проблему;) пояснюю .. пояснення іноді краще, ніж виправлення
Темані Афіф,

Проблема все ще виникає, навіть якщо ви виймаєте div-файли один з одного і розміщуєте: абсолютизуйте їх для стеку.
YAHзберігає

1
@YAHзберігає проблему, навіть якщо ми використовуємо кілька фонів або будь-яку річ, яка робить два кольори один над одним (з абсолютним положенням чи ні);)
Темані Афіф,

5
Якщо ви хочете додати TLDR, можливо, вони мультипликативні замість адитивних.
Caramiriel

2
@Caramiriel: "мультиплікативний" все одно не пояснює, чому операція не є комутативною.
Ерік Думініл

41

Ви можете використовувати властивість 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>


6
Практично будь-який режим змішування кольорів із цього списку, який є "комутативним", зробить свою справу.
Салман,

Цікаво, що це працює з Chrome, але не з Edge (станом на останнє оновлення Windows 10).
Hong Ooi,

3
@rmv, чому ти очікуєш чогось іншого, крім накладання / звичайного? Який очікуваний колір, якщо розташувати непрозору блакитну коробку перед червоною коробкою? Це буде синій замість червоного або функція синьо-червоного.
Салман,

1
@Moffen Ідеальна відповідь, але чи можете ви додати пояснення, чому це працює, і чому оригінальний код не зробив?
Бергі

1
@rmv: Те, що "нормальний" режим змішування найтісніше імітує, це насправді змішування фарби. Наприклад, якщо ви взяли трохи білої фарби, замінили половину на червону, а потім половину отриманої рожевої фарби замінили на синю, ви отримаєте блакитно-фіолетовий (25% білий, 25% червоний, 50% блакитний). Якщо ви починаєте з тієї ж білої фарби, але спочатку замінюєте половину її синьою, а потім половину результату червоною, замість цього ви отримаєте червонувато- фіолетову (25% білу, 25% синю, 50% червону).
Ілмарі Каронен

22

Ви змішуєте три кольори в такому порядку:

  • 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).

Рішення полягає у використанні комутаційного режиму змішування: режиму, який повертає однаковий колір для тієї самої пари кольорів у будь-якому порядку (наприклад, режим множення, що множить обидва кольори та повертає результуючий колір; або темніючий режим змішування, який повертає темніший колір двох).


Для повноти, ось формула для розрахунку складеного кольору:

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

з:

Cs: значення кольору переднього плану
αs: альфа-значення кольору переднього плану
Cb: значення кольору фонового кольору
αb: альфа-значення кольору тла
B: функція змішування


8

Пояснення щодо того, що відбувається, див. У відповіді Темані Афіф.
В якості альтернативного рішення ви можете взяти один проміжок, aнаприклад, розташувати його і надати йому нижчий z-індекс, якщо він знаходиться всередині 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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.