[译] CSS 变量 + calc + rgb = 自动高对比度

1,360 阅读4分钟

原文在这里

所有例子可以在文中的CODEPEN里查看


如你所知, 最近css的更新和附加功能非常得强大。 从Flex布局到Grid布局, 还有和我们这里提及的-自定义属性(又称 CSS 变量), 使得强大的动态布局还有界面, 比过去简单, 并开拓了很多梦寐以求的可能。

几天前, 我认为应该有一种方法, 使用自定义属性的颜色作为一个元素的背景色, 和前景色形成对比(用黑或者白) 并足以通过WCAG AA访问标准。

用javascript, 只需要短短几行代码就卓有成效。

var rgb = [255, 0, 0]; 

function setForegroundColor() {
    var sum = Math.round(((parseInt(rgb[0]) * 299) + (parseInt(rgb[1]) * 587) + (parseInt(rgb[2]) * 114)) / 1000); 
    return (sum > 128) ? 'black' : 'white'; 
}

一个元素的背景色选择红, 绿, 蓝的值, 乘上一些特殊的数字(分别是299, 587, 144), 再想加, 然后除以1000, 当得到的值比128大, 将会返回黑色, 否则, 我们返回白色。 还不错。

唯一的问题是, 当用css来重构时, 我们没有原生的if来判断值。 那么, 我们如何用css来实现这个效果呢?

所幸, 如html一样, css 非常宽容, 如果我们在RGB函数里传入一个大于255的值, 他会限制为255。 值一样不可以小于0。 负数一样会被限制为0, 所以, 测试值大于或者小于128, 我们用值减去128, 得到一个正数或者负整数。 然后, 如果我们乘一个很大的负数(如1000), 我们同样会得到一个可以通过RGB函数的很大的正数或者负数。 如我所说, 值会按照浏览器的要求去限制。

这是一个使用CSS变量的例子

:root {
  --red: 28; 
  --green: 150; 
  --blue: 130; 

  --accessible-color: calc(
    (
      (
        (var(--red) * 299) +
        (var(--green) * 587) +
        (var(--blue) * 114) /
        1000
      ) - 128
    ) * -1000
  ); 
}

.button {
  color:
    rgb(
      var(--accessible-color), 
      var(--accessible-color), 
      var(--accessible-color)
    ); 
  background-color:
    rgb(
      var(--red), 
      var(--green), 
      var(--blue)
    ); 
}

如果我数学没错~作者卖萌~我们得到了16, 758, 远远大于255, 输入这个值到rgb函数里, 浏览器会设置文本颜色为白色。

在这点上, chrome和firefox上都正常工作, 但safari 有些古怪, 给了一个不同的结果, 开始, 我认为, 这个可能是因为safari 没有限制大值, 但经过一些测试, 我发现safari因为一些原因不喜欢我计算里的除法。

仔细看看 calc 函数, 我注意到我可以去掉除以1000通过提升值从128到128, 000. 像这样:

:root {
  --red: 28; 
  --green: 150; 
  --blue: 130; 

  --accessible-color: calc(
    (
      (
        (var(--red) * 299) +
        (var(--green) * 587) +
        (var(--blue) * 114)
      ) - 128000 /* HIGHLIGHT */
    ) * -1000
  ); 
}

.button {
  color:
    rgb(
      var(--accessible-color), 
      var(--accessible-color), 
      var(--accessible-color)
    ); 
  background-color:
    rgb(
      var(--red), 
      var(--green), 
      var(--blue)
    ); 
}

滑动几个范围的滑块, 以调整颜色值, 现在你可以看到, 一个能够基于它的背景色切换文本颜色的动态元素, 并可以通过 WCAG AA 的标准。

CODEPEN

把这个概念放到实际应用中

下面是一个 用来展示如何配置用户主题的 PEN 。 我已经复制并移动 --accessible-color 到需要它的特定的css规则, 以确保背景色基于前景色可见, 我 把 --accessible-color 变量在几个地方乘以-1 。 颜色能够通过控制右下侧的控制器改变, 点击齿轮来配置他们。

CODEPEN

还有其他的方式来做

一会儿后, Facundo Corradini 在这片文章里解释如何做一些非常相似的事情, 他用一个有轻微差异的算法与hsl函数组合起来。 他还会深入一些问题的细节关于提出这个概念的过程。

一些色调变得非常不确定(通常是黄色或者蓝绿色), 他们显示得比其他颜色(如红色和蓝色)要亮, 尽管他们有相同的亮度值。 因此, 一些颜色作为深色处理, 并让白色的文本变得更加醒目

css的名字是什么?

他提到 Edge 没有限制大数字, 并且, 在我的测试中, 我注意到有时他们正常, 有时不正常。 如果任何人知道为什么, 可以在评论里自由分享。

此外, Ana Tudor 解释了 如何使用 filter + mix-blend-mode 可以 帮助文本与更复杂的背景对比。 我的意思是相当地复杂, 她甚至证明了文字颜色如何随着背景色改变而改变 - 令人惊叹!

同时, Robin Rendle 解释了如何使用 mix-blend-mode 和 伪元素一起自动基于背景色反转文字颜色。

因此, 将此视为另一种投入混合的方式。 自定义特性 开创了一些可能性, 并允许我们使用不同的方式, 来解决相同的问题。


补充兼容性:

css变量兼容性