以编程方式使六角颜色(或rgb和混合颜色)变亮或变暗

Pim*_*kit 463 javascript hex colors

这是我正在努力以编程方式使特定量的十六进制颜色变亮或变暗的功能.只需输入一个字符串就像"3F6D2A"color(col)和一个base10整数(amt)一样,可以减轻或变暗.要变暗,传入负数(即-20).

我这样做的原因是因为我发现的所有解决方案,到目前为止,它们似乎使问题过于复杂.而且我觉得只需几行代码即可完成.如果您发现任何问题,请告诉我,或者进行任何调整以使其加速.

function LightenDarkenColor(col,amt) {
    col = parseInt(col,16);
    return (((col & 0x0000FF) + amt) | ((((col>> 8) & 0x00FF) + amt) << 8) | (((col >> 16) + amt) << 16)).toString(16);
}
Run Code Online (Sandbox Code Playgroud)

对于开发使用,这里是一个更容易阅读的版本:

function LightenDarkenColor(col,amt) {
    var num = parseInt(col,16);
    var r = (num >> 16) + amt;
    var b = ((num >> 8) & 0x00FF) + amt;
    var g = (num & 0x0000FF) + amt;
    var newColor = g | (b << 8) | (r << 16);
    return newColor.toString(16);
}
Run Code Online (Sandbox Code Playgroud)

最后一个版本处理可能(或可能不)在开头有"#"的颜色.另外调整不正确的颜色值:

function LightenDarkenColor(col,amt) {
    var usePound = false;
    if ( col[0] == "#" ) {
        col = col.slice(1);
        usePound = true;
    }

    var num = parseInt(col,16);

    var r = (num >> 16) + amt;

    if ( r > 255 ) r = 255;
    else if  (r < 0) r = 0;

    var b = ((num >> 8) & 0x00FF) + amt;

    if ( b > 255 ) b = 255;
    else if  (b < 0) b = 0;

    var g = (num & 0x0000FF) + amt;

    if ( g > 255 ) g = 255;
    else if  ( g < 0 ) g = 0;

    return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}
Run Code Online (Sandbox Code Playgroud)

好吧,所以现在它不只是几行,但它似乎更简单,如果你没有使用"#"并且不需要检查超出范围的颜色,它只是几行.

如果不使用"#",您只需将其添加到以下代码中:

var myColor = "3F6D2A";
myColor = LightenDarkenColor(myColor,10);
thePlaceTheColorIsUsed = ("#" + myColor);
Run Code Online (Sandbox Code Playgroud)

我想我的主要问题是,我在这里是否正确?这不包括某些(正常)情况吗?

Pim*_*kit 851

好吧,这个答案已成为它自己的野兽.许多新版本,它变得越来越愚蠢.非常感谢这个答案的所有贡献者.但是,为了让群众保持简单.我将这个答案的演变的所有版本/历史存档到我的github.并在StackOverflow上使用最新版本开始清理它.特别感谢Mike'Pomax'Kamermans这个版本.他给了我新的数学.


此函数(pSBC)将采用HEX或RGB Web颜色.pSBC可以将它变暗或变暗,或者将其与第二种颜色混合,也可以直接传递,但是从Hex转换为RGB(Hex2RGB)或RGB转换为Hex(RGB2Hex).所有这一切都没有你甚至不知道你正在使用什么颜色

这种运行速度非常快,可能是最快的,特别是考虑到它的许多功能.这是一段很长的时间.在我的github上查看整个故事.如果您想要绝对最小和最快的遮挡或混合方式,请参阅下面的微功能并使用其中一个双线速度恶魔.它们非常适合激烈的动画,但这个版本对于大多数动画都足够快.

此功能使用日志混合或线性混合.但是,它不会转换为HSL以使颜色正确变亮或变暗.因此,此函数的结果将不同于使用HSL的更大且更慢的函数.

jsFiddle与pSBC

github> pSBC Wiki

特征:

  • 自动检测并接受字符串形式的标准Hex颜色.例如:"#AA6622""#bb551144".
  • 自动检测并接受字符串形式的标准RGB颜色.例如:"rgb(123,45,76)""rgba(45,15,74,0.45)".
  • 根据百分比将颜色变为白色或黑色.
  • 按百分比将颜色混合在一起.
  • Hex2RGB和RGB2Hex同时进行转换,还是单独转换.
  • 接受3位(或4位数w/alpha)HEX颜色代码,格式为#RGB(或#RGBA).它会扩展它们.例如:"#C41"变成"#CC4411".
  • 接受和(线性)混合alpha通道.如果c0(从)颜色或c1(到)颜色具有Alpha通道,则返回的颜色将具有Alpha通道.如果两种颜色都具有Alpha通道,则返回的颜色将是使用给定百分比的两个Alpha通道的线性混合(就像它是正常颜色通道一样).如果两种颜色中只有一种具有alpha通道,则此alpha将直接传递给返回的颜色.这允许人们在保持透明度水平的同时混合/遮蔽透明色.或者,如果透明度级别也应该混合,请确保两种颜色都有alpha.在着色时,它将直接通过alpha通道.如果你想要同样遮蔽alpha通道的基本着色,那么使用rgb(0,0,0,1)rgb(255,255,255,1)作为你的c1(到)颜色(或它们的十六进制等值).对于RGB颜色,返回颜色的Alpha通道将四舍五入到小数点后3位.
  • 使用混合时,RGB2Hex和Hex2RGB转换是隐含的.无论c0(从)颜色; 返回的颜色将始终采用c1(到)颜色的颜色格式(如果存在).如果没有c1(到)颜色,那么'c'作为c1颜色传入它将遮蔽并转换任何c0颜色.如果只需要转换,那么0也以%(p)传入.如果c1省略颜色或传入falsy,则不会转换.
  • 辅助功能也被添加到全局.pSBCr可以传递十六进制或RGB颜色,并返回包含此颜色信息的对象.它的形式为:{r:XXX,g:XXX,b:XXX,a:X.XXX}.其中.r,, .g和的.b范围是0到255.当没有alpha时:.a是-1.否则:.a范围为0.000到1.000.
  • 对于RGB输出时,它输出rgba()rgb()当与alpha通道的色通入c0(从)和/或c1(至).
  • 已添加次要错误检查.这不完美.它仍然可能崩溃或造成乱码.但它会抓住一些东西.基本上,如果结构在某些方面是错误的,或者如果百分比不是数字或超出范围,它将返回null.一个例子:pSBC(0.5,"salt") == null,它认为#salt是有效的颜色.删除最后的四行return null;以删除此功能并使其更快更小.
  • 使用日志混合.通过truel(第4个参数)使用线性混合.

码:

// Version 4.0
const pSBC=(p,c0,c1,l)=>{
    let r,g,b,P,f,t,h,i=parseInt,m=Math.round,a=typeof(c1)=="string";
    if(typeof(p)!="number"||p<-1||p>1||typeof(c0)!="string"||(c0[0]!='r'&&c0[0]!='#')||(c1&&!a))return null;
    if(!this.pSBCr)this.pSBCr=(d)=>{
        let n=d.length,x={};
        if(n>9){
            [r,g,b,a]=d=d.split(","),n=d.length;
            if(n<3||n>4)return null;
            x.r=i(r[3]=="a"?r.slice(5):r.slice(4)),x.g=i(g),x.b=i(b),x.a=a?parseFloat(a):-1
        }else{
            if(n==8||n==6||n<4)return null;
            if(n<6)d="#"+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]+(n>4?d[4]+d[4]:"");
            d=i(d.slice(1),16);
            if(n==9||n==5)x.r=d>>24&255,x.g=d>>16&255,x.b=d>>8&255,x.a=m((d&255)/0.255)/1000;
            else x.r=d>>16,x.g=d>>8&255,x.b=d&255,x.a=-1
        }return x};
    h=c0.length>9,h=a?c1.length>9?true:c1=="c"?!h:false:h,f=this.pSBCr(c0),P=p<0,t=c1&&c1!="c"?this.pSBCr(c1):P?{r:0,g:0,b:0,a:-1}:{r:255,g:255,b:255,a:-1},p=P?p*-1:p,P=1-p;
    if(!f||!t)return null;
    if(l)r=m(P*f.r+p*t.r),g=m(P*f.g+p*t.g),b=m(P*f.b+p*t.b);
    else r=m((P*f.r**2+p*t.r**2)**0.5),g=m((P*f.g**2+p*t.g**2)**0.5),b=m((P*f.b**2+p*t.b**2)**0.5);
    a=f.a,t=t.a,f=a>=0||t>=0,a=f?a<0?t:t<0?a:a*P+t*p:0;
    if(h)return"rgb"+(f?"a(":"(")+r+","+g+","+b+(f?","+m(a*1000)/1000:"")+")";
    else return"#"+(4294967296+r*16777216+g*65536+b*256+(f?m(a*255):0)).toString(16).slice(1,f?undefined:-2)
}
Run Code Online (Sandbox Code Playgroud)

用法:

// Setup:

let color1 = "rgb(20,60,200)";
let color2 = "rgba(20,60,200,0.67423)";
let color3 = "#67DAF0";
let color4 = "#5567DAF0";
let color5 = "#F3A";
let color6 = "#F3A9";
let color7 = "rgb(200,60,20)";
let color8 = "rgba(200,60,20,0.98631)";

// Tests:

/*** Log Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1 ); // rgb(20,60,200) + [42% Lighter] => rgb(166,171,225)
pSBC ( -0.4, color5 ); // #F3A + [40% Darker] => #c62884
pSBC ( 0.42, color8 ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(225,171,166,0.98631)

// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c" ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #a6abe1ac

// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c" ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)

// Blending
pSBC ( -0.5, color2, color8 ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(142,60,142,0.83)
pSBC ( 0.7, color2, color7 ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(168,60,111,0.67423)
pSBC ( 0.25, color3, color7 ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(134,191,208)
pSBC ( 0.75, color7, color3 ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #86bfd0

/*** Linear Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1, false, true ); // rgb(20,60,200) + [42% Lighter] => rgb(119,142,223)
pSBC ( -0.4, color5, false, true ); // #F3A + [40% Darker] => #991f66
pSBC ( 0.42, color8, false, true ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(223,142,119,0.98631)

// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c", true ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #778edfac

// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c", true ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)

// Blending
pSBC ( -0.5, color2, color8, true ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(110,60,110,0.83)
pSBC ( 0.7, color2, color7, true ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(146,60,74,0.67423)
pSBC ( 0.25, color3, color7, true ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(127,179,185)
pSBC ( 0.75, color7, color3, true ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #7fb3b9

/*** Other Stuff ***/
// Error Checking
pSBC ( 0.42, "#FFBAA" ); // #FFBAA + [42% Lighter] => null??(Invalid Input Color)
pSBC ( 42, color1, color5 ); // rgb(20,60,200) + #F3A + [4200% Blend] => null??(Invalid Percentage Range)
pSBC ( 0.42, {} ); // [object Object] + [42% Lighter] => null??(Strings Only for Color)
pSBC ( "42", color1 ); // rgb(20,60,200) + ["42"] => null??(Numbers Only for Percentage)
pSBC ( 0.42, "salt" ); // salt + [42% Lighter] => null??(A Little Salt is No Good...)

// Error Check Fails?(Some Errors are not Caught)
pSBC ( 0.42, "#salt" ); // #salt + [42% Lighter] => #a5a5a500??(...and a Pound of Salt is Jibberish)

// Ripping
pSBCr ( color4 ); // #5567DAF0 + [Rip] => [object Object] => {'r':85,'g':103,'b':218,'a':0.941}
Run Code Online (Sandbox Code Playgroud)

下图将有助于显示两种混合方法的不同之处:


微功能

如果你真的想要速度和尺寸,你将不得不使用RGB而不是HEX.RGB更简单,更简单,HEX写得太慢,并且对于简单的双线程(IE,它可能是3,4,6或8位HEX代码)来说有太多的风格.你还需要牺牲一些功能,没有错误检查,没有HEX2RGB和RGB2HEX.同样,您需要为颜色混合数学选择一个特定的函数(基于下面的函数名称),如果您想要着色或混合.这些函数支持alpha通道.当两种输入颜色都有alpha时,它会将它们线性混合.如果两种颜色中只有一种具有α,则它将直接传递给所得到的颜色.下面是两个非常快速和小巧的衬里功能:

const RGB_Linear_Blend=(p,c0,c1)=>{
    var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
    return"rgb"+(x?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+i(e[3]=="a"?e.slice(5):e.slice(4))*p)+","+r(i(b)*P+i(f)*p)+","+r(i(c)*P+i(g)*p)+d;
}

const RGB_Linear_Shade=(p,c)=>{
    var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:255*p,P=P?1+p:1-p;
    return"rgb"+(d?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+t)+","+r(i(b)*P+t)+","+r(i(c)*P+t)+(d?","+d:")");
}

const RGB_Log_Blend=(p,c0,c1)=>{
    var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
    return"rgb"+(x?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+p*i(e[3]=="a"?e.slice(5):e.slice(4))**2)**0.5)+","+r((P*i(b)**2+p*i(f)**2)**0.5)+","+r((P*i(c)**2+p*i(g)**2)**0.5)+d;
}

const RGB_Log_Shade=(p,c)=>{
    var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:p*255**2,P=P?1+p:1-p;
    return"rgb"+(d?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+t)**0.5)+","+r((P*i(b)**2+t)**0.5)+","+r((P*i(c)**2+t)**0.5)+(d?","+d:")");
}
Run Code Online (Sandbox Code Playgroud)

想了解更多信息?阅读github上的完整文章.

PT

(如果有人有其他混合方法的数学,请分享.)

  • 我用[TinyColor](https://github.com/bgrins/TinyColor) - `tinycolor.darken(color,amount);` (20认同)
  • 适用于需要它的人的PHP版本:https://gist.github.com/chaoszcat/5325115#file-gistfile1-php (8认同)
  • 伟大的帖子...... :) ...刚刚创建它的Swift扩展名:https://gist.github.com/matejukmar/1da47f7a950d1ba68a95 (4认同)
  • `'pSBCr' 未定义 no-undef` (4认同)
  • 这样想吧。如果我将数字“100”降低 10%,它将是“90”。然后,如果我将“90”提高 10%,它将是“99”。相反...如果我有“100”并将其提高 10%,我将得到“110”,然后如果我将其降低 10%...我将得到“99”。我认为这个技巧在金融系统中是用来赚钱(偷)钱的。 (3认同)
  • 这是更新的shadeColor2版本的PHP版本:`function shadeColor2($ color,$ percent){$ color = str_replace("#","",$ color); $吨= $%的<0 0:255;??$ P = $%的<0 $百分比*-1:$百分比; $ RGB = str_split($ color,2); $ R = hexdec($ RGB [0]); $ G = hexdec($ RGB [1]); $ B = hexdec($ RGB [2]); 返回'#'.substr(dechex(0x1000000 +(round(($ t- $ R)*$ p)+ $ R)*0x10000 +(round(($ t- $ G)*$ p)+ $ G)*0x100 + (圆(($ $叔B)*$ p)+ $ B)),1); }` (2认同)
  • 对不起,我显然错过了这一点.可能有两个原因.第一个显而易见的是我使用Math.Round并且你不能使用十进制数来进行准确的着色(颜色在十六进制中没有小数).例如,如果红色通道为"8",则添加"10%",得到"8.8",其舍入为"9".然后从`9`获得'9.09%`,你得到'8.1819`.哪一轮到'8`所以这是一个坏榜样.但它仍然表明你正在服用`9`而不是'8.8`的`9.09%`.因此,可能会有一些数字与我的示例完全相同. (2认同)
  • 很棒的答案,不幸的是不支持rgba透明度,即`rgba(15,15,15,0.5)`并且也不支持3位数代码,即``ccc` @jindrichm也许你可以保存原始颜色,转换它减轻10%,然后只使用储值? (2认同)
  • @PimpTrizkit 我忘了还有其他错误:`期望赋值或函数调用,而是在 `[r,g,b,a]=d=d.split("," 上看到一个表达式 no-unused-expressions` ),n=d.length;`, `xr=i(r[3]=="a"?r.slice(5):r.slice(4)),xg=i(g),xb=i (b),xa=a?parseFloat(a):-1`, `if(n==9||n==5)xr=d&gt;&gt;24&amp;255,xg=d&gt;&gt;16&amp;255,xb=d&gt;&gt; 8&amp;255,xa=m((d&amp;255)/0.255)/1000;`等等。`no-undef` 和 `this.pSBCr` 一起消失了。我正在使用 Node.js 进行编码。 (2认同)

小智 105

我提出了一个对我来说非常好的解决方案:

function shadeColor(color, percent) {

    var R = parseInt(color.substring(1,3),16);
    var G = parseInt(color.substring(3,5),16);
    var B = parseInt(color.substring(5,7),16);

    R = parseInt(R * (100 + percent) / 100);
    G = parseInt(G * (100 + percent) / 100);
    B = parseInt(B * (100 + percent) / 100);

    R = (R<255)?R:255;  
    G = (G<255)?G:255;  
    B = (B<255)?B:255;  

    var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
    var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
    var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));

    return "#"+RR+GG+BB;
}
Run Code Online (Sandbox Code Playgroud)

示例减轻:

shadeColor("#63C6FF",40);
Run Code Online (Sandbox Code Playgroud)

示例变暗:

shadeColor("#63C6FF",-40);
Run Code Online (Sandbox Code Playgroud)

  • 很好,我喜欢百分比!+1 Tho,我可能会做`R =((R <255)?R:255).toString(16);`那么`R = R.length == 1?速度为"0"+ R:R`.我不确定toUpperCase的意义吗? (4认同)
  • 不适用于#ff0000,#00ff00,#0000ff等纯色 (2认同)
  • 为了使它与黑色一起工作,我只是做了这个 hack `var R = parseInt(color.substring(1, 3), 16) var G = parseInt(color.substring(3, 5), 16) var B = parseInt( color.substring(5, 7), 16) 如果 (R == 0) R = 32; 如果 (G == 0) G = 32; 如果(B == 0)B = 32;` (2认同)

ant*_*oni 23

我在这里加了 2 美分,这是不同答案的令人满意的小组合:

const colorShade = (col, amt) => {
  col = col.replace(/^#/, '')
  if (col.length === 3) col = col[0] + col[0] + col[1] + col[1] + col[2] + col[2]

  let [r, g, b] = col.match(/.{2}/g);
  ([r, g, b] = [parseInt(r, 16) + amt, parseInt(g, 16) + amt, parseInt(b, 16) + amt])

  r = Math.max(Math.min(255, r), 0).toString(16)
  g = Math.max(Math.min(255, g), 0).toString(16)
  b = Math.max(Math.min(255, b), 0).toString(16)

  const rr = (r.length < 2 ? '0' : '') + r
  const gg = (g.length < 2 ? '0' : '') + g
  const bb = (b.length < 2 ? '0' : '') + b

  return `#${rr}${gg}${bb}`
}

Run Code Online (Sandbox Code Playgroud)

接受以#或不以 6 个字符或 3 个字符开头的颜色。

使用示例: colorShade('#54b946', -40)

这是 4 种颜色的输出,每种颜色有 3 种颜色较浅,3 种颜色较深(此处数量为 40 的倍数)。

在此处输入图片说明


Nat*_*ski 8

基于 David Sherret 和 Pablo,上面的答案将解决方案转换为 Typescript 的更安全版本

/**
 * @param color Hex value format: #ffffff or ffffff
 * @param decimal lighten or darken decimal value, example 0.5 to lighten by 50% or 1.5 to darken by 50%.
 */
static shadeColor(color: string, decimal: number): string {
    const base = color.startsWith('#') ? 1 : 0;

    let r = parseInt(color.substring(base, 3), 16);
    let g = parseInt(color.substring(base + 2, 5), 16);
    let b = parseInt(color.substring(base + 4, 7), 16);

    r = Math.round(r / decimal);
    g = Math.round(g / decimal);
    b = Math.round(b / decimal);

    r = (r < 255)? r : 255;
    g = (g < 255)? g : 255;
    b = (b < 255)? b : 255;

    const rr = ((r.toString(16).length === 1)? `0${r.toString(16)}` : r.toString(16));
    const gg = ((g.toString(16).length === 1)? `0${g.toString(16)}` : g.toString(16));
    const bb = ((b.toString(16).length === 1)? `0${b.toString(16)}` : b.toString(16));

    return `#${rr}${gg}${bb}`;
}
  
Run Code Online (Sandbox Code Playgroud)


sup*_*san 7

这是一个基于Eric答案的超级简单的班轮

function adjust(color, amount) {
    return '#' + color.replace(/^#/, '').replace(/../g, color => ('0'+Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2));
}
Run Code Online (Sandbox Code Playgroud)

例子:

adjust('#ffffff', -20) => "#ebebeb"
adjust('000000', 20) => "#141414"
Run Code Online (Sandbox Code Playgroud)

  • “超级简单”。 (25认同)
  • 金额是多少?可以帮助澄清它是否是 px、百分比等。 (2认同)

小智 6

这是我根据您的功能使用的。我更喜欢使用步骤而不是百分比,因为它对我来说更直观。

例如,200 蓝值的 20% 与 40 蓝值的 20% 大不相同。

无论如何,这是我的修改,感谢您的原始功能。

function adjustBrightness(col, amt) {

    var usePound = false;

    if (col[0] == "#") {
        col = col.slice(1);
        usePound = true;
    }

    var R = parseInt(col.substring(0,2),16);
    var G = parseInt(col.substring(2,4),16);
    var B = parseInt(col.substring(4,6),16);

    // to make the colour less bright than the input
    // change the following three "+" symbols to "-"
    R = R + amt;
    G = G + amt;
    B = B + amt;

    if (R > 255) R = 255;
    else if (R < 0) R = 0;

    if (G > 255) G = 255;
    else if (G < 0) G = 0;

    if (B > 255) B = 255;
    else if (B < 0) B = 0;

    var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
    var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
    var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));

    return (usePound?"#":"") + RR + GG + BB;

}
Run Code Online (Sandbox Code Playgroud)


Jam*_*ury 5

您是否考虑过 RGB > HSL 转换?然后只需上下移动亮度?这就是我要走的路。

快速查找一些算法后,我找到了以下网站。

PHP: http: //serennu.com/colour/rgbtohsl.php

JavaScript: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript

编辑以上链接不再有效。您可以查看 git hub 来获取页面源代码要点

或者,另一个 StackOverflow问题可能是一个不错的选择。


尽管这对于OP来说不是正确的选择,但以下是我最初建议的代码的近似值。(假设你有rgb/hsl转换功能)

var SHADE_SHIFT_AMOUNT = 0.1; 

function lightenShade(colorValue)
{
    if(colorValue && colorValue.length >= 6)
    {
        var redValue = parseInt(colorValue.slice(-6,-4), 16);
        var greenValue = parseInt(colorValue.slice(-4,-2), 16);
        var blueValue = parseInt(colorValue.slice(-2), 16);

        var hsl = rgbToHsl(redValue, greenValue, blueValue);
        hsl[2]= Math.min(hsl[2] + SHADE_SHIFT_AMOUNT, 1);
        var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
        return "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
    }
    return null;
}

function darkenShade(colorValue)
{
    if(colorValue && colorValue.length >= 6)
    {
        var redValue = parseInt(colorValue.slice(-6,-4), 16);
        var greenValue = parseInt(colorValue.slice(-4,-2), 16);
        var blueValue = parseInt(colorValue.slice(-2), 16);

        var hsl = rgbToHsl(redValue, greenValue, blueValue);
        hsl[2]= Math.max(hsl[2] - SHADE_SHIFT_AMOUNT, 0);
        var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
        return "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

这假设:

  1. 你有函数hslToRgbrgbToHsl.
  2. 参数是#RRGGBBcolorValue形式的字符串

尽管如果我们讨论 css,有一个用于为 IE9/Chrome/Firefox 指定hsl/hsla的语法。


Coo*_*cid 5

我尝试了你的函数,但有一个小错误:例如,如果某些最终的 'r' 值只有 1 位数字,则结果如下:'a0a0a' 当正确的值为 '0a0a0a' 时。我只是通过添加这个而不是你的回报来快速修复它:

var rStr = (r.toString(16).length < 2)?'0'+r.toString(16):r.toString(16);
var gStr = (g.toString(16).length < 2)?'0'+g.toString(16):g.toString(16);
var bStr = (b.toString(16).length < 2)?'0'+b.toString(16):b.toString(16);

return (usePound?"#":"") + rStr + gStr + bStr;
Run Code Online (Sandbox Code Playgroud)

也许它不是那么好,但它可以完成工作。很棒的功能,顺便说一句。正是我所需要的。:)


小智 5

我想将颜色更改为特定的亮度级别 - 无论颜色之前的亮度是什么 - 这是一个简单的 JS 函数,似乎运行良好,尽管我确信它可以更短

function setLightPercentage(col: any, p: number) {
    const R = parseInt(col.substring(1, 3), 16);
    const G = parseInt(col.substring(3, 5), 16);
    const B = parseInt(col.substring(5, 7), 16);
    const curr_total_dark = (255 * 3) - (R + G + B);

    // calculate how much of the current darkness comes from the different channels
    const RR = ((255 - R) / curr_total_dark);
    const GR = ((255 - G) / curr_total_dark);
    const BR = ((255 - B) / curr_total_dark);

    // calculate how much darkness there should be in the new color
    const new_total_dark = ((255 - 255 * (p / 100)) * 3);

    // make the new channels contain the same % of available dark as the old ones did
    const NR = 255 - Math.round(RR * new_total_dark);
    const NG = 255 - Math.round(GR * new_total_dark);
    const NB = 255 - Math.round(BR * new_total_dark);

    const RO = ((NR.toString(16).length === 1) ? "0" + NR.toString(16) : NR.toString(16));
    const GO = ((NG.toString(16).length === 1) ? "0" + NG.toString(16) : NG.toString(16));
    const BO = ((NB.toString(16).length === 1) ? "0" + NB.toString(16) : NB.toString(16));

    return "#" + RO + GO + BO;}
Run Code Online (Sandbox Code Playgroud)


Kam*_*ski 5

你的方法没问题:)我稍微简化了你的最短版本(对于饱和度控制,请看这里

(col,amt)=> (+('0x'+col)+amt*0x010101).toString(16).padStart(6,0)
Run Code Online (Sandbox Code Playgroud)

(col,amt)=> (+('0x'+col)+amt*0x010101).toString(16).padStart(6,0)
Run Code Online (Sandbox Code Playgroud)
// Similar to OP shortest version, we not have here # and colors range checking

var LightenDarkenColor = 
     (col,amt) => (+('0x'+col)+amt*0x010101).toString(16).padStart(6,0);    




// ------
// TEST
// ------

function update() {
  let c= col.value.padEnd(6,'0').slice(0,6);
  let color = '#'+LightenDarkenColor(c, +amt.value);
  oldColor.innerHTML = 'Old: #'+c;
  oldColor.style = `background: #${c}`;
  newColor.innerHTML = 'New: '+color
  newColor.style = `background: ${color}`;

  
}

update();
Run Code Online (Sandbox Code Playgroud)
.box{ width: 100px; height: 100px; margin: 10px; display: inline-block}
Run Code Online (Sandbox Code Playgroud)

以及带有 # 和颜色范围检查的版本

<input id="col" value="3F6D2A" oninput="update()">
<input id="amt" value="30" oninput="update()"><br>
<div id="oldColor" class="box"></div>
<div id="newColor" class="box"></div>
Run Code Online (Sandbox Code Playgroud)
// # and colors range checking

var LightenDarkenColor = 
     (col,amt) => '#'+col.slice(1).match(/../g)
                         .map(x=>(x=+`0x${x}`+amt,x<0?0:(x>255?255:x))
                         .toString(16).padStart(2,0)).join``;




// ------
// TEST
// ------

function update() {
  let c= col.value.padEnd(6,'0').slice(0,7);
  let color = LightenDarkenColor(c, +amt.value);
  oldColor.innerHTML = 'Old: '+c;
  oldColor.style = `background: ${c}`;
  newColor.innerHTML = 'New: '+color
  newColor.style = `background: ${color}`;
}

update();
Run Code Online (Sandbox Code Playgroud)
.box{ width: 100px; height: 100px; margin: 10px; display: inline-block}
Run Code Online (Sandbox Code Playgroud)