根据目标对比度缩放颜色
Scaling a color based on a target contrast ratio
我正在尝试创建一个 Sass 函数来接收前景色和背景色并计算对比度。从那里(以及我坚持的部分)是,如果满足目标对比度,它只会 return 前景颜色,但如果不满足目标对比度,它将使前景颜色变亮或变暗以满足目标对比度。
例如,如果提供的背景为 #000
,提供的前景为 #444
(对比度为 2.15),此函数会将前景调亮为 #757575
和 return 那种颜色。
除了我需要反转对比度计算的部分,我已经完成了所有工作。我最初的想法是用它偏离目标的百分比来接近它,然后简单地 lighten/darken(取决于哪种颜色最初更暗)乘以 100 减去百分比差异。事后看来,这种方法有点幼稚,恐怕会涉及到一些更高级的数学。
这是我目前创建的 (and here is a simplified fiddle):
@function wcag-color($bg, $fg, $size: 16px, $level: "aa"){
@if ( $level == "aa" ){
$wcag_contrast_ratio: 4.5; //For text smaller than 18px
@if ( $size >= 19 ){
$wcag_contrast_ratio: 3; //For text larger than 19px
}
}
@if ( $level == "aaa" ){
$wcag_contrast_ratio: 7; //For text smaller than 18px
@if ( $size >= 19 ){
$wcag_contrast_ratio: 4.5; //For text larger than 19px
}
}
$actual_contrast_ratio: contrast($bg, $fg); //This function returns the contrast between the two colors.
@if ( $actual_contrast_ratio > $wcag_contrast_ratio ){
@return $fg; //Foreground color is acceptable
}
//Scale the lightness of the foreground to meet requested WCAG contrast ratio
$difference: 100 - $actual_contrast_ratio / $wcag_contrast_ratio * 100; //There is more to it than this...
//Edit: here are a few new lines to ponder. This assumes BG is darker than FG (would need to add a condition to compare luminance of each).
$acceptable_luminance: luminance($bg)*$wcag_contrast_ratio; //What the luminance of the FG must be to comply
$difference: ($acceptable_luminance - luminance($fg)); //How far away the FG luminance actually is (not sure if this helps anything...)
@return scale-color($fg, $lightness: $difference); //Unfortunately luminance is not the same as lightness.
}
请注意注释行 "There is more to it than this..." – 这是我需要反转对比度公式的地方,但我希望能使用更简单的公式,因为我已经知道目标对比度是多少。
这几天我一直在想这个问题,但我很困惑。我更愿意通过遍历 1% lightened/darkened 颜色并单独测试每种颜色的对比度来避免猜测和检查方法——这可行,但我确信有更优化的解决方案。
这是我初始功能(对比度和亮度)的参考,非常有帮助:https://medium.com/dev-channel/using-sass-to-automatically-pick-text-colors-4ba7645d2796
注意:我没有使用 Compass 或任何其他 Sass 库。
编辑:这是一个简化的 fiddle 以供参考:https://www.sassmeister.com/gist/445836123feb42885a0cf7f4709261ff
因此给定#000000 和#444444,您可以计算对比度(在本例中为 2.15)。数学非常简单,尽管有点毛茸茸。 (参见“relative luminance”定义。)
现在你想倒退?如果你有 #000000 并且想要 4.5 的比率,从 #444444 开始,颜色应该是什么?那是什么
I need to reverse my contrast formula
是什么意思?
这有点复杂,因为您要求解 3 个变量,即红色、绿色和蓝色分量,而且亮度公式不会平等对待红色、绿色和蓝色。它使用 21.25% 的红色、71.5% 的绿色和 7.25% 的蓝色。
此外,亮度公式不是一个简单的线性公式,因此您不能只减去亮度的百分比,然后将颜色值增加相同的百分比。
例如,在您的情况下,比率为 2.15,但您需要它为 4.5。 2.15 比期望值 4.5 差 108%。
但是,如果您查看原始 RGB 值 #444444 并计算出它需要为 #757575(为了获得 4.5 的比率),那么如果您将这些 RGB 值视为简单数字(并转换为十进制),那么#444444 (4473924) 比#757575 (7697781) 少 72%。
所以你有一个断开连接,你的比率短了 108%,但你的 RGB 值短了 72%。因此你不能做一个简单的线性方程。
(数字不是很准确,因为 #757575 给你的比率是 4.56,而不是精确的 4.5 比率。如果你使用 #747474,你会得到 4.49 的比率,这只是一点点对于 WCAG 合规性来说太小了,但比 4.56 更接近 4.5。但是,#444444 比 #747474 少 71%,所以它仍然与 2.15 不一样,比 4.5 少 108%,所以基本概念仍然适用。)
为了好玩,我查看了 0x11111 到 0x666666 的值,以 0x111111 递增,并计算了对比度。图表上没有足够的点,所以我在 0x111111 和 0x222222 之间的中间添加了一种颜色,然后在 0x222222 和 0x333333 之间的中间添加了颜色,等等
RGB contrast % from 4.5 % from 0x747474
111111 1.11 305.41% 582.35%
191919 1.19 278.15% 364.00%
222222 1.32 240.91% 241.18%
2a2a2a 1.46 208.22% 176.19%
333333 1.66 171.08% 127.45%
3b3b3b 1.87 140.64% 96.61%
444444 2.16 108.33% 70.59%
4c4c4c 2.45 83.67% 52.63%
555555 2.82 59.57% 36.47%
5d5d5d 3.19 41.07% 24.73%
666666 3.66 22.95% 13.73%
6e6e6e 4.12 9.22% 5.45%
如您所见,线条在第 3 个数据点处相交,然后相互汇聚。我确定其中有一个公式,因此您可以获取对比度百分比,对其执行一些(可能是对数)函数并获得更改颜色所需的百分比。
这将是一个令人着迷的数学问题,但我目前没有时间去玩。
2019 年 1 月 18 日更新
我让它向后工作,但它不处理边缘情况,例如当使深色变暗但您已经达到最大值(或使浅色变浅但您达到最大值)时。但也许你可以玩一下。
测试用例
#ee0add
浅色(洋红色)
#445566
为深色(深灰色)
- 对比度2.09
在计算颜色的“relative luminance”时,有一个条件语句。
if X <= 0.03928 then
X = X/12.92
else
X = ((X+0.055)/1.055) ^ 2.4
在该条件下使用 X 之前,它被 除 除以 255 以标准化 0 和 1 之间的值。因此,如果您采用条件值 0.03928 和 乘乘以255,得到10.0164。由于 RGB 值必须是整数,这意味着 10 (0x0A) 或更小的 RGB 分量将通过 "if",任何 11 (0x0B) 或更大的分量将通过 "else"。因此,在我的测试用例值中,我希望颜色部分之一为 10 (0x0A) (#EE0ADD).
#ee0add 的相对亮度为 0.23614683378171950172526363525113 (0.236)
#445566 的相对亮度为 0.0868525191131797135799815832377 (0.0868)
“contrast ratio”是
(0.236 + .05) / (0.0868 + .05) = 2.09
(你可以在https://webaim.org/resources/contrastchecker/?fcolor=EE0ADD&bcolor=445566上验证这个比例)
如果我们想要4.5的比率,并且我们希望#ee0add不变,那么我们必须调整#445566。这意味着您需要解决:
4.5 = (0.236 + .05) / (XX + .05)
所以第二个亮度值(XX)需要为0.01358818528482655593894747450025(0.0136)
The original second luminance value was 0.0868525191131797135799815832377 (0.0868), so to get 0.01358818528482655593894747450025 (0.0136), we need to multiply the original by 0.15645125119651910313960717062698 (0.0136 / 0.0868 = 0.156) (or 15.6% of the original value)
如果我们将 15.6% 应用到 R、G 和 B 相对亮度值中的每一个,然后通过上面的条件语句向后计算,就可以得到 RGB 值。
#445566 的原始亮度
r = 0x44 = 68
g = 0x55 = 85
b = 0x66 = 102
r1 = 68 / 255 = 0.26666666666666666666666666666667
g1 = 85 / 255 = 0.33333333333333333333333333333333
b1 = 102 / 255 = 0.4
r2 = ((.267 + .055) / 1.055)^^2.4 = 0.05780543019106721120703816752337
g2 = ((.333 + .055) / 1.055)^^2.4 = 0.09084171118340767766490119106965
b2 = ((.400 + .055) / 1.055)^^2.4 = 0.13286832155381791428570549818868
l = 0.2126 * r2 + 0.7152 * g2 + 0.0722 * b2
= 0.0868525191131797135799815832377
向后计算,取 r2、g2 和 b2 值的 15.6%
r2 = 0.05780543019106721120703816752337 * 15.6% = 0.00904373187934550551617004082875
g2 = 0.09084171118340767766490119106965 * 15.6% = 0.01421229937547695322310904970549
b2 = 0.13286832155381791428570549818868 * 15.6% = 0.02078741515147623990363062978804
现在撤消 ^^2.4
和其他东西的混乱
- 要撤消
X^^2.4
您必须执行相反的操作,X^^(1/2.4)
或 X^^(0.4167)
- 然后乘以 1.055
- 然后减去 0.055
- 然后乘以255
pow( 0.00904373187934550551617004082875, 1/2.4) = 0.14075965680504652191078668676178
pow( 0.01421229937547695322310904970549, 1/2.4) = 0.16993264267137740728089791717873
pow( 0.02078741515147623990363062978804, 1/2.4) = 0.19910562853770829265100914759565
乘以 1.055
0.14075965680504652191078668676178 * 1.055 = 0.14850143792932408061587995453368
0.16993264267137740728089791717873 * 1.055 = 0.17927893801830316468134730262356
0.19910562853770829265100914759565 * 1.055 = 0.21005643810728224874681465071341
减去 0.055
0.14850143792932408061587995453368 - 0.055 = 0.09350143792932408061587995453368
0.17927893801830316468134730262356 - 0.055 = 0.12427893801830316468134730262356
0.21005643810728224874681465071341 - 0.055 = 0.15505643810728224874681465071341
乘以 255
0.09350143792932408061587995453368 * 255 = 23.842866671977640557049388406088 = 24 = 0x18
0.12427893801830316468134730262356 * 255 = 31.691129194667306993743562169008 = 32 = 0x20
0.15505643810728224874681465071341 * 255 = 39.53939171735697343043773593192 = 40 = 0x28
所以较深的颜色是#182028。可能存在一些舍入误差,但如果您检查原始前景颜色 #ee0add 和新颜色 #182028,您会得到 4.48 的对比度。略低于 4.5,但正如我所说,可能存在一些舍入误差。
https://webaim.org/resources/contrastchecker/?fcolor=EE0ADD&bcolor=182028
我尝试用#ee0add 做同样的事情,保持#445566 相同,但是当向后移动并到达乘以 255 的最后一步时,我得到大于 255 的数字,这不是有效的 RGB 组件(它们最多只能达到 0xFF)。如果我将数字停在 255,然后取差值并将其添加到最小颜色值,我得到了不错的颜色,但比率为 5.04,超过 4.5。如果你愿意,我也可以 post 那门数学课。
我正在尝试创建一个 Sass 函数来接收前景色和背景色并计算对比度。从那里(以及我坚持的部分)是,如果满足目标对比度,它只会 return 前景颜色,但如果不满足目标对比度,它将使前景颜色变亮或变暗以满足目标对比度。
例如,如果提供的背景为 #000
,提供的前景为 #444
(对比度为 2.15),此函数会将前景调亮为 #757575
和 return 那种颜色。
除了我需要反转对比度计算的部分,我已经完成了所有工作。我最初的想法是用它偏离目标的百分比来接近它,然后简单地 lighten/darken(取决于哪种颜色最初更暗)乘以 100 减去百分比差异。事后看来,这种方法有点幼稚,恐怕会涉及到一些更高级的数学。
这是我目前创建的 (and here is a simplified fiddle):
@function wcag-color($bg, $fg, $size: 16px, $level: "aa"){
@if ( $level == "aa" ){
$wcag_contrast_ratio: 4.5; //For text smaller than 18px
@if ( $size >= 19 ){
$wcag_contrast_ratio: 3; //For text larger than 19px
}
}
@if ( $level == "aaa" ){
$wcag_contrast_ratio: 7; //For text smaller than 18px
@if ( $size >= 19 ){
$wcag_contrast_ratio: 4.5; //For text larger than 19px
}
}
$actual_contrast_ratio: contrast($bg, $fg); //This function returns the contrast between the two colors.
@if ( $actual_contrast_ratio > $wcag_contrast_ratio ){
@return $fg; //Foreground color is acceptable
}
//Scale the lightness of the foreground to meet requested WCAG contrast ratio
$difference: 100 - $actual_contrast_ratio / $wcag_contrast_ratio * 100; //There is more to it than this...
//Edit: here are a few new lines to ponder. This assumes BG is darker than FG (would need to add a condition to compare luminance of each).
$acceptable_luminance: luminance($bg)*$wcag_contrast_ratio; //What the luminance of the FG must be to comply
$difference: ($acceptable_luminance - luminance($fg)); //How far away the FG luminance actually is (not sure if this helps anything...)
@return scale-color($fg, $lightness: $difference); //Unfortunately luminance is not the same as lightness.
}
请注意注释行 "There is more to it than this..." – 这是我需要反转对比度公式的地方,但我希望能使用更简单的公式,因为我已经知道目标对比度是多少。
这几天我一直在想这个问题,但我很困惑。我更愿意通过遍历 1% lightened/darkened 颜色并单独测试每种颜色的对比度来避免猜测和检查方法——这可行,但我确信有更优化的解决方案。
这是我初始功能(对比度和亮度)的参考,非常有帮助:https://medium.com/dev-channel/using-sass-to-automatically-pick-text-colors-4ba7645d2796
注意:我没有使用 Compass 或任何其他 Sass 库。
编辑:这是一个简化的 fiddle 以供参考:https://www.sassmeister.com/gist/445836123feb42885a0cf7f4709261ff
因此给定#000000 和#444444,您可以计算对比度(在本例中为 2.15)。数学非常简单,尽管有点毛茸茸。 (参见“relative luminance”定义。)
现在你想倒退?如果你有 #000000 并且想要 4.5 的比率,从 #444444 开始,颜色应该是什么?那是什么
I need to reverse my contrast formula
是什么意思?
这有点复杂,因为您要求解 3 个变量,即红色、绿色和蓝色分量,而且亮度公式不会平等对待红色、绿色和蓝色。它使用 21.25% 的红色、71.5% 的绿色和 7.25% 的蓝色。
此外,亮度公式不是一个简单的线性公式,因此您不能只减去亮度的百分比,然后将颜色值增加相同的百分比。
例如,在您的情况下,比率为 2.15,但您需要它为 4.5。 2.15 比期望值 4.5 差 108%。
但是,如果您查看原始 RGB 值 #444444 并计算出它需要为 #757575(为了获得 4.5 的比率),那么如果您将这些 RGB 值视为简单数字(并转换为十进制),那么#444444 (4473924) 比#757575 (7697781) 少 72%。
所以你有一个断开连接,你的比率短了 108%,但你的 RGB 值短了 72%。因此你不能做一个简单的线性方程。
(数字不是很准确,因为 #757575 给你的比率是 4.56,而不是精确的 4.5 比率。如果你使用 #747474,你会得到 4.49 的比率,这只是一点点对于 WCAG 合规性来说太小了,但比 4.56 更接近 4.5。但是,#444444 比 #747474 少 71%,所以它仍然与 2.15 不一样,比 4.5 少 108%,所以基本概念仍然适用。)
为了好玩,我查看了 0x11111 到 0x666666 的值,以 0x111111 递增,并计算了对比度。图表上没有足够的点,所以我在 0x111111 和 0x222222 之间的中间添加了一种颜色,然后在 0x222222 和 0x333333 之间的中间添加了颜色,等等
RGB contrast % from 4.5 % from 0x747474
111111 1.11 305.41% 582.35%
191919 1.19 278.15% 364.00%
222222 1.32 240.91% 241.18%
2a2a2a 1.46 208.22% 176.19%
333333 1.66 171.08% 127.45%
3b3b3b 1.87 140.64% 96.61%
444444 2.16 108.33% 70.59%
4c4c4c 2.45 83.67% 52.63%
555555 2.82 59.57% 36.47%
5d5d5d 3.19 41.07% 24.73%
666666 3.66 22.95% 13.73%
6e6e6e 4.12 9.22% 5.45%
如您所见,线条在第 3 个数据点处相交,然后相互汇聚。我确定其中有一个公式,因此您可以获取对比度百分比,对其执行一些(可能是对数)函数并获得更改颜色所需的百分比。
这将是一个令人着迷的数学问题,但我目前没有时间去玩。
2019 年 1 月 18 日更新
我让它向后工作,但它不处理边缘情况,例如当使深色变暗但您已经达到最大值(或使浅色变浅但您达到最大值)时。但也许你可以玩一下。
测试用例
#ee0add
浅色(洋红色)#445566
为深色(深灰色)- 对比度2.09
在计算颜色的“relative luminance”时,有一个条件语句。
if X <= 0.03928 then
X = X/12.92
else
X = ((X+0.055)/1.055) ^ 2.4
在该条件下使用 X 之前,它被 除 除以 255 以标准化 0 和 1 之间的值。因此,如果您采用条件值 0.03928 和 乘乘以255,得到10.0164。由于 RGB 值必须是整数,这意味着 10 (0x0A) 或更小的 RGB 分量将通过 "if",任何 11 (0x0B) 或更大的分量将通过 "else"。因此,在我的测试用例值中,我希望颜色部分之一为 10 (0x0A) (#EE0ADD).
#ee0add 的相对亮度为 0.23614683378171950172526363525113 (0.236)
#445566 的相对亮度为 0.0868525191131797135799815832377 (0.0868)
“contrast ratio”是 (0.236 + .05) / (0.0868 + .05) = 2.09
(你可以在https://webaim.org/resources/contrastchecker/?fcolor=EE0ADD&bcolor=445566上验证这个比例)
如果我们想要4.5的比率,并且我们希望#ee0add不变,那么我们必须调整#445566。这意味着您需要解决:
4.5 = (0.236 + .05) / (XX + .05)
所以第二个亮度值(XX)需要为0.01358818528482655593894747450025(0.0136)
The original second luminance value was 0.0868525191131797135799815832377 (0.0868), so to get 0.01358818528482655593894747450025 (0.0136), we need to multiply the original by 0.15645125119651910313960717062698 (0.0136 / 0.0868 = 0.156) (or 15.6% of the original value)
如果我们将 15.6% 应用到 R、G 和 B 相对亮度值中的每一个,然后通过上面的条件语句向后计算,就可以得到 RGB 值。
#445566 的原始亮度
r = 0x44 = 68
g = 0x55 = 85
b = 0x66 = 102
r1 = 68 / 255 = 0.26666666666666666666666666666667
g1 = 85 / 255 = 0.33333333333333333333333333333333
b1 = 102 / 255 = 0.4
r2 = ((.267 + .055) / 1.055)^^2.4 = 0.05780543019106721120703816752337
g2 = ((.333 + .055) / 1.055)^^2.4 = 0.09084171118340767766490119106965
b2 = ((.400 + .055) / 1.055)^^2.4 = 0.13286832155381791428570549818868
l = 0.2126 * r2 + 0.7152 * g2 + 0.0722 * b2
= 0.0868525191131797135799815832377
向后计算,取 r2、g2 和 b2 值的 15.6%
r2 = 0.05780543019106721120703816752337 * 15.6% = 0.00904373187934550551617004082875
g2 = 0.09084171118340767766490119106965 * 15.6% = 0.01421229937547695322310904970549
b2 = 0.13286832155381791428570549818868 * 15.6% = 0.02078741515147623990363062978804
现在撤消 ^^2.4
和其他东西的混乱
- 要撤消
X^^2.4
您必须执行相反的操作,X^^(1/2.4)
或X^^(0.4167)
- 然后乘以 1.055
- 然后减去 0.055
- 然后乘以255
pow( 0.00904373187934550551617004082875, 1/2.4) = 0.14075965680504652191078668676178
pow( 0.01421229937547695322310904970549, 1/2.4) = 0.16993264267137740728089791717873
pow( 0.02078741515147623990363062978804, 1/2.4) = 0.19910562853770829265100914759565
乘以 1.055
0.14075965680504652191078668676178 * 1.055 = 0.14850143792932408061587995453368
0.16993264267137740728089791717873 * 1.055 = 0.17927893801830316468134730262356
0.19910562853770829265100914759565 * 1.055 = 0.21005643810728224874681465071341
减去 0.055
0.14850143792932408061587995453368 - 0.055 = 0.09350143792932408061587995453368
0.17927893801830316468134730262356 - 0.055 = 0.12427893801830316468134730262356
0.21005643810728224874681465071341 - 0.055 = 0.15505643810728224874681465071341
乘以 255
0.09350143792932408061587995453368 * 255 = 23.842866671977640557049388406088 = 24 = 0x18
0.12427893801830316468134730262356 * 255 = 31.691129194667306993743562169008 = 32 = 0x20
0.15505643810728224874681465071341 * 255 = 39.53939171735697343043773593192 = 40 = 0x28
所以较深的颜色是#182028。可能存在一些舍入误差,但如果您检查原始前景颜色 #ee0add 和新颜色 #182028,您会得到 4.48 的对比度。略低于 4.5,但正如我所说,可能存在一些舍入误差。
https://webaim.org/resources/contrastchecker/?fcolor=EE0ADD&bcolor=182028
我尝试用#ee0add 做同样的事情,保持#445566 相同,但是当向后移动并到达乘以 255 的最后一步时,我得到大于 255 的数字,这不是有效的 RGB 组件(它们最多只能达到 0xFF)。如果我将数字停在 255,然后取差值并将其添加到最小颜色值,我得到了不错的颜色,但比率为 5.04,超过 4.5。如果你愿意,我也可以 post 那门数学课。