Disons que j'ai une couleur d'arrière-plan avec un "ruban" qui le recouvre dans une autre couleur unie. Maintenant, je veux que le ruban soit partiellement transparent pour permettre à certains détails de se fondre, tout en conservant la "même couleur" du ruban sur l'arrière-plan.
Existe-t-il un moyen de déterminer (facilement), pour une opacité/alpha <100% donnée de la couleur du ruban, quelles valeurs RVB il doit être identique à sa couleur avec une opacité de 100% sur le fond?
Voici une photo. L'arrière-plan est rgb(72, 28, 97)
, ruban rgb(45, 34, 70)
. Je veux une rgba(r, g, b, a)
pour le ruban afin qu'il apparaisse identique à cette couleur unie.
Le mélange des couleurs n'est qu'une interpolation linéaire par canal, non? Le calcul est donc assez simple. Si vous avez RGBA1 sur RGB2, le résultat visuel effectif RGB3 sera:
r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1
… Où le canal alpha est de 0,0 à 1,0.
Sanity check: si l'alpha est 0, RGB3 est-il le même que RGB2? Oui. Si l'alpha est 1, RGB3 est-il le même que RGB1? Oui.
Si vous ne verrouillez que la couleur d'arrière-plan et la couleur finale, il existe un grand nombre de couleurs RGBA (infinies, dans un espace à virgule flottante) qui pourraient répondre aux exigences. Vous devez donc choisir soit la couleur de la barre, soit le niveau d'opacité souhaité, et connaître la valeur de l'autre.
Si vous connaissez RGB3 (la couleur finale souhaitée), RGB2 (la couleur d'arrière-plan) et A1 (combien d'opacité vous voulez), et que vous recherchez simplement RGB1, alors nous pouvons réorganiser les équations de la manière suivante:
r1 = (r3 - r2 + r2*a1)/a1
g1 = (g3 - g2 + g2*a1)/a1
b1 = (b3 - b2 + b2*a1)/a1
Il existe certaines combinaisons de couleurs théoriquement possibles, mais impossibles compte tenu de la plage RGBA standard. Par exemple, si l'arrière-plan est d'un noir pur, la couleur perçue souhaitée est du blanc pur et l'alpha souhaité est de 1%, alors vous aurait besoin de:
r1 = g1 = b1 = 255/0.01 = 25500
… un blanc super brillant 100 × plus brillant que n'importe quel autre disponible.
Si vous connaissez RGB3 (la couleur finale souhaitée), RGB2 (la couleur d'arrière-plan) et RGB1 (la couleur que vous avez dont vous souhaitez modifier l'opacité), et que vous recherchez simplement A1, nous pouvons réorganiser le équations ainsi:
a1 = (r3-r2) / (r1-r2)
a1 = (g3-g2) / (g1-g2)
a1 = (b3-b2) / (b1-b2)
Si ceux-ci donnent des valeurs différentes, vous ne pouvez pas les faire correspondre exactement, mais vous pouvez faire la moyenne des alphas pour vous rapprocher le plus possible. Par exemple, il n'y a pas d'opacité dans le monde qui vous permettra de mettre le vert sur le rouge pour devenir bleu.
j'ai fait un mixin MOINS en utilisant la réponse de Phrogz. vous entrez:
Voici le code:
.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);
}
Utilisation comme ça:
@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);
}
Évidemment, cela ne fonctionne pas pour les combinaisons impossibles (comme mentionné par Phrogz), cela signifie que seuls des niveaux de transparence légers sont pris en charge. Voyez comment vous allez avec.
Grâce aux bonnes réponses de Phrogz et éphémère, voici une fonction SASS qui automagiquement calcule la meilleure couleur RGBA équivalente.
Vous l'appelez avec la couleur souhaitée et l'arrière-plan existant, et il calculera la meilleure couleur RGBA équivalente (c'est-à-dire la plus transparente) qui donne le résultat souhaité à ± 1/256 de chaque composant RGB (en raison d'erreurs d'arrondi):
@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);
}
Je viens de le tester contre un certain nombre de combinaisons (tous les thèmes Bootswatch) et cela fonctionne un régal, à la fois pour les résultats sombre sur lumière et lumière sur sombre.
PS: si vous avez besoin d'une précision supérieure à ± 1/256 dans la couleur résultante, vous devrez savoir quel type de navigateur d'algorithme d'arrondi appliquer lors du mélange des couleurs rgba (je ne sais pas si cela est standardisé ou non) et ajouter un condition à l'existant @while
, pour qu'il continue d'augmenter $alpha
jusqu'à ce qu'il atteigne la précision souhaitée.
De la réponse de @Phrogz:
r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1
Alors:
r3 - r2 = (r1-r2)*a1
g3 - g2 = (g1-g2)*a1
b3 - b2 = (b1-b2)*a1
Alors:
r1 = (r3 - r2) / a1 + r2
g1 = (g3 - g2) / a1 + g2
b1 = (b3 - b2) / a1 + b2
Notez que vous pouvez choisir n'importe quelle valeur de a1
, ce qui trouvera les valeurs correspondantes de r1
, g1
, et b1
Champs obligatoires. Par exemple, choisir un alpha de 1 vous indique que vous avez besoin de RGB1 = RGB3, mais choisir un alpha de 0 ne donne aucune solution (évidemment).
Pour développer la réponse de @ Tobia et permettre de spécifier l'opacité plus comme 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);
}