CSS 寻找具有不透明度的“等效”颜色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12228548/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 20:04:03  来源:igfitidea点击:

Finding "equivalent" color with opacity

csscolors

提问by vicvicvic

Say I have a background color with a "ribbon" running over it in another solid color. Now, I want the ribbon to be partially transparent to let some details blend through, but still keep the ribbon the "same color" over the background.

假设我有一个背景颜色,上面有一条“丝带”,上面有另一种纯色。现在,我希望色带部分透明,让一些细节混合通过,但仍然让色带在背景上保持“相同的颜色”。

Is there a way to (easily) determine, for a given opacity/alpha < 100% of the ribbon color, what RGB values it should have to be identical to its color with 100% opacity over the background?

有没有办法(轻松)确定,对于给定的不透明度/alpha < 100% 色带颜色,它应该具有哪些 RGB 值与其背景上的 100% 不透明度的颜色相同?

Here's a picture. Background is rgb(72, 28, 97), ribbon rgb(45, 34, 70). I want a rgba(r, g, b, a)for the ribbon so that it appears identical to this solid color.

这是一张图片。背景是rgb(72, 28, 97),丝带rgb(45, 34, 70)。我想要一个rgba(r, g, b, a)用于缎带的,以便它看起来与这种纯色相同。

enter image description here

在此处输入图片说明

回答by Phrogz

Color blending is just a linear interpolation per channel, right? So the math is pretty simple. If you have RGBA1 over RGB2, the effective visual result RGB3 will be:

颜色混合只是每个通道的线性插值,对吗?所以数学很简单。如果 RGBA1 超过 RGB2,则有效的视觉效果 RGB3 将是:

r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1

…where the alpha channel is from 0.0 to 1.0.

...其中 alpha 通道从 0.0 到 1.0。

Sanity check: if the alpha is 0, is RGB3 the same as RGB2? Yes. If the alpha is 1, is RGB3 the same as RGB1? Yes.

完整性检查:如果 alpha 为 0,RGB3 是否与 RGB2 相同?是的。如果 alpha 为 1,RGB3 是否与 RGB1 相同?是的。

If you locked down only the background color and final color, there are a large number of RGBA colors (infinite, in floating-point space) that could satisfy the requirements. So you have to pick either the color of the bar or the opacity level you want, and find out the value of the other.

如果只锁定背景颜色和最终颜色,则有大量 RGBA 颜色(无限,在浮点空间中)可以满足要求。所以你必须选择你想要的条形颜色或不透明度级别,并找出另一个的值。

Picking the Color Based on Alpha

根据 Alpha 选择颜色

If you know RGB3 (the final desired color), RGB2 (the background color), and A1 (how much opacity you want), and you are just looking for RGB1, then we can re-arrange the equations thusly:

如果您知道 RGB3(最终所需的颜色)、RGB2(背景颜色)和 A1(您想要多少不透明度),并且您只是在寻找 RGB1,那么我们可以这样重新排列方程:

r1 = (r3 - r2 + r2*a1)/a1
g1 = (g3 - g2 + g2*a1)/a1
b1 = (b3 - b2 + b2*a1)/a1

There are some color combinations which are theoretically possible, but impossible given the standard RGBA range. For example, if the background is pure black, the desired perceived color is pure white, and the desired alpha is 1%, then you would need:

有一些颜色组合在理论上是可能的,但鉴于标准的 RGBA 范围是不可能的。例如,如果背景是纯黑色,所需的感知颜色是纯白色,并且所需的 alpha 为 1%,那么您需要:

r1 = g1 = b1 = 255/0.01 = 25500

…a super-bright white 100× brighter than any available.

...超亮白色比任何现有产品都亮 100 倍。

Picking the Alpha Based on Colors

根据颜色选择 Alpha

If you know RGB3 (the final desired color), RGB2 (the background color), and RGB1 (the color you have that you want to vary the opacity of), and you are just looking for A1, then we can re-arrange the equations thusly:

如果您知道 RGB3(最终所需的颜色)、RGB2(背景颜色)和 RGB1(您想要改变其不透明度的颜色),并且您只是在寻找 A1,那么我们可以重新排列方程因此:

a1 = (r3-r2) / (r1-r2)
a1 = (g3-g2) / (g1-g2)
a1 = (b3-b2) / (b1-b2)

If these give different values, then you can't make it match exactly, but you can average the alphas to get as close as possible. For example, there's no opacity in the world that will let you put green over red to get blue.

如果这些给出不同的值,那么你不能让它完全匹配,但你可以平均 alphas 以尽可能接近。例如,世界上没有不透明度可以让您将绿色置于红色之上以获得蓝色。

回答by ephemer

i made a LESS mixin using Phrogz' answer. you input:

我使用 Phrogz 的回答做了一个 LESS mixin。你输入:

  1. how the colour should look
  2. with a certain alpha
  3. on a given background (default being white)
  1. 颜色应该看起来如何
  2. 有一定的阿尔法
  3. 在给定的背景上(默认为白色)

Here's the 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);

}

Usage like so:

用法如下:

@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);
}

Obviously doesn't work for impossible combinations (as mentioned by Phrogz), that means only mild levels of transparency are supported. See how you go with it.

显然不适用于不可能的组合(如 Phrogz 所述),这意味着仅支持适度的透明度。看看你如何处理它。

回答by Tobia

Thanks to Phrogz's and ephemer's great answers, here is a SASS function that automagicallycomputes the best equivalent RGBA color.

感谢Phrogzephemer的出色回答,这里有一个 SASS 函数,可以自动计算最佳等效 RGBA 颜色。

You call it with the desired color and the existing background, and it will compute the best (meaning most transparent) equivalent RGBA color that gives the desired result within ±1/256 of each RGB component (due to rounding errors):

您使用所需颜色和现有背景调用它,它将计算最佳(即最透明)等效 RGBA 颜色,在每个 RGB 分量的 ±1/256 范围内提供所需结果(由于舍入误差):

@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);
}

I just tested it against a number of combinations (all the Bootswatch themes) and it works a treat, both for dark-on-light and light-on-dark results.

我刚刚针对多种组合(所有 Bootswatch 主题)对它进行了测试,它对明暗效果和明暗效果都有效。

PS: If you need better than ±1/256 precision in the resulting color, you will need to know what kind of rounding algorithm browsers apply when blending rgba colors (I don't know if that is standardized or not) and add a suitable condition to the existing @while, so that it keeps increasing $alphauntil it achieves the desired precision.

PS:如果您需要的结果颜色精度高于±1/256,您将需要知道在混合 rgba 颜色时浏览器应用什么样的舍入算法(我不知道这是否标准化)并添加合适的条件到现有的@while,以便它不断增加,$alpha直到达到所需的精度。

回答by Eric

From @Phrogz' answer:

来自@Phrogz 的回答:

r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1

So:

所以:

r3 - r2 = (r1-r2)*a1
g3 - g2 = (g1-g2)*a1
b3 - b2 = (b1-b2)*a1

So:

所以:

r1 = (r3 - r2) / a1 + r2
g1 = (g3 - g2) / a1 + g2
b1 = (b3 - b2) / a1 + b2

Note you can pick any value of a1, and this will find the corresponding values of r1, g1, and b1required. For example, picking an alpha of 1 tells you that you need RGB1 = RGB3, but picking an alpha of 0 gives no solution (obviously).

请注意,您可以挑选任何价值a1,这将找到的相应值r1g1b1需要。例如,选择 1 的 alpha 告诉您需要 RGB1 = RGB3,但选择 0 的 alpha 没有解决方案(显然)。

回答by phazei

To expand on @Tobia's answer and allow for specifying the opacity more like transparentify:

要扩展@Tobia 的答案并允许指定更像透明化的不透明度:

@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);
}