使用CSS切换不同背景的字体颜色

曾经获得其中的一个,“我可以使用CSS做到这一点!” 看着某人展示自己JavaScript肌肉的片刻? 这正是我在CSSconf EU 2018上观看Dag-Inge Aas和Ida Aalen演讲时的感受 。

他们设在挪威, WCAG的可访问性不仅是一种良好的做法,而且实际上是法律所要求的(去,挪威!)。 在开发允许用户选择其主要产品的颜色主​​题的功能时,他们面临一个挑战:根据容器的选定背景颜色自动调整字体颜色。 如果背景较暗,则最好使用白色文本以使其符合WCAG对比度 。 但是,如果选择浅背景色会怎样呢? 文本难以辨认并且无法访问。

他们采用了一种优雅的方法,并使用“ color” npm软件包解决了该问题,添加了有条件的边框并自动生成第二色。

但这是一个JavaScript解决方案。 这是我的纯CSS替代方法。

挑战

这是我要完成的标准:

  • 根据背景颜色将字体color更改为黑色或白色
  • 仅当背景真的很浅时 ,才对边框应用相同的逻辑,使用较深的背景基色变化来提高按钮的可见性
  • 自动生成60°色相旋转的辅助颜色
使用CSS切换不同背景的字体颜色_第1张图片 使用CSS切换不同背景的字体颜色_第2张图片

使用HSL颜色和CSS变量

为此,我想到的最简单的方法就是运行HSL颜色。 将背景声明设置为HSL,其中每个参数都是CSS定制属性,这允许使用一种非常简单的方法来确定亮度并将其用作条件语句的基础。

:root {
  --hue: 220;
  --sat: 100;
  --light: 81;
}

.btn {
  background: hsl(var(--hue), calc(var(--sat) * 1%), calc(var(--light) * 1%));
}

这应该允许我们通过更改变量并运行if / else语句更改前景色来将背景交换为运行时所需的任何颜色。

除了……我们在CSS上没有if / else语句…… 还是我们?

引入CSS条件语句

自从引入CSS变量以来,我们还附带了条件语句。 或类似的。

该技巧基于以下事实: 某些CSS参数设置为最小值和最大值 。 例如,认为不透明。 有效范围是0到1,因此我们通常将其保留在那里。 但是我们也可以声明不透明度为2、3或1000,并且将不透明度设置为1,并以此进行解释。 以相似的方式,我们甚至可以声明一个负的不透明度值,并将其上限设置为0。

.something {
  opacity: -2; /* resolves to 0, transparent */
  opacity: -1; /* resolves to 0, transparent */
  opacity: 2; /*resolves to 1, fully opaque */
  opacity: 100; /* resolves to 1, fully opaque */
}

将技巧应用于我们的字体颜色声明

HSL颜色声明的明度参数的行为类似,将任何负值的上限设置为0(无论色相和饱和度是什么,都会导致黑色),而任何高于100%的值都上限为100%(始终为白色) )。

因此,我们可以将颜色声明为HSL,从亮度参数中减去所需的阈值,然后乘以100%以强制其超出限制之一(小于零或高于100%)。 由于我们需要将负结果转换为白色,将正结果转换为黑色,因此我们还必须将其乘以-1并将其取反。

:root {
  --light: 80;
  /* the threshold at which colors are considered "light." Range: integers from 0 to 100,
recommended 50 - 70 */
  --threshold: 60;
}

.btn {
  /* Any lightness value below the threshold will result in white, any above will result in black */
  --switch: calc((var(--light) - var(--threshold)) * -100%);
  color: hsl(0, 0%, var(--switch));
}

让我们回顾一下这段代码:从80的亮度开始,并考虑60的阈值,相减得出20,再乘以-100%,得出-2000%上限为0%。 我们的背景比阈值浅,因此我们认为它较浅并应用黑色文本。

如果我们将--light变量设置为20,则减法将导致-40,乘以-100%将变为4000%,上限为100%。 我们的浅色变量低于阈值,因此我们将其视为“深色”背景,并应用白色文本以保持较高的对比度。

产生条件边界

如果元素的背景太亮,则很容易在白色背景下丢失。 我们可能有一个按钮,甚至没有注意到它。 为了在真正的浅色上提供更好的UI,我们可以基于完全相同的背景色(只是更深)设置边框。

使用CSS切换不同背景的字体颜色_第3张图片 使用CSS切换不同背景的字体颜色_第4张图片 具有基于该背景色的深色边框的浅色背景。

为此,我们可以使用相同的技术,但将其应用于HSLA声明的alpha通道。 这样,我们可以根据需要调整颜色,然后使颜色完全透明或完全不透明。

:root {
  /* (...) */
  --light: 85;
  --border-threshold: 80;
}

.btn {
  /* sets the border-color as a 30% darker shade of the same color*/
  --border-light: calc(var(--light) * 0.7%);
  --border-alpha: calc((var(--light) - var(--border-threshold)) * 10);
  
  border: .1em solid hsla(var(--hue), calc(var(--sat) * 1%), var(--border-light), var(--border-alpha));
}

假设色相为0且饱和度为100%,则上面的代码将在背景亮度高于80时以原始亮度的70%提供完全不透明的纯红色边框,或者提供完全透明的边框(因此,在全部)如果天黑了。

设置第二种60°色相旋转的颜色

可能是最简单的挑战。 有两种可能的方法:

  1. 过滤器:hue-rotate(60):这是第一个想到的方法,但这不是最佳解决方案,因为它会影响子元素的颜色。 如有必要,可以反向旋转反向。
  2. HSL色相+ 60:另一种选择是获取我们的色相变量并将其添加60。 由于hue参数在360时没有这种限制行为,而是可以环绕(就像任何CSS 类型一样),因此它应该可以正常工作。 认为400deg=40deg480deg=120deg

考虑到这一点,我们可以为第二色元素添加一个修饰符类,该修饰符类将色相值增加60。 由于自修改变量在CSS中不可用(即,没有--hue: calc(var(--hue) + 60)这样的东西),我们可以为我们的基本样式和在背景和边框声明中使用它。

.btn {
  /* (...) */
  --h: var(--hue);
  background: hsl(var(--h), calc(var(--sat) * 1%), calc(var(--light) * 1%));
  border:.1em solid hsla(var(--h), calc(var(--sat) * 1%), var(--border-light), var(--border-alpha));
}

然后在修饰符中重新声明其值:

.btn--secondary {
  --h: calc(var(--hue) + 60);
}

这种方法的最好之处在于,由于CSS自定义属性的作用域,它会自动将所有计算结果调整为新的色调并将其应用于属性。

我们到了。 综上所述, 这是我针对所有三个挑战的纯CSS解决方案 。 这应该像一种魅力,并且可以避免我们包含外部JavaScript库。

请参见Pen CSS自动切换字体颜色,具体取决于元素背景…。 FAIL由法昆多考拉蒂尼( @facundocorradini )上CodePen 。

除非不是。 有些色调得到真正的问题(特别是黄色和青色),因为它们显示方式亮度比其他人(如红色和蓝色),尽管具有相同的亮度值。 结果,尽管有些颜色非常亮,但仍将某些颜色视为深色并给出白色文本。

CSS的名字到底是怎么回事?

引入感知的亮度

我敢肯定,你们中的很多人可能已经注意到了这一点,但是对于我们其他人来说,我们发现的亮度与HSL的亮度并不相同 。 幸运的是,我们有一些方法可以权衡色调的亮度并调整我们的代码,使其对色调也能做出响应。

要做到这一点,我们需要通过给三种系数分别对应于人眼感知其亮度的系数来考虑三种原色的感知亮度。 这通常称为亮度

有几种方法可以实现此目的。 在某些情况下,有些比其他更好,但没有哪一种是100%完美的。 因此,我选择了两个最受欢迎的,它们足够好

  • sRGB亮度(ITU Rec。709) : L =(红色* 0.2126 +绿色* 0.7152 +蓝色* 0.0722)/ 255
  • W3C方法(工作草案) : L =(红色* 0.299 +绿色* 0.587 +蓝色* 0.114)/ 255

实施亮度校正的计算

采用亮度校正方法的第一个明显含义是,由于CSS没有本机方法来访问HSL声明的RGB值,因此我们不能使用HSL。

因此,我们需要切换到背景的RBG声明,从我们选择的任何方法中计算亮度,并将其用于我们的前景颜色声明中,该颜色可以(并且将仍然是HSL)。

:root {
  /* theme color variables to use in RGB declarations */
  --red: 200;
  --green: 60;
  --blue: 255;
  /* the threshold at which colors are considered "light". 
  Range: decimals from 0 to 1, recommended 0.5 - 0.6 */
  --threshold: 0.5;
  /* the threshold at which a darker border will be applied.
  Range: decimals from 0 to 1, recommended 0.8+ */
  --border-threshold: 0.8;
}

.btn {
  /* sets the background for the base class */
  background: rgb(var(--red), var(--green), var(--blue));

  /* calculates perceived lightness using the sRGB Luma method 
  Luma = (red * 0.2126 + green * 0.7152 + blue * 0.0722) / 255 */
  --r: calc(var(--red) * 0.2126);
  --g: calc(var(--green) * 0.7152);
  --b: calc(var(--blue) * 0.0722);
  --sum: calc(var(--r) + var(--g) + var(--b));
  --perceived-lightness: calc(var(--sum) / 255);
  
  /* shows either white or black color depending on perceived darkness */
  color: hsl(0, 0%, calc((var(--perceived-lightness) - var(--threshold)) * -10000000%)); 
}

对于条件边框,我们需要将声明转换为RGBA,然后再次使用alpha通道使其完全透明或完全不透明。 与以前几乎相同,只是运行RGBA而不是HSLA。 通过从每个通道中减去50获得较暗的阴影。

如果在速记边框声明的RGBA参数中使用变量,iOS上的WebKit上确实存在一个奇怪的错误,它将显示黑色边框而不是适当的颜色。 解决方案是长期宣布边界。
感谢Joel指出错误!

.btn {
  /* (...) */
  /* applies a darker border if the lightness is higher than the border threshold */ 
  --border-alpha: calc((var(--perceived-lightness) - var(--border-threshold)) * 100);

  border-width: .2em;
  border-style: solid;
  border-color: rgba(calc(var(--red) - 50), calc(var(--green) - 50), calc(var(--blue) - 50), var(--border-alpha));  
}

由于我们丢失了最初的HSL背景声明,因此需要通过色相旋转来获得我们的次要主题颜色:

.btn--secondary {
  filter: hue-rotate(60deg);
}

这不是世界上最好的事情。 除了将色相旋转应用于如前所述的潜在子元素外,这还意味着切换到黑/白和次要元素上的边框可见性将取决于主要元素的色相,而不是其自身。 但据我所知,JavaScript实现存在相同的问题,因此我将其称为足够接近

到此为止,我们已经拥有了。

见笔取决于元件背景CSS自动WCAG对比度字体颜色由法昆科拉迪尼( @facundocorradini )上CodePen 。

一个纯CSS解决方案,可以达到与原始JavaScript方法相同的效果,但是可以大大减少占用空间。

浏览器支持

IE由于使用CSS变量而被排除在外。 Edge没有我们一直使用的上限行为。 它会看到该声明,将其视作废话,并将其完全丢弃,就像它会破坏或未知的规则一样。 其他所有主要浏览器均应正常工作。

翻译自: https://css-tricks.com/switch-font-color-for-different-backgrounds-with-css/

你可能感兴趣的:(java,css,python,swift,css3)