Kolor półprzezroczystych pudełek piętrowych zależy od zamówienia?

84

Dlaczego ostateczny kolor dwóch ułożonych w stos półprzezroczystych pudełek zależy od zamówienia?

Jak mogłem to zrobić, aby uzyskać ten sam kolor w obu przypadkach?

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

rmv
źródło
7
Nie znam odpowiedzi na to pytanie, ale to samo dzieje się w Photoshopie i od lat akceptuję to jako część komputerowej teorii koloru. Rozejrzę się, żeby zobaczyć, czy znajdę więcej informacji.
YAHsaves
11
Bez względu na to, co jest warte, to samo dzieje się w prawdziwym życiu w przypadku wszystkiego, co nie jest w 100% przezroczyste i jest oświetlone od przodu. Do oka dociera więcej światła z przedniego obiektu, dzięki czemu jego kolor ma większy wpływ na ostateczny kolor, nawet jeśli oba mają 50% przezroczystości.
jpa
4
@YAHsaves: Średnia z 0 i 100 to 50 (krok 1). Średnia z 50 i 150 to 100 (krok 2). Porównaj to z: średnia 150 i 0 to 75 (krok 1). Średnia 75 i 100 to 87,5 (krok 2). Problem polega na tym, że te trzy liczby nie są poprawnie ważone. Średnia musi być obliczona na podstawie wszystkich liczb w tym samym czasie; nie możesz po prostu rekurencyjnie obliczyć średniej krok po kroku. (Należy zauważyć, że średnie wyliczenie to zasadniczo 50% obliczenie przezroczystości. Obliczenie zmienia się dla różnych poziomów przezroczystości, ale zasada pozostaje taka sama)
Flater
2
Wyciągnięte wnioski: w trybie „mix-blend-mode: multiply” uzyskam kolor niezależny od kolejności układania - właśnie tego szukałem na początku! Myślę, że odpowiedź @Moffens jest najbardziej przydatna dla każdego innego użytkownika mającego ten sam problem. Ale wyjaśnienia Temani Afif faktycznie odnoszą się do mojego pytania i opisują, dlaczego HTML zachowuje się w inny sposób (naśladuje fizyczne rozchodzenie się światła przez półprzezroczyste folie), więc zielony znaczek trafia do niego.
rmv

Odpowiedzi:

101

Po prostu dlatego, że w obu przypadkach kombinacja kolorów nie jest taka sama ze względu na to, jak krycie górnej warstwy wpływa na kolor dolnej warstwy.

W pierwszym przypadku widać 50% niebieskiego i 50% przezroczystości w górnej warstwie. Przez przezroczystą część widać 50% koloru czerwonego w dolnej warstwie (więc w sumie widzimy tylko 25% czerwieni ). Ta sama logika w drugim przypadku ( 50% czerwieni i 25% niebieskiego ); w ten sposób zobaczysz różne kolory, ponieważ w obu przypadkach nie mamy takich samych proporcji.

Aby tego uniknąć, musisz mieć takie same proporcje dla obu kolorów.

Oto przykład, aby lepiej zilustrować i pokazać, jak możemy uzyskać ten sam kolor:

W górnej warstwie (wewnętrzna rozpiętość) mamy 0.25krycie (więc mamy 25% pierwszego koloru i 75% przezroczystości), a dla dolnej warstwy (zewnętrzna rozpiętość) mamy 0.333krycie (więc mamy 1/3 75% = 25% koloru, a pozostała część jest przezroczysta). Mamy taki sam udział w obu warstwach (25%), więc widzimy ten sam kolor, nawet jeśli odwrócimy kolejność warstw.

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

Na marginesie, białe tło ma również wpływ na renderowanie kolorów. Jego proporcja wynosi 50%, co daje logiczny wynik 100% (25% + 25% + 50%).

Możesz również zauważyć, że nie będzie możliwe uzyskanie takiej samej proporcji dla obu kolorów, jeśli górna warstwa ma krycie większe niż 0.5dlatego, że pierwsza będzie miała więcej niż 50%, a pozostanie mniej niż 50% dla drugiej jeden:

Typowym trywialnym przypadkiem jest sytuacja, w której wierzchnia warstwa opacity:1tworzy kolor wierzchni w 100%; dlatego jest to nieprzezroczysty kolor.


Aby uzyskać dokładniejsze i bardziej precyzyjne wyjaśnienie, oto wzór używany do obliczenia koloru, który widzimy po połączeniu obu warstw, ref :

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

ColorF to nasz ostateczny kolor. ColorT / ColorB to odpowiednio górny i dolny kolor. krycieT / krycieB to odpowiednio górne i dolne krycia zdefiniowane dla każdego koloru:

factorDefiniuje się w niniejszym wzorze OpacityT + OpacityB*(1 - OpacityT).

Oczywiste jest, że jeśli zmienimy dwie warstwy factor, nie zmieni się (pozostanie stała), ale wyraźnie widać, że proporcje dla każdego koloru ulegną zmianie, ponieważ nie mamy tego samego mnożnika.

W naszym początkowym przypadku oba zmętnienia są 0.5więc:

ColorF = (ColorT*0.5 + ColorB*0.5*(1 - 0.5)) / factor

Jak wyjaśniono powyżej, górny kolor ma udział 50% ( 0.5), a dolny ma udział 25% ( 0.5*(1-0.5)), więc przełączanie warstw również zmieni te proporcje; w ten sposób widzimy inny ostateczny kolor.

Teraz, jeśli weźmiemy pod uwagę drugi przykład, będziemy mieli:

ColorF = (ColorT*0.25 + ColorB*0.333*(1 - 0.25)) / factor

W tym przypadku mamy 0.25 = 0.333*(1 - 0.25)więc zamianę dwóch warstw bez efektu; w ten sposób kolor pozostanie taki sam.

Możemy również wyraźnie zidentyfikować trywialne przypadki:

  • Gdy warstwa wierzchnia ma opacity:0formułę równąColorF = ColorB
  • Gdy warstwa wierzchnia ma opacity:1formułę równąColorF = ColorT
Temani Afif
źródło
23
@ChrisHappy nie rozwiązuję problemu;) wyjaśniam ... wyjaśnienie jest czasem lepsze niż poprawka
Temani Afif
Problem nadal występuje, nawet jeśli zdejmiesz ze sobą elementy div i ustawiasz je w pozycji: bezwzględnie ustaw je na stosie.
YAHsaves
1
@YAHzapisuje, że problem wystąpi, nawet jeśli użyjemy wielu tła lub czegoś, co sprawia, że ​​dwa kolory nad sobą (używając pozycji bezwzględnej lub nie);)
Temani Afif
5
Jeśli chcesz dodać TLDR, oznaczałoby to, że są one multiplikatywne, a nie addytywne.
Caramiriel
2
@Caramiriel: „multiplicative” nadal nie wyjaśnia, dlaczego operacja nie jest przemienna.
Eric Duminil
41

Możesz użyć właściwości css mix-blend-mode : multiply (ograniczona obsługa przeglądarki )

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

Moffen
źródło
6
Prawie każdy tryb mieszania kolorów z tej listy, który jest „przemienny”, wystarczy.
Salman A
Co ciekawe, działa to z Chrome, ale nie z Edge (od najnowszej aktualizacji Windows 10).
Hong Ooi
3
@rmv, dlaczego miałbyś oczekiwać czegoś innego niż overlay / normal? Jaki jest oczekiwany kolor, jeśli umieszczenie nieprzezroczyste niebieskie pole przed czerwonym polu? Będzie niebieski zamiast czerwonego lub funkcja niebiesko-czerwonego.
Salman A
1
@Moffen Doskonała odpowiedź, ale czy mógłbyś dodać wyjaśnienie, dlaczego to działa, a oryginalny kod nie?
Bergi
1
@rmv: To, co najbardziej imituje „normalny” tryb mieszania, to w rzeczywistości mieszanie farb. Na przykład, jeśli weźmiesz białą farbę, zastąpisz połowę czerwoną farbą, a następnie połowę powstałej różowej farby niebieską, otrzymasz niebieskawo-fioletowy (25% biały, 25% czerwony, 50% niebieski). Jeśli zaczniesz od tej samej białej farby, ale najpierw zastąpisz jej połowę niebieską, a następnie połowę wyniku czerwoną, otrzymasz zamiast tego czerwonawo- fioletowy (25% biały, 25% niebieski, 50% czerwony).
Ilmari Karonen
22

Mieszasz trzy kolory w następującej kolejności:

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

Otrzymujesz różne wyniki. Dzieje się tak, ponieważ kolor pierwszego planu jest mieszany z kolorem tła przy użyciu normalnego trybu mieszania 1, 2, który nie jest przemienny 3 . A ponieważ nie jest przemienna, zamiana kolorów pierwszego planu i tła da inny wynik.

1 Tryb mieszania to funkcja, która akceptuje kolor pierwszego planu i tła, stosuje jakąś formułę i zwraca wynikowy kolor.

2 W przypadku dwóch kolorów, tła i pierwszego planu, normalny tryb mieszania po prostu zwraca kolor pierwszego planu.

3 Operacja jest przemienna, jeśli zmiana kolejności operandów nie zmienia wyniku, np. Dodawanie jest przemienne (1 + 2 = 2 + 1), a odejmowanie nie jest (1 - 2 ≠ 2 - 1).

Rozwiązaniem jest użycie trybu mieszania, który jest przemienny: taki, który zwraca ten sam kolor dla tej samej pary kolorów w dowolnej kolejności (na przykład tryb mieszania mnożenia, który mnoży oba kolory i zwraca kolor wynikowy; lub tryb mieszania ciemniej, który zwraca ciemniejszy kolor z dwóch).


Aby uzyskać kompletność, oto wzór do obliczenia złożonego koloru:

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

z:

Cs: wartość koloru pierwszego planu
αs: wartość alfa koloru pierwszego planu
Cb: wartość koloru tła
αb: wartość alfa koloru tła
B: funkcja mieszania

Salman A
źródło
8

Aby wyjaśnić, co się dzieje, zobacz odpowiedź Temani Afif.
Jako alternatywne rozwiązanie możesz ana przykład wziąć jeden przęsło, ustawić go i nadać mu niższy indeks Z, jeśli znajduje się wewnątrz b. Wtedy układanie będzie zawsze takie samo: bjest rysowany na górze aw pierwszej linii i ajest rysowany pod spodem bw drugiej.

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

Panie Lister
źródło