Il colore delle scatole semitrasparenti impilate dipende dall'ordine?


86

Perché il colore finale di due scatole semitrasparenti impilate dipende dall'ordine?

Come potrei fare in modo da ottenere lo stesso colore in entrambi i casi?

.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
Non conosco la risposta alla domanda, ma la stessa cosa accade in Photoshop ed è qualcosa che ho accettato per anni come parte della teoria del colore del computer. Mi guarderò intorno per vedere se riesco a trovare altre informazioni.
YAHsaves

11
Per quel che vale, la stessa cosa accade nella vita reale per tutto ciò che non è trasparente al 100% ed è illuminato frontalmente. Più luce dall'oggetto frontale arriva all'occhio, quindi il suo colore ha un effetto maggiore sul colore finale anche se entrambi hanno il 50% di trasparenza.
jpa

4
@YAHsaves: la media di 0 e 100 è 50 (passaggio 1). La media di 50 e 150 è 100 (passaggio 2). Confronta questo con: la media di 150 e 0 è 75 (passaggio 1). La media di 75 e 100 è 87,5 (passaggio 2). Il problema è che i tre numeri non vengono ponderati correttamente. È necessario calcolare una media basata su tutti i numeri contemporaneamente; non puoi semplicemente calcolare ricorsivamente la media passo dopo passo. (Si noti che il calcolo medio è essenzialmente un calcolo di trasparenza del 50%. Il calcolo cambia per diversi livelli di trasparenza, ma il principio rimane lo stesso)
Flater

2
Lezioni apprese: con 'mix-blend-mode: multiply' otterrò un colore indipendente dall'ordine di sovrapposizione - questo è quello che stavo cercando inizialmente! Penso che la risposta di @Moffens sia molto utile per qualsiasi altro utente che affronta lo stesso problema. Ma le spiegazioni di Temani Afif si applicano effettivamente alla mia domanda e descrivono perché l'HTML si comporta in un altro modo (imita la propagazione fisica della luce attraverso fogli semitrasparenti), quindi il segno di spunta verde va a lui.
rmv

Risposte:


103

Semplicemente perché in entrambi i casi la combinazione dei colori non è la stessa a causa di come l'opacità dello strato superiore influisce sul colore dello strato inferiore .

Per il primo caso, vedi il 50% di blu e il 50% di trasparente nello strato superiore. Attraverso la parte trasparente, vedi il 50% di colore rosso nello strato inferiore (quindi vediamo solo il 25% di rosso in totale). Stessa logica per il secondo caso ( 50% di rosso e 25% di blu ); quindi vedrai colori diversi perché per entrambi i casi non abbiamo la stessa proporzione.

Per evitare ciò è necessario avere la stessa proporzione per entrambi i colori.

Ecco un esempio per meglio illustrare e mostrare come possiamo ottenere lo stesso colore:

Nello strato superiore (lo span interno) abbiamo 0.25dell'opacità (quindi abbiamo il 25% del primo colore e il 75% di trasparente) poi per lo strato inferiore (lo span esterno) abbiamo 0.333opacità (quindi abbiamo 1/3 di 75% = 25% del colore e il restante è trasparente). Abbiamo la stessa proporzione in entrambi gli strati (25%) quindi vediamo lo stesso colore anche se invertiamo l'ordine degli strati.

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

Come nota a margine, lo sfondo bianco influisce anche sulla resa dei colori. La sua proporzione è del 50%, il che renderà il risultato logico del 100% (25% + 25% + 50%).

Potresti anche notare che non sarà possibile avere la stessa proporzione per entrambi i nostri colori se lo strato superiore ha un'opacità maggiore di 0.5perché il primo avrà più del 50% e rimarrà inferiore al 50% per il secondo uno:

Il caso banale comune è quando lo strato superiore è avente opacity:1che rende il colore superiore con una proporzione del 100%; quindi è un colore opaco .


Per una spiegazione più accurata e precisa ecco la formula utilizzata per calcolare il colore che vediamo dopo la combinazione di entrambi gli strati rif :

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

ColorF è il nostro colore finale. ColorT / ColorB sono rispettivamente i colori superiore e inferiore. opacityT / opacityB sono rispettivamente le opacità superiore e inferiore definite per ciascun colore:

Il factorè definito da questa formula OpacityT + OpacityB*(1 - OpacityT).

È chiaro che se cambiamo i due livelli factornon cambierà (rimarrà una costante) ma possiamo vedere chiaramente che la proporzione per ogni colore cambierà poiché non abbiamo lo stesso moltiplicatore.

Per il nostro caso iniziale, entrambe le opacità sono 0.5così avremo:

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

Come spiegato sopra, il colore superiore ha una proporzione del 50% ( 0.5) e quello inferiore ha una proporzione del 25% ( 0.5*(1-0.5)), quindi cambiare gli strati cambierà anche queste proporzioni; quindi vediamo un colore finale diverso .

Ora se consideriamo il secondo esempio avremo:

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

In questo caso, il 0.25 = 0.333*(1 - 0.25)passaggio dei due livelli non avrà alcun effetto; così il colore rimarrà lo stesso.

Possiamo anche identificare chiaramente i casi banali:

  • Quando lo strato superiore ha opacity:0la formula è uguale aColorF = ColorB
  • Quando lo strato superiore ha opacity:1la formula è uguale aColorF = ColorT

23
@ChrisHappy non sto risolvendo il problema;) sto spiegando .. la spiegazione a volte è migliore della correzione
Temani Afif

Il problema si verifica ancora anche se prendi i div l'uno dall'altro e li posizioni: assoluti per impilarli.
YAHsaves

1
@YAHsaves il problema si verificherà anche se utilizziamo più sfondi o qualsiasi cosa che renda i due colori uno sopra l'altro (usando la posizione assoluta o meno);)
Temani Afif

5
Se vuoi aggiungere un TLDR, sarebbe che sono moltiplicativi anziché additivi.
Caramiriel

2
@Caramiriel: "moltiplicativo" ancora non spiega perché l'operazione non è commutativa.
Eric Duminil

41

È possibile utilizzare la proprietà css, mix-blend-mode : multiply ( supporto browser limitato )

.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
Quasi tutti i metodi di fusione dei colori di questo elenco che sono "commutativi" andranno bene.
Salman A

Interessante, funziona con Chrome ma non con Edge (a partire dall'ultimo aggiornamento di Windows 10).
Hong Ooi

3
@rmv perché ti aspetteresti qualcosa di diverso da overlay / normal? Qual è il colore previsto se si posiziona un riquadro blu opaco davanti a un riquadro rosso? Sarà blu invece che rosso o in funzione di blu e rosso.
Salman A

1
@ Moffen Risposta perfetta, ma potresti aggiungere una spiegazione del motivo per cui funziona e perché il codice originale no?
Bergi

1
@rmv: Ciò che la modalità di miscelazione "normale" imita più da vicino è in realtà la miscelazione della pittura. Ad esempio, se prendi un po 'di vernice bianca, ne sostituisci metà con vernice rossa e poi sostituisci metà della vernice rosa risultante con vernice blu, ti ritroverai con un viola bluastro (25% bianco, 25% rosso, 50% blu). Se inizi con la stessa vernice bianca ma prima ne sostituisci metà con il blu e poi metà del risultato con il rosso, ti ritroverai invece con un viola rossastro (25% bianco, 25% blu, 50% rosso).
Ilmari Karonen

22

Stai mescolando tre colori nel seguente ordine:

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

E ottieni risultati diversi. Questo perché il colore di primo piano viene miscelato con il colore di sfondo utilizzando la modalità di fusione normale 1,2 che non è commutativa 3 . E poiché non è commutativo, lo scambio dei colori di primo piano e di sfondo produrrà risultati diversi.

1 La modalità di fusione è una funzione che accetta un colore di primo piano e di sfondo, applica una formula e restituisce il colore risultante.

2 Dati due colori, sfondo e primo piano, la modalità di fusione normale restituisce semplicemente il colore di primo piano.

3 Un'operazione è commutativa se la modifica dell'ordine degli operandi non cambia il risultato, ad esempio l'addizione è commutativa (1 + 2 = 2 + 1) e la sottrazione non lo è (1 - 2 ≠ 2 - 1).

La soluzione è utilizzare una modalità di fusione commutativa: una che restituisce lo stesso colore per la stessa coppia di colori in qualsiasi ordine (ad esempio la modalità di fusione multipla, che moltiplica entrambi i colori e restituisce il colore risultante; o la modalità di fusione scurisce, che restituisce il colore più scuro dei due).


Per completezza, ecco la formula per calcolare il colore composito:

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

con:

Cs: il valore del colore di primo piano
αs: il valore alfa del colore di primo piano
Cb: il valore del colore del colore di sfondo
αb: il valore alfa del colore di sfondo
B: la funzione di fusione


8

Per la spiegazione di ciò che accade, vedere la risposta di Temani Afif.
Come soluzione alternativa, puoi prendere un intervallo, aad esempio, posizionarlo e assegnargli uno z-index inferiore se è all'interno b. Quindi l'impilamento sarà sempre lo stesso: bviene disegnato sopra anella prima riga e aviene disegnato sotto bnella seconda.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.