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-color
或color
的原始值并且可以读取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)
,其中red
, green
和blue
可以采用0
到255
之间的值,而应用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
通道保持不变,并且仅修改了red
, green
和blue
通道,因此这意味着我们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%
,首先将red
, green
和blue
通道的[0, 255]
范围压缩到其中心值附近。 这意味着,该范围的上限变为从255
到65%
的255
和它的下限变为从0
至100% - 65% = 35%
的255
。 然后,我们计算原始background-color
压缩等效值,这仅意味着获取每个通道值,将其缩放到新的压缩范围,然后添加下限。 最后,最后一步是获得与原始background-color
类似的red
, green
和blue
通道中每个red
, green
和blue
通道的中心值的对称值。
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.
原始范围从0
到255
, green
通道的原始值为165
。 invert
过滤器函数的参数的任何小于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浏览器始终以0
到1
之间的值返回它。 所以我们也需要处理:
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 反色
还没有评论,来说两句吧...