根据目标对比度缩放颜色

时间:2019-01-17 18:11:12

标签: css colors sass wcag

我正在尝试创建一个Sass函数,该函数接收前景色和背景色并计算对比度。从那里开始(以及我坚持的部分)是,如果它满足目标对比度,它将仅返回前景色,但如果不满足目标对比度,则它将使前景颜色变亮或变暗以满足目标对比度。

例如,如果提供的背景为#000,而提供的前景为#444(对比度为2.15),则此函数会将前景照亮为#757575,并返回那种颜色。

除了需要反转对比度计算的部分之外,我已经完成了所有工作。我最初的想法是以接近目标的百分比接近它,然后将其变浅/变暗(取决于最初的颜色是较暗的)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.
}

请注意注释行“除了它之外还有更多……” –那是我需要反转对比度公式的地方,但是我很想如果有一个更简单的公式可以使用,因为我已经知道目标对比度是。

几天以来,我一直在想这个问题,我很困惑。我希望避免使用猜测和检查的方法,方法是遍历1%的变暗/变暗的颜色并分别测试它们的对比度,这是可行的,但是我敢肯定,有更好的解决方案。

这是我的初始功能(对比度和亮度)的参考,非常有用:https://medium.com/dev-channel/using-sass-to-automatically-pick-text-colors-4ba7645d2796

注意:我没有使用Compass或任何其他Sass库。

编辑:以下是简化的提琴供参考:https://www.sassmeister.com/gist/445836123feb42885a0cf7f4709261ff

1 个答案:

答案 0 :(得分:2)

因此,给定#000000和#444444,您可以计算对比度(在这种情况下为2.15)。数学很简单,尽管有点毛。 (请参阅“ relative luminance”定义。)

现在您想倒退吗?如果您有#000000,并且要以#444444开头的比例为4.5,则颜色应该是什么?就是

  

我需要反转对比公式

是什么意思?

这有点复杂,因为您要求解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.56少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%

graph of contrast ratios

如您所见,在第三个数据点插入的线然后会聚在一起。我确定里面有一个公式,这样您就可以获取对比度百分比,对它执行一些(可能是对数的)函数,并获取更改颜色所需的百分比。

这将是一个令人着迷的数学问题,我目前没有时间玩。

更新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之前,先将其除以以将0到1之间的值归一化。因此,如果将条件值0.03928和相乘乘以255,则得出10.0164。由于RGB值必须为整数,这意味着RGB分量10(0x0A)或更小将通过“ if”,而11(0x0B)或更大的任何东西将通过“ else”。因此,在测试用例值中,我希望其中一个颜色部分为10(0x0A)(#EE 0A DD)。

#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.01358818528482655655593894747450025(0.0136)

原始的第二个亮度值为0.0868525191191131797135799815832377(0.0868),因此要获得0.01358818528482655655593894747450025(0.0136),我们需要将原始值乘以0.156451251196519651910313960717062698(0.0136 / 0.0868 = 0.156)(或原始值的15.6%)

如果我们对R,G和B的每个相对亮度值分别应用15.6%,然后反向执行上面的条件语句,则可以获得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。如果您愿意,我也可以发布该数学。