CSS 如何计算所需的色调旋转以生成特定颜色?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29037023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 03:04:27  来源:igfitidea点击:

How to calculate required hue-rotate to generate specific colour?

csscss-filters

提问by Richard Parnaby-King

I have a white image that I am using as a background for a div, and I would like to colour to match the themes main colour. I am aware I can do:

我有一张白色图像,用作 div 的背景,我想着色以匹配主题主色。我知道我可以做到:

filter: sepia() saturate(10000%) hue-rotate(30deg);

and cycle through hue-rotateto find a colour, but is it possible to calculate this value in advance? Given that the specified hex value is quite dark, I imagine I will need to include the invert(%)filter as well.

并循环hue-rotate查找颜色,但是否可以提前计算该值?鉴于指定的十六进制值很暗,我想我还需要包括invert(%)过滤器。

Given a hex value of #689d94what math do I need to do to calculate the desired hue-rotateand invertvalue to convert my white background image into the same colour?

给定一个十六进制值,#689d94我需要做什么数学来计算将我的白色背景图像转换为相同颜色的所需值hue-rotateinvert值?

Edit

编辑

Here's a snippet of a divwith a white background image being filtered green. The trick here, is it is the whole of the divthat is being filtered, not just the image. If I was to enter some text into the divthe text colour would turn green as well.

这是一个div带有白色背景图像被过滤为绿色的片段。这里的诀窍div是,被过滤的是整个图像,而不仅仅是图像。如果我要在其中输入一些文本div,文本颜色也会变成绿色。

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat scroll 0 0 transparent;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: invert(25%) sepia() saturate(100000%) hue-rotate(174deg);
  filter: invert(25%) sepia() saturate(100000%) hue-rotate(174deg);
}
<div>
  </div>

回答by

The key in this case is to define an initial color. White nor black or any gray-scale is technically an actual color - you can't saturate or rotate it. You'll have to "colorize" it somehow, and the sepia filter is the only filter which do some form of colorizing.

这种情况下的关键是定义初始颜色。从技术上讲,白色、黑色或任何灰度都是一种实际颜色——您无法使其饱和或旋转。您必须以某种方式对其进行“着色”,而棕褐色滤镜是唯一可以进行某种形式着色的滤镜。

It would be easier if your image was pure 100% red. Then you could just add the target degree directly and adjust saturation and lightness using HSL for target. For a white color start point the first step is to convert and define an intermediate color so we can saturate and rotate it later on.

如果您的图像是纯 100% 红色会更容易。然后您可以直接添加目标度数并使用 HSL 作为目标调整饱和度和亮度。对于白色起点,第一步是转换和定义中间色,以便我们稍后对其进行饱和和旋转。

Lets first darken the white image and apply sepia to get a "base" color we can work with:

让我们首先使白色图像变暗并应用棕褐色以获得我们可以使用的“基础”颜色:

filter: brightness(50%) sepia(1);

This will produce RGB color value of approximately:

这将产生大约的 RGB 颜色值:

rgb(178, 160, 128)

Step two is to convert that to HSL color-spacewhich gives us:

第二步是将其转换为 HSL 颜色空间,它为我们提供:

hsl(38, 24.5%, 60%);

Base color result

基色结果

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: brightness(50%) sepia(1);
  filter: brightness(50%) sepia(1);
}
<div></div>

Converting base color to target color

将基色转换为目标色

These two first steps are static and its result will be reused every time we need to find a target adjustment (the actual value of sepiais defined in the SVG Filters specification).

前两个步骤是静态的,每次我们需要找到目标调整时都会重用其结果(sepia的实际值在SVG Filters 规范中定义)。

Now we need to calculate what we need to apply to this base color to get target color. First convert target color, for example #689d94 as given in the question, to HSL:

现在我们需要计算我们需要应用到这个基色上以获得目标颜色。首先将目标颜色(例如问题中给出的 #689d94)转换为 HSL:

hsl(170, 21.3%, 51.2%);

Then we have to calculate the difference between those. Hue is calculated by simply subtracting base from target. The same for Saturation and Lightness, but as we assume 100% of the base value we need to subtract the result from 100% to end up with a diff for the accumulated values:

然后我们必须计算它们之间的差异。色调是通过简单地从目标中减去基数来计算的。饱和度和亮度相同,但由于我们假设基值的 100%,我们需要从 100% 中减去结果,以得出累积值的差异:

H:  170 - 38             ->  132°
S:  100 + (24.5 - 21.3)  ->  103.2%  (relative to base 100% =  3.2%)
L:  100 + (51.2 - 60.0)  ->   91.2%  (relative to base 100% = -8.8%)

Convert those values to a filter-string by appending it to the existing filter, then set it on the div:

通过将这些值附加到现有过滤器,将这些值转换为过滤器字符串,然后将其设置在 div 上:

/*      ------ base color ------  -------  new target -------------------------------*/
filter: brightness(50%) sepia(1)  hue-rotate(132deg) saturate(103.2%) brightness(91.2%);

And to set it you would probably do something like this assuming filter and divElement are already declared:

并且要设置它,假设已经声明了过滤器和 divElement,您可能会执行以下操作:

...
filter = "brightness(0.5) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%)";
divElement.style.filter = filter;
divElement.style.webkitFilter = filter;

Note that there is likely rounding errors as RGB is represented as integer, while HSL is floating point, so the actual result may not be exact, but it should get pretty close.

请注意,可能存在舍入错误,因为 RGB 表示为整数,而 HSL 是浮点数,因此实际结果可能不准确,但应该非常接近。

Live example

活生生的例子

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: 
      brightness(50%) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%);
  filter: 
      brightness(50%) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%);
}
<div></div>
<span style="font:14px sans-serif;padding:7px;color:#fff;background:#689d94">
Target color</span>

Viable alternative options are:

可行的替代选择是:

  • Predefine SVGs with the color already set.
  • Work with HSL/RGB directly in JavaScript and modify the SVG tree with the color directly for the shape rather than using filters. Filters are expensive performance wise, especially if many are chained as here and they are in addition a dominant part of a page. They are neither supported in all browsers.
  • 使用已设置的颜色预定义 SVG。
  • 直接在 JavaScript 中使用 HSL/RGB,并直接使用形状的颜色修改 SVG 树,而不是使用过滤器。过滤器在性能方面是昂贵的,特别是如果许多过滤器像这里一样链接并且它们另外是页面的主要部分。所有浏览器都不支持它们。

回答by Michael Mullany

The accepted answer is wrong. Hue-rotate does not conserve saturation or brightness and you have to do crazy math to come up with the correct values. The far easier way - which will result in a correct result - is to do a CSS filter that references an SVG filter. The feColorMatrix primitive in SVG filters allows you to pick a color directly - like so. Take your color #424242 - divide each color's hex value by #FF (.257) and put them in the fifth column, first three rows of your color matrix. Like so:

接受的答案是错误的。色相旋转不会保存饱和度或亮度,您必须进行疯狂的数学运算才能得出正确的值。更简单的方法 - 这将产生正确的结果 - 是做一个引用 SVG 过滤器的 CSS 过滤器。SVG 过滤器中的 feColorMatrix 基元允许您直接选择颜色 - 就像这样。取你的颜色 #424242 - 将每种颜色的十六进制值除以 #FF (.257) 并将它们放在第五列,颜色矩阵的前三行。像这样:

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat scroll 0 0 transparent;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: url(#colorize);
  filter: url(#colorize);
}
<div>
  </div>

<svg>
<defs>
<filter id="colorize" color-interpolation-filters="sRGB">
<feColorMatrix type="matrix" values="0 0 0 0 .257
                                 0 0 0 0 .257
                                 0 0 0 0 .257
                                 0 0 0 1 0"/>
 
/filter>
</defs>
</svg>

回答by Azi

If svg are being used then ...

如果正在使用 svg 那么...

You can open svg files with some text editor copy and paste to html file then change path color as required.

您可以使用一些文本编辑器打开 svg 文件,复制并粘贴到 html 文件,然后根据需要更改路径颜色。

In below example code... I just changed the path color of center ring. Hope this helps..

在下面的示例代码中......我只是改变了中心环的路径颜色。希望这可以帮助..

        var imgg =document.getElementById("path");
        imgg.style="fill:#424242";
   
<html>
<body>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg id="imgg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 296.838 296.838" style="enable-background:new 0 0 296.838 296.838;" xml:space="preserve" width="512px" height="512px">
<g>
 <path  d="M58.733,64.566L41.763,47.596C14.832,74.526,0,110.333,0,148.419s14.832,73.893,41.763,100.823l16.971-16.971   C36.335,209.874,24,180.095,24,148.419S36.335,86.964,58.733,64.566z" fill="#91DC5A"/>
 <path d="M82.137,81.969c-17.75,17.748-27.525,41.348-27.525,66.45s9.775,48.702,27.525,66.45l16.971-16.971   c-13.218-13.216-20.496-30.788-20.496-49.479s7.278-36.264,20.496-49.48L82.137,81.969z" fill="#91DC5A"/>
 <path d="M255.075,47.596l-16.971,16.971c22.399,22.397,34.733,52.177,34.733,83.853s-12.335,61.455-34.733,83.852l16.971,16.971   c26.931-26.931,41.763-62.737,41.763-100.823S282.006,74.526,255.075,47.596z" fill="#91DC5A"/>
 <path d="M214.701,81.969L197.73,98.939c13.218,13.216,20.496,30.788,20.496,49.48s-7.278,36.264-20.496,49.479l16.971,16.971   c17.75-17.748,27.525-41.348,27.525-66.45S232.451,99.717,214.701,81.969z" fill="#91DC5A"/>
 <path id="path" d="M148.586,114.789c-8.607,0-17.212,3.284-23.78,9.851c-13.131,13.133-13.131,34.424,0,47.559   c6.568,6.566,15.174,9.851,23.78,9.851c8.606,0,17.212-3.284,23.779-9.851c13.131-13.135,13.131-34.426,0-47.559   C165.798,118.073,157.192,114.789,148.586,114.789z M155.395,155.228c-2.454,2.454-5.319,2.821-6.809,2.821   c-1.489,0-4.356-0.367-6.808-2.818c-3.755-3.756-3.755-9.867-0.003-13.619c2.455-2.455,5.321-2.822,6.811-2.822   c1.489,0,4.354,0.367,6.808,2.82C159.147,145.363,159.147,151.475,155.395,155.228z" fill="#91DC5A"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
    
    
</body>
</html>

For background image

对于背景图像

        var myimg='url(\'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 296.838 296.838" style="enable-background:new 0 0 296.838 296.838;" xml:space="preserve" width="512px" height="512px"><g><path  d="M58.733,64.566L41.763,47.596C14.832,74.526,0,110.333,0,148.419s14.832,73.893,41.763,100.823l16.971-16.971   C36.335,209.874,24,180.095,24,148.419S36.335,86.964,58.733,64.566z" fill="#91DC5A"/><path d="M82.137,81.969c-17.75,17.748-27.525,41.348-27.525,66.45s9.775,48.702,27.525,66.45l16.971-16.971   c-13.218-13.216-20.496-30.788-20.496-49.479s7.278-36.264,20.496-49.48L82.137,81.969z" fill="#91DC5A"/><path d="M255.075,47.596l-16.971,16.971c22.399,22.397,34.733,52.177,34.733,83.853s-12.335,61.455-34.733,83.852l16.971,16.971   c26.931-26.931,41.763-62.737,41.763-100.823S282.006,74.526,255.075,47.596z" fill="#91DC5A"/><path d="M214.701,81.969L197.73,98.939c13.218,13.216,20.496,30.788,20.496,49.48s-7.278,36.264-20.496,49.479l16.971,16.971   c17.75-17.748,27.525-41.348,27.525-66.45S232.451,99.717,214.701,81.969z" fill="#91DC5A"/><path d="M148.586,114.789c-8.607,0-17.212,3.284-23.78,9.851c-13.131,13.133-13.131,34.424,0,47.559   c6.568,6.566,15.174,9.851,23.78,9.851c8.606,0,17.212-3.284,23.779-9.851c13.131-13.135,13.131-34.426,0-47.559   C165.798,118.073,157.192,114.789,148.586,114.789z M155.395,155.228c-2.454,2.454-5.319,2.821-6.809,2.821   c-1.489,0-4.356-0.367-6.808-2.818c-3.755-3.756-3.755-9.867-0.003-13.619c2.455-2.455,5.321-2.822,6.811-2.822   c1.489,0,4.354,0.367,6.808,2.82C159.147,145.363,159.147,151.475,155.395,155.228z" fill="#91DC5A"/></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg> \')';
        
        document.getElementById("mydiv").style.backgroundImage =myimg ;  
        
        
        
        //changing color according to theme .. new theme color :#424242
        myimg=myimg.replace(/#91DC5A/g,"#424242");
       document.getElementById("mydiv").style.backgroundImage =myimg ; 
             div {

  background-size:5em;
  width:5em;
  height:5em;
  
}
<html>
<body>

    
    <div id="mydiv"></div>
<span style="font:14px sans-serif;padding:7px;color:#fff;background:#689d94">
Target color</span>
   
  
    
</body>
</html>