css 反色_使用CSS和JavaScript检测反色

css 反色

There was something that bugged me after reading David's article on the invert filter last week. It was this sentence:

在上周阅读了David关于invert滤波器的文章后,有些事情困扰了我。 就是这句话:

The values reported back by window.getComputedStyle(el) will be the original CSS values, however, so there's no way of getting the true inverted values of given properties.

但是,由window.getComputedStyle(el)返回的值将是原始CSS值,因此无法获取给定属性的真实倒置值。

But if I can read the original value for background-color or color and I can read the value for the filter, then I can compute the inverted value, which means there is a way after all.

但是,如果我可以读取background-colorcolor的原始值并且可以读取filter的值,那么我可以计算取反的值,这意味着总有办法。

Well, let's see how we do that.

好吧,让我们看看我们如何做到这一点。

完全反转以获得坚实的背景 (Full inversion for a solid background)

First of all we need to understand how the invert filter works and we'll start with the particular case of full inversion - invert(100%). For an arbitrary original value rgb(red, green, blue), where red, green and blue can take values between 0 and 255 applying an invert(100%) filter is going to produce rgb(255 - red, 255 - green, 255 - blue).

首先,我们需要了解invert滤波器的工作原理,并从完全反转的特殊情况invert(100%) 。 对于任意原始值rgb(red, green, blue) ,其中redgreenblue可以采用0255之间的值,而应用invert(100%)滤镜将产生rgb(255 - red, 255 - green, 255 - blue)

This is pretty straightforward and easy to code, especially since the values obtained via window.getComputedStyle(el) are rgb() or rgba() values in all browsers supporting CSS filters, depending on whether the initial value has an alpha channel that is less than 1 or not.

这非常简单明了,易于编码,特别是因为在所有支持CSS过滤器的浏览器中,通过window.getComputedStyle(el)获得的值是rgb()rgba()值,具体取决于初始值的alpha通道是否小于大于或等于1

Note: CSS filters with filter function values (not just url() values) are supported by Chrome 18+, Safari 6.1+, Opera 15+ and Firefox 34+. Chrome, Safari and Opera need the -webkit- prefix, while Firefox doesn't need and never needed a prefix, but needs layout.css.filters.enabled set to true in about:config. IE does not support CSS filters yet, though they are listed as "Under Consideration". If implemented, it's probably not going to need a prefix either. So don't use -moz- or -ms- prefixes for filters!

注意:Chrome 18 +,Safari 6.1 +,Opera 15+和Firefox 34+支持具有过滤器功能值(而不仅仅是url()值)CSS过滤器。 Chrome,Safari和Opera需要-webkit-前缀,而Firefox既不需要也不需要前缀,但需要在about:config中将layout.css.filters.enabled设置为true IE尚不支持CSS过滤器,尽管它们被列为“考虑中” 如果实施,则也可能不需要前缀。 因此,请勿将-moz--ms-前缀用于过滤器!

So if we have an element for which we set a background-color and then we apply an invert(100%) filter on it:

因此,如果我们有一个为其设置background-color的元素,然后对其应用invert(100%)滤镜:

.box {
    background-color: darkorange;
    -webkit-filter: invert(100%);
    filter: invert(100%);
}


Then we can read its styles and compute the inverted value from the original:

然后,我们可以读取其样式并从原始值计算取反值:

var box = document.querySelector('.box'), 
    styles = window.getComputedStyle(box), 
    original = styles.backgroundColor, 
    channels = original.match(/\d+/g), 
    inverted_channels = channels.map(function(ch) {
        return 255 - ch;
    }), 
    inverted = 'rgb(' + inverted_channels.join(', ') + ')';


It can be seen working in this pen, where the first box has the original background-color and no filter applied, the second one the same background-color and an invert(100%) filter, while the third one has a background that's the inverted value (as computed by the JavaScript code above) of the original background-color, assuming an invert(100%) filter.

可以看出这支笔的工作原理 ,其中第一个框具有原始background-color且未应用滤镜,第二个框具有相同的background-color并具有invert(100%)滤镜,而第三个框具有background-color ,即假设使用invert(100%)过滤器,则原始background-color反转值(由上面JavaScript代码计算invert(100%)

See the Pen Getting the inverted value for `background-color` via JS #1 by Ana Tudor (@thebabydino) on CodePen.

见笔经由JS#1开始为`背景color`反转值由安娜铎( @thebabydino )上CodePen

那半透明的背景呢? (What about semitransparent backgrounds?)

But this is only for rgb() and if our background-color isn't fully opaque, then the value we read with JavaScript is going to be an rgba() value.

但这仅适用于rgb() ,如果我们的background-color不是完全不透明,那么我们用JavaScript读取的值将是rgba()值。

For example, the backgroundColor style value read via JavaScript is going to be "rgb(255, 140, 0)" if, in the CSS, we set background-color to any of the following:

例如,如果在CSS中将background-color设置为以下任意一项,则通过JavaScript读取的backgroundColor样式值将为"rgb(255, 140, 0)"

  • darkorange

    darkorange

  • #ff8c00

    #ff8c00

  • rgb(255, 140, 0)

    rgb(255, 140, 0)

  • rgb(100%, 54.9%, 0%)

    rgb(100%, 54.9%, 0%)

  • rgba(255, 140, 0, 1)

    rgba(255, 140, 0, 1)

  • rgba(100%, 54.9%, 0%, 1)

    rgba(100%, 54.9%, 0%, 1)

  • hsl(33, 100%, 50%)

    hsl(33, 100%, 50%)

  • hsla(33, 100%, 50%, 1)

    hsla(33, 100%, 50%, 1)

But it's going to be "rgba(255, 140, 0, .65)" if we set background-color to one of the following:

但是,如果我们将background-color设置为以下之一,则它将是"rgba(255, 140, 0, .65)"

  • rgba(255, 140, 0, .65)

    rgba(255, 140, 0, .65)

  • rgba(100%, 54.9%, 0%, .65)

    rgba(100%, 54.9%, 0%, .65)

  • hsla(33, 100%, 50%, .65)

    hsla(33, 100%, 50%, .65)

Since the invert filter leaves the alpha channel unchanged and only modifies the red, green and blue channels, this means that our JavaScript code becomes:

由于invert过滤器使alpha通道保持不变,并且仅修改了redgreenblue通道,因此这意味着我们JavaScript代码变为:

var box = document.querySelector('.box'), 
    styles = window.getComputedStyle(box), 
    original = styles.backgroundColor.split('('), 
    channels = original[1].match(/(0\.\d+)|\d+/g), 
    alpha = (channels.length > 3)?(1*channels.splice(3, 1)[0]):1, 
    inverted_channels = channels.map(function(ch) { return 255 - ch; }), 
    inverted;

if(alpha !== 1) {
  inverted_channels.splice(3, 0, alpha);
}

inverted = original[0] + '(' + inverted_channels.join(', ') + ')';


It can be seen working in this pen.

可以看出这支笔在工作。

See the Pen Getting the inverted value for `background-color` via JS #2 by Ana Tudor (@thebabydino) on CodePen.

见笔经由JS#2获取用于`背景color`反转值由安娜铎( @thebabydino )上CodePen

Note that this assumes that the value of the alpha channel of the background we set in the CSS is always greater than 0. If the value of the alpha channel is 0, then the value returned by styles.backgroundColor is going to be "transparent" and inversion really has no point anymore.

请注意,这假设我们在CSS中设置的背景的alpha通道的值始终大于0 。 如果alpha通道的值为0 ,则styles.backgroundColor返回的值将是"transparent"并且反转实际上不再有用。

Alright, but this was all for a filter value of invert(100%). What happens if we want to have a value that's less than 100%?

好的,但这全都是针对invert(100%)filter值的。 如果我们想要一个小于100%的值会怎样?

一般情况 (General case)

Well, for a value less than 100%, let's say 65%, the [0, 255] range for each of the red, green and blue channels is first squished around its central value. This means that the upper limit of the range goes from 255 to 65% of 255 and its lower limit goes from 0 to 100% - 65% = 35% of 255. Then we compute the squished equivalent of our original background-color which simply means taking each channel value, scaling it to the new squished range and then adding the lower limit. And finally, the last step is getting the symmetrical value with respect to the central one for each of the red, green and blue channels of the squished equivalent of our original background-color.

好吧,对于小于100%的值(假设为65% ,首先将redgreenblue通道的[0, 255]范围压缩到其中心值附近。 这意味着,该范围的上限变为从25565%255和它的下限变为从0100% - 65% = 35%255 。 然后,我们计算原始background-color压缩等效值,这仅意味着获取每个通道值,将其缩放到新的压缩范围,然后添加下限。 最后,最后一步是获得与原始background-color类似的redgreenblue通道中每个redgreenblue通道的中心值的对称值。

The following demo visually shows all this happening, taking the green channel as an example.

以下演示green通道为例,直观地显示了所有发生的情况。

See the Pen Squishing a channel range by Ana Tudor (@thebabydino) on CodePen.

见笔压扁的信道范围由安娜铎( @thebabydino )上CodePen

The original range goes from 0 to 255 and the original value for the green channel is taken to be 165. Any value less than 100% for the argument of the invert filter function squishes the range. A value of 50% means that the range is squished to nothing, as the upper limit equals the lower one. This also means that the final inverted rgb() value is always rgb(128, 128, 128), no matter what the initial background-color may be.

原始范围从0255green通道的原始值为165invert过滤器函数的参数的任何小于100%值都会挤压范围。 值为50%表示该范围被压缩为零,因为上限等于下限。 这也意味着最终的反转rgb()值始终是rgb(128, 128, 128) ,无论初始background-color是什么。

The squished equivalent of the original value for the green channel is the one having an s in front on its label. The inverted value of this squished equivalent with respect to the middle of the range has an i in front on its label. And we can see that this is the value of the green channel for the solid background of the second box at the bottom after applying an invert filter on it.

green通道原始值的压缩等效值是在其标签上带有s那个。 相对于范围中间值,此压缩等效项的倒数值在其标签上带有一个i 。 我们可以看到,这是价值green第二盒的底部的坚实背景声道应用的后invert就可以了过滤器。

This means that our JavaScript code now becomes:

这意味着我们JavaScript代码现在变为:

var box = document.querySelector('.box'), 
    styles = window.getComputedStyle(box), 
    invert_perc = (styles.webkitFilter || styles.filter).match(/\d+/), 
    upper = invert_perc/100*255, 
    lower = 255 - upper, 
    original = styles.backgroundColor.split('('), 
    channels = original[1].match(/(0\.\d+)|\d+/g), 
    alpha = (channels.length > 3)?(1*channels.splice(3, 1)[0]):1, 
    inverted_channels = channels.map(function(ch) {
      return 255 - Math.round(lower + ch*(upper - lower)/255);
    }), 
    inverted;

if(alpha !== 1) {
  inverted_channels.splice(3, 0, alpha);
}

inverted = original[0] + '(' + inverted_channels.join(', ') + ')';


However, there is a problem: this assumes that the computed style value for the filter property is something like "invert(65%)". But most of the time, this is not the case. If we set the filter value to invert(65%) in the CSS, then the value we get this way via JavaScript is "invert(0.65)" in WebKit browsers and "invert(65%)" in Firefox. If we set the filter value to filter(.65) in the CSS, then the value we get via JavaScript is "invert(0.65)". Firefox returns it in the same format as the one we have set it in the CSS, while WebKit browsers always return it as a value between 0 and 1. So we need to handle this as well:

但是,存在一个问题:这假设filter属性的计算样式值类似于"invert(65%)" 。 但是在大多数情况下,情况并非如此。 如果在CSS中将过滤器值设置为invert(65%) ,则通过JavaScript通过这种方式获得的值在WebKit浏览器中为"invert(0.65)" ,而在Firefox中为"invert(65%)" 。 如果在CSS中将filter值设置为filter(.65) ,那么通过JavaScript获得的值是"invert(0.65)" 。 Firefox以与我们在CSS中设置的格式相同的格式返回它,而WebKit浏览器始终以01之间的值返回它。 所以我们也需要处理:

var box = document.querySelector('.box'), 
    styles = window.getComputedStyle(box), 
    filter = (styles.webkitFilter || styles.filter),
    invert_arg = filter.match(/(0\.\d+)|\d+/)[0], 
    upper = ((filter.indexOf('%') > -1)?(invert_arg/100):invert_arg)*255, 
    lower = 255 - upper, 
    original = styles.backgroundColor.split('('), 
    channels = original[1].match(/(0\.\d+)|\d+/g), 
    alpha = (channels.length > 3)?(1*channels.splice(3, 1)[0]):1, 
    inverted_channels = channels.map(function(ch) {
      return 255 - Math.round(lower + ch*(upper - lower)/255);
    }), 
    inverted;

if(alpha !== 1) {
  inverted_channels.splice(3, 0, alpha);
}

inverted = original[0] + '(' + inverted_channels.join(', ') + ')';


As it can be seen in this pen, it now works properly for both formats, provided that the alpha channel isn't 0.

从这支笔可以看出,只要alpha通道不为0 ,它现在就可以在两种格式下正常工作。

See the Pen Getting the inverted value for `background-color` via JS #3 by Ana Tudor (@thebabydino) on CodePen.

见笔经由JS#3获得用于`背景color`反转值由安娜铎( @thebabydino )上CodePen

最后的话 (Final words)

This still only deals with the very simple case where the value of the filter property is just one invert function. It won't work when we have chained filter functions, for example, something like filter: hue-rotate(90deg) invert(73%).

这仍然只处理非常简单的情况,即filter属性的值只是一个invert函数。 当我们具有链接的过滤器功能时,例如filter: hue-rotate(90deg) invert(73%)类的功能,它将无法正常工作。

翻译自: https://davidwalsh.name/detect-invert-color

css 反色

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值