Digamos que eu tenha uma cor de fundo com uma "fita" em outra cor sólida. Agora, quero que a fita seja parcialmente transparente para permitir que alguns detalhes se misturem, mas ainda manter a "mesma cor" sobre o fundo.
Existe uma maneira de (facilmente) determinar, para uma determinada opacidade / alfa <100% da cor da fita, quais valores RGB ele deve ter para ser idêntico à sua cor com 100% de opacidade sobre o fundo?
Aqui está uma foto. O plano de fundo é rgb(72, 28, 97)
fita rgb(45, 34, 70)
. Quero um rgba(r, g, b, a)
para a fita para que pareça idêntica a esta cor sólida.
Respostas:
A mistura de cores é apenas uma interpolação linear por canal, certo? Portanto, a matemática é muito simples. Se você tiver RGBA1 sobre RGB2, o resultado visual efetivo RGB3 será:
… Onde o canal alfa é de 0,0 a 1,0.
Verificação de sanidade: se o alfa for 0, RGB3 é o mesmo que RGB2? Sim. Se o alfa for 1, RGB3 é o mesmo que RGB1? Sim.
Se você bloqueou apenas a cor de fundo e a cor final, há um grande número de cores RGBA (infinitas, em espaço de ponto flutuante) que podem atender aos requisitos. Portanto, você precisa escolher a cor da barra ou o nível de opacidade desejado e descobrir o valor do outro.
Escolhendo a cor com base no alfa
Se você conhece RGB3 (a cor final desejada), RGB2 (a cor de fundo) e A1 (quanta opacidade você deseja), e está apenas procurando RGB1, então podemos reorganizar as equações da seguinte maneira:
Existem algumas combinações de cores que são teoricamente possíveis, mas impossíveis dada a faixa RGBA padrão. Por exemplo, se o fundo for preto puro, a cor percebida desejada é branco puro e o alfa desejado é 1%, então você precisa:
r1 = g1 = b1 = 255/0.01 = 25500
… Um branco superclaro 100 × mais brilhante do que qualquer disponível.
Escolhendo o alfa com base nas cores
Se você conhece RGB3 (a cor final desejada), RGB2 (a cor de fundo) e RGB1 (a cor que você tem e deseja variar a opacidade), e está apenas procurando A1, então podemos reorganizar o equações assim:
Se eles fornecerem valores diferentes, você não poderá fazer uma correspondência exata, mas pode calcular a média dos alfas para chegar o mais próximo possível. Por exemplo, não há opacidade no mundo que permita colocar o verde sobre o vermelho para ficar azul.
fonte
r1
,g1
eb1
também desconhecido?fiz MENOS mixin usando a resposta de Phrogz. você insere:
Aqui está o código:
.bg_alpha_calc (@desired_colour, @desired_alpha, @background_colour: white) { @r3: red(@desired_colour); @g3: green(@desired_colour); @b3: blue(@desired_colour); @r2: red(@background_colour); @g2: green(@background_colour); @b2: blue(@background_colour); // r1 = (r3 - r2 + r2 * a1) / a1 @r1: ( @r3 - @r2 + (@r2 * @desired_alpha) ) / @desired_alpha; @g1: ( @g3 - @g2 + (@g2 * @desired_alpha) ) / @desired_alpha; @b1: ( @b3 - @b2 + (@b2 * @desired_alpha) ) / @desired_alpha; background-color: @desired_colour; background-color: rgba(@r1, @g1, @b1, @desired_alpha); }
Uso assim:
@mycolour: #abc; @another_colour: blue; .box_overlay { // example: .bg_alpha_calc (@mycolour, 0.97, @another_colour); // or (for white bg) just: .bg_alpha_calc (@mycolour, 0.97); }
Obviamente, não funciona para combinações impossíveis (como mencionado por Phrogz), o que significa que apenas níveis suaves de transparência são suportados. Veja como você vai com isso.
fonte
Graças à Phrogz 's e Ephemer ' s grandes respostas, aqui é uma função SASS que automagicamente calcula a melhor cor RGBA equivalente.
Você o chama com a cor desejada e o fundo existente, e ele calcula a melhor (ou seja, mais transparente) cor RGBA equivalente que dá o resultado desejado dentro de ± 1/256 de cada componente RGB (devido a erros de arredondamento):
@function alphaize($desired-color, $background-color) { $r1: red($background-color); $g1: green($background-color); $b1: blue($background-color); $r2: red($desired-color); $g2: green($desired-color); $b2: blue($desired-color); $alpha: 0; $r: -1; $g: -1; $b: -1; @while $alpha < 1 and ($r < 0 or $g < 0 or $b < 0 or $r > 255 or $g > 255 or $b > 255) { $alpha: $alpha + 1/256; $inv: 1 / $alpha; $r: $r2 * $inv + $r1 * (1 - $inv); $g: $g2 * $inv + $g1 * (1 - $inv); $b: $b2 * $inv + $b1 * (1 - $inv); } @return rgba($r, $g, $b, $alpha); }
Acabei de testá-lo contra uma série de combinações (todos os temas Bootswatch) e funciona muito bem, tanto para resultados escuro sobre claro quanto claro sobre escuro.
PS: Se você precisar de precisão melhor do que ± 1/256 na cor resultante, você precisará saber que tipo de algoritmo de arredondamento os navegadores aplicam ao misturar cores rgba (não sei se isso é padronizado ou não) e adicionar um adequado condição ao existente
@while
, de forma que vai aumentando$alpha
até atingir a precisão desejada.fonte
transparentify()
: stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha ... que descobri após portar manualmente para a Stylus ...Da resposta de @Phrogz:
r3 = r2 + (r1-r2)*a1 g3 = g2 + (g1-g2)*a1 b3 = b2 + (b1-b2)*a1
Então:
r3 - r2 = (r1-r2)*a1 g3 - g2 = (g1-g2)*a1 b3 - b2 = (b1-b2)*a1
Então:
r1 = (r3 - r2) / a1 + r2 g1 = (g3 - g2) / a1 + g2 b1 = (b3 - b2) / a1 + b2
Nota você pode escolher qualquer valor
a1
, e isso vai encontrar os valores correspondentesr1
,g1
eb1
necessários. Por exemplo, escolher um alfa de 1 indica que você precisa de RGB1 = RGB3, mas escolher um alfa de 0 não dá solução (obviamente).fonte
A solução mais prática que encontrei até agora: basta medir a cor resultante com uma ferramenta de seleção de cores e usar a cor medida para a sobreposição. Este método fornece uma combinação perfeita de cores.
Eu tentei usar mixins diferentes, mas devido a um erro de arredondamento, ainda consegui ver a diferença a olho nu
fonte
Para expandir a resposta de @Tobia e permitir a especificação da opacidade mais como transparentify:
@function rgbaMorph($desired-color, $background-color: rgb(255,255,255), $desired-alpha: 0) { $r1: red($desired-color); $g1: green($desired-color); $b1: blue($desired-color); $r2: red($background-color); $g2: green($background-color); $b2: blue($background-color); $r: -1; $g: -1; $b: -1; @if ($desired-alpha != 0) { $r: ( $r1 - $r2 + ($r2 * $desired-alpha) ) / $desired-alpha; $g: ( $g1 - $g2 + ($g2 * $desired-alpha) ) / $desired-alpha; $b: ( $b1 - $b2 + ($b2 * $desired-alpha) ) / $desired-alpha; } @if (($desired-alpha == 0) or ($r < 0 or $g < 0 or $b < 0 or $r > 255 or $g > 255 or $b > 255)) { //if alpha not attainable, this will find lowest alpha that is $alpha: $desired-alpha; @while $alpha < 1 and ($r < 0 or $g < 0 or $b < 0 or $r > 255 or $g > 255 or $b > 255) { $alpha: $alpha + 1/256; $inv: 1 / $alpha; $r: $r1 * $inv + $r2 * (1 - $inv); $g: $g1 * $inv + $g2 * (1 - $inv); $b: $b1 * $inv + $b2 * (1 - $inv); } @debug "Color not attainable at opacity using alpha: " $alpha " instead of: " $desired-alpha; $desired-alpha: $alpha; } @return rgba($r, $g, $b, $desired-alpha); }
fonte