如何计算所需的色相旋转来生成特定的颜色?

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

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

然后循环 hue-rotate找到一种颜色,但是有没有可能提前计算出这个值呢?鉴于指定的十六进制值是相当暗的,我想我将需要包括 invert(%)过滤器以及。

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

剪辑

下面是 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>
<p style="background: #689d94">​</p>

64651 次浏览

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.

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(178, 160, 128)

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

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 sepia is defined in the SVG Filters specification).

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:

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:

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:

/*      ------ 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:

...
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.

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.

If svg are being used then ...

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

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>

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.

Take your color #424242 - divide each RGB channel value by #FF and put them in the fifth column, first three rows of your color matrix. In this case, hex #42 is 68 in decimal, so divide that by 255 (#FF in decimal) and you'll get 0.257 - which you put in the fifth column, first three rows.

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>

The only way to get the exact match is to use an SVG color matrix filter.

For RGB color #689d94, which is rgb(104, 157, 148), divide each primary color's value by 255:

Put these weights into the SVG <filter> matrix (5ᵗʰ column in the first 3 rows):

<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="689d94" color-interpolation-filters="sRGB">
<feColorMatrix type="matrix"
values="0 0 0 0 0.40784
0 0 0 0 0.61569
0 0 0 0 0.58039
0 0 0 1 0"/>
</filter>
</defs>
</svg>

The <filter> has to have id (I used the RGB hex code 689d94), so we can use it as a reference.

Since some browsers (e.g. Firefox) don't see/use the SVG filter if the display property of the SVG element is set to none, and having this SVG element in HTML code would inconveniently occupy some space, the best way is to convert this SVG into a pure inline CSS filter.

To get an inline filter value, take the above listed SVG code, transform it into a single line by remove line breaks and unnecessary spaces, then prepend url('data:image/svg+xml, and append the previously mentioned id as #689d94'):

div {
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="71.063" height="60.938"><path d="M33.938 0l-16.97 19.906H1.625L0 21.781v8.781l1.25 1.407h4.781l5.875 28.969h46.969l6.188-28.97h4.687l1.313-1.343v-8.844L69.5 19.906H54.656L37.312 0h-3.375zm1.593 7.594l9.594 12.312H26.25l9.281-12.312zm-20.281 16s-.405 2.9 1.594 3.844c1.998.942 4.406.03 4.406.03-1.666 2.763-3.638 3.551-5.469 2.688-3.312-1.562-.531-6.562-.531-6.562zm41.188.031s2.749 4.969-.563 6.531c-2.487 1.162-4.848-1.541-5.438-2.656 0 0 2.377.88 4.375-.063 1.999-.942 1.625-3.812 1.625-3.812z"/></svg>') no-repeat; // optimized from http://richard.parnaby-king.co.uk/basket.svg
background-size: 100%;
display: inline-block;
height: 5em;
width: 5em;
}
#colored {
filter: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><defs><filter id="689d94" color-interpolation-filters="sRGB"><feColorMatrix type="matrix" values="0 0 0 0 0.40784 0 0 0 0 0.61569 0 0 0 0 0.58039 0 0 0 1 0"/></filter></defs></svg>#689d94');
margin-left: 20px;
}
<!-- No <svg> in HTML; pure CSS -->
<div></div><div id="colored"></div>
<p style="background: #689d94">​</p>

Hex Color To CSS Filter Converter

Use this website to calculate the filter: https://isotropic.co/tool/hex-color-to-css-filter/