假设我有一个带有“绶带”的背景颜色,绶带的颜色是另一种纯色。现在,我想让绶带部分透明,以便让一些细节融入其中,但仍然保持绶带在背景上的“相同颜色”。
有没有一种方法(简单地)确定给定不透明度/alpha < 100%时,需要使用哪些RGB值才能使绶带与在背景下100%不透明时的颜色相同?
这里有一张图片。背景为rgb(72, 28, 97)
,绶带rgb(45, 34, 70)
。我想要一个rgba(r, g, b, a)
,使其外观与这种纯色相同。
假设我有一个带有“绶带”的背景颜色,绶带的颜色是另一种纯色。现在,我想让绶带部分透明,以便让一些细节融入其中,但仍然保持绶带在背景上的“相同颜色”。
有没有一种方法(简单地)确定给定不透明度/alpha < 100%时,需要使用哪些RGB值才能使绶带与在背景下100%不透明时的颜色相同?
这里有一张图片。背景为rgb(72, 28, 97)
,绶带rgb(45, 34, 70)
。我想要一个rgba(r, g, b, a)
,使其外观与这种纯色相同。
颜色混合只是每个通道的线性插值,对吧?因此,数学计算非常简单。如果您具有RGBA1覆盖RGB2,则有效的可视结果RGB3将为:
r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1
……其中alpha通道的取值范围是0.0到1.0。
合理性检查:如果alpha为0,RGB3是否与RGB2相同?是的。如果alpha为1,RGB3是否与RGB1相同?是的。
如果你只锁定了背景颜色和最终颜色,那么会有大量的RGBA颜色(在浮点空间中是无限的)可以满足要求。因此,你必须选择条形的颜色或所需的不透明度水平,并找出另一个值。
如果你知道RGB3(最终期望的颜色),RGB2(背景颜色)和A1(你想要的不透明度水平),并且你只是想找到RGB1,那么我们可以重新排列方程:
r1 = (r3 - r2 + r2*a1)/a1
g1 = (g3 - g2 + g2*a1)/a1
b1 = (b3 - b2 + b2*a1)/a1
有一些颜色组合在理论上是可能的,但在标准RGBA范围内是不可能的。例如,如果背景是纯黑色,所期望的颜色是纯白色,期望的透明度为1%,那么您需要:
r1 = g1 = b1 = 255/0.01 = 25500
…一个超亮的白色,比任何可用的颜色都要亮100倍。
如果您知道 RGB3(最终期望的颜色)、RGB2(背景色)和 RGB1(您想要改变不透明度的颜色),并且您只是在寻找 A1,则我们可以重排方程:
a1 = (r3-r2) / (r1-r2)
a1 = (g3-g2) / (g1-g2)
a1 = (b3-b2) / (b1-b2)
如果这些值不同,那么你无法完全匹配它们,但你可以平均透明度来尽量接近。例如,在世界上没有任何不透明度可以让你将绿色放在红色上来得到蓝色。
r1
,g1
和b1
也不是未知的吗? - Eric我使用Phrogz的答案创建了一个LESS mixin。你需要输入:
这是代码:
.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);
}
使用方法如下:
@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);
}
很明显,这对于不可能的组合是不起作用的(如Phrogz所提到的),这意味着只支持轻度透明度。看看你能否使用它。
感谢< strong>Phrogz < /strong>和< strong>ephemer< /strong>提供的好答案,这里有一个SASS函数,可以< strong>自动幻化< /strong>计算出最佳等效的RGBA颜色。
您可以使用所需的颜色和现有的背景来调用它,并且它将计算出在每个RGB组件±1/256内(由于四舍五入误差)给出所需结果的最佳(即最透明)等效RGBA颜色:
@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);
}
我刚刚对各种组合(所有的Bootswatch主题)进行了测试,它完美地工作,无论是暗色背景上的浅色字体还是浅色背景上的深色字体。
附注:如果您需要在结果颜色中获得比±1/256更好的精度,则需要了解浏览器在混合rgba颜色时应用的四舍五入算法(我不知道是否标准化),并向现有的@while
添加适当的条件,以便它保持增加$alpha
直到达到所需的精度。
transparentify()
:http://stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha。在我手动将其移植到 Stylus 后发现了这一点。 - weotch来自@Phrogz的回答:
r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1
r3 - r2 = (r1-r2)*a1
g3 - g2 = (g1-g2)*a1
b3 - b2 = (b1-b2)*a1
r1 = (r3 - r2) / a1 + r2
g1 = (g3 - g2) / a1 + g2
b1 = (b3 - b2) / a1 + b2
a1
,并找到所需的r1
、g1
和b1
的相应值。例如,选择alpha值为1告诉您需要RGB1 = RGB3,但选择alpha值为0则无解(显然)。为了扩展@Tobia的答案并允许更像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);
}
我写了一个工具,可以从JSS中使用它来帮助我使颜色透明。它使用了material-ui的实用方法,可以在这里找到。
这是我的实用类代码(使用TypeScript编写)。请注意,有些颜色无法保持其颜色不变而同时使其透明。
抱歉我没有提供codepen或可运行的代码。我希望有人能发现这个工具并从中获得一些用处!
import {
decomposeColor,
recomposeColor,
ColorObject,
} from '@material-ui/core/styles/colorManipulator';
/**
* Take a non transparent color and create a transparent color that looks identical visually.
* Using formula from this SO post https://dev59.com/92ct5IYBdhLWcg3wQ7My
* Assuming a white background
* @param origColor The color you want to match.
* @param value Transparency value between 0 and 1. Cannot be too low because it is mathematically not possible (usually <0.2 but depends on the color)
*/
export const makeTransparent = (origColor: string, value: number): string => {
const origColorObj: ColorObject = decomposeColor(origColor);
if (value >= 1 || value <= 0)
throw new Error('makeTransparent: invalid value provided');
if (origColorObj.values[3] != null && origColorObj.values[3] !== 1)
throw new Error('makeTransparent: origColor cannot be transparent');
const newColorObj: ColorObject = {
type: 'rgba',
values: [0, 0, 0, value],
};
for (let i = 0; i < 3; i++) {
const rgbNum: number = (255 * value + origColorObj.values[i] - 255) / value;
if (rgbNum < 0 || rgbNum > 255)
throw new Error('makeTransparent: Transparency value too low');
newColorObj.values[i] = rgbNum;
}
return recomposeColor(newColorObj);
};