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>
Odpowiedzi:
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.25
krycie (więc mamy 25% pierwszego koloru i 75% przezroczystości), a dla dolnej warstwy (zewnętrzna rozpiętość) mamy0.333
krycie (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.5
dlatego, że pierwsza będzie miała więcej niż 50%, a pozostanie mniej niż 50% dla drugiej jeden:Pokaż fragment kodu
.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>
Typowym trywialnym przypadkiem jest sytuacja, w której wierzchnia warstwa
opacity:1
tworzy 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:
factor
Definiuje się w niniejszym wzorzeOpacityT + 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.5
wię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:
opacity:0
formułę równąColorF = ColorB
opacity:1
formułę równąColorF = ColorT
źródło
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>
źródło
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).
Pokaż fragment kodu
$(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>
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
źródło
Aby wyjaśnić, co się dzieje, zobacz odpowiedź Temani Afif.
Jako alternatywne rozwiązanie możesz
a
na przykład wziąć jeden przęsło, ustawić go i nadać mu niższy indeks Z, jeśli znajduje się wewnątrzb
. Wtedy układanie będzie zawsze takie samo:b
jest rysowany na górzea
w pierwszej linii ia
jest rysowany pod spodemb
w 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>
źródło