如何使用JavaScript生成比某个特定百分比更浅/深的CSS颜色

36

假设我有一个颜色代码为#404040。如何生成比原来亮或者暗20%的新颜色代码(或者其他给定百分比)?我需要这个来生成hover时应用的颜色。

应用的颜色基于所选主题而变化,因此无法使用另一个带有预定义颜色值的类或:hover。


颜色是否总是十六进制颜色?是否可能将它们全部转换为RGB,甚至更好的是HSV? - Sean Vieira
11个回答

67
var pad = function(num, totalChars) {
    var pad = '0';
    num = num + '';
    while (num.length < totalChars) {
        num = pad + num;
    }
    return num;
};

// Ratio is between 0 and 1
var changeColor = function(color, ratio, darker) {
    // Trim trailing/leading whitespace
    color = color.replace(/^\s*|\s*$/, '');

    // Expand three-digit hex
    color = color.replace(
        /^#?([a-f0-9])([a-f0-9])([a-f0-9])$/i,
        '#$1$1$2$2$3$3'
    );

    // Calculate ratio
    var difference = Math.round(ratio * 256) * (darker ? -1 : 1),
        // Determine if input is RGB(A)
        rgb = color.match(new RegExp('^rgba?\\(\\s*' +
            '(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])' +
            '\\s*,\\s*' +
            '(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])' +
            '\\s*,\\s*' +
            '(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])' +
            '(?:\\s*,\\s*' +
            '(0|1|0?\\.\\d+))?' +
            '\\s*\\)$'
        , 'i')),
        alpha = !!rgb && rgb[4] != null ? rgb[4] : null,

        // Convert hex to decimal
        decimal = !!rgb? [rgb[1], rgb[2], rgb[3]] : color.replace(
            /^#?([a-f0-9][a-f0-9])([a-f0-9][a-f0-9])([a-f0-9][a-f0-9])/i,
            function() {
                return parseInt(arguments[1], 16) + ',' +
                    parseInt(arguments[2], 16) + ',' +
                    parseInt(arguments[3], 16);
            }
        ).split(/,/),
        returnValue;

    // Return RGB(A)
    return !!rgb ?
        'rgb' + (alpha !== null ? 'a' : '') + '(' +
            Math[darker ? 'max' : 'min'](
                parseInt(decimal[0], 10) + difference, darker ? 0 : 255
            ) + ', ' +
            Math[darker ? 'max' : 'min'](
                parseInt(decimal[1], 10) + difference, darker ? 0 : 255
            ) + ', ' +
            Math[darker ? 'max' : 'min'](
                parseInt(decimal[2], 10) + difference, darker ? 0 : 255
            ) +
            (alpha !== null ? ', ' + alpha : '') +
            ')' :
        // Return hex
        [
            '#',
            pad(Math[darker ? 'max' : 'min'](
                parseInt(decimal[0], 10) + difference, darker ? 0 : 255
            ).toString(16), 2),
            pad(Math[darker ? 'max' : 'min'](
                parseInt(decimal[1], 10) + difference, darker ? 0 : 255
            ).toString(16), 2),
            pad(Math[darker ? 'max' : 'min'](
                parseInt(decimal[2], 10) + difference, darker ? 0 : 255
            ).toString(16), 2)
        ].join('');
};
var lighterColor = function(color, ratio) {
    return changeColor(color, ratio, false);
};
var darkerColor = function(color, ratio) {
    return changeColor(color, ratio, true);
};

// Use
var darker = darkerColor('rgba(80, 75, 52, .5)', .2);
var lighter = lighterColor('rgba(80, 75, 52, .5)', .2);

现在可以处理RGB(A)输入,以及3位或6位十六进制颜色码。


1
从技术上讲,要从RGB值中获得x%更轻或更暗的颜色,您需要将其转换为HSL,将(L)亮度减少或增加x%,然后再转换回RGB。我不确定像在这里减少各个RGB值是否会导致相同的颜色。更不用说人眼如何感知亮度变化可能会引入非线性比例尺来等效于x%感知亮度变化 :) - AsGoodAsItGets
这是真的,这是一个非常天真的方法。 - eyelidlessness

8
您可以制作一个部分半透明的白色或黑色PNG,并在鼠标悬停时叠加(下层)它:
div.button {
  background-color: #404040;
}
body>div.button:hover {
  background-image: url('blackpixel.png');
}

不需要 JavaScript。

4
请添加更多的代码以支持IE 6。然后添加另一个选项来实现更轻量级的功能。然后...... - eyelidlessness
LOL,那根本没有解决我列出的任何问题。 它的实用性有限,但如果这是你所需要的全部,那就用吧。 - eyelidlessness

3

来自 Craig Buckler 的文章 如何在 JavaScript 中计算较浅或较深的十六进制颜色,发表于2011年9月6日:

function ColorLuminance(hex, lum) {
  // validate hex string
  hex = String(hex).replace(/[^0-9a-f]/gi, '');
  if (hex.length < 6) {
      hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
  }
  lum = lum || 0;
  // convert to decimal and change luminosity
  var rgb = "#", c, i;
  for (i = 0; i < 3; i++) {
      c = parseInt(hex.substr(i*2,2), 16);
      c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
      rgb += ("00"+c).substr(c.length);
  }
  return rgb;
}

1
你基本上只需要从每个 R、G、B 组件中添加(用于更轻)或减去(用于更暗)等量的颜色值。
看一下 Domino 2.0,这是一个小型的 JavaScript 库,可以做到这一点。

我使用了:hover并且动脑筋计算,但这对我起到了作用。 - semiomant

1
这是我的做法,使用replace和split函数。
var CO='';

$('#HoverMe').hover(function(){  
    CO=$(this).css('backgroundColor');
 
    var CC= $(this).css('backgroundColor').replace('rgb(','').replace(')','').split(',');

    var Change=0.2;

    var CR=Math.floor((CC[0]*Change)+parseInt(CC[0]));

    var CG=Math.floor((CC[1]*Change)+parseInt(CC[1]));

    var CB=Math.floor((CC[2]*Change)+parseInt(CC[2]));

    $(this).css('background','rgb('+CR+','+CG+','+CB+')');
},

function(){
    $(this).css('background',CO);
});

1

对于这个解决方案,你需要两个元素,外部元素定义了你的颜色,内部元素用于高亮显示。在我的情况下,我有像这样的东西:

<div class="button"><a href="#">Hi Color</a></div>

然后你在CSS中定义:
.button {
   display: inline-block;
   background-color: blue;
}

.button a {
   display: inline-block;
}

.button a:hover {
   background-color: rgba(255,255,255,0.5);
}

JSFiddle

可以直译为“

{{链接1:JSFiddle}}

”,其中保留了HTML标记和变量。

0

这只是eyelidlessness答案的一个修改,因为我看到了相同的函数两次

var pad = function(num, totalChars) {
    var pad = '0';
    num = num + '';
    while (num.length < totalChars) {
        num = pad + num;
    }
    return num;
};

// Ratio is between 0 and 1
var changeColor = function(color, ratio, darker) {
    var difference = Math.round(ratio * 255) * (darker ? -1 : 1),
        minmax     = darker ? Math.max : Math.min,
        decimal    = color.replace(
            /^#?([a-z0-9][a-z0-9])([a-z0-9][a-z0-9])([a-z0-9][a-z0-9])/i,
            function() {
                return parseInt(arguments[1], 16) + ',' +
                    parseInt(arguments[2], 16) + ',' +
                    parseInt(arguments[3], 16);
            }
        ).split(/,/);
    return [
        '#',
        pad(minmax(parseInt(decimal[0], 10) + difference, 0).toString(16), 2),
        pad(minmax(parseInt(decimal[1], 10) + difference, 0).toString(16), 2),
        pad(minmax(parseInt(decimal[2], 10) + difference, 0).toString(16), 2)
    ].join('');
};
var lighterColor = function(color, ratio) {
    return changeColor(color, ratio, false);
};
var darkerColor = function(color, ratio) {
    return changeColor(color, ratio, true);
};

// Use
var darker = darkerColor('#404040', .2);
var lighter = lighterColor('#404040', .2);

然后第二个参数将是255。嘿,我更新了我的支持RGB(A)。 - eyelidlessness
...仍然有问题!你在minmax调用中缺少了darker ? 0 : 255条件,因此大部分时间它会产生黑色! - Mrchief

0

可能你错过了http://www.safalra.com/web-design/javascript/colour-handling-and-processing/。它支持HSV和HSL颜色,并且可以在它们之间以及RGB值之间进行转换。

HSV和HSL是更加“人类友好”的颜色表示方式,因此使用它们可以非常简单地制作浅色、深色、更或者不那么强烈的颜色,或者找到对比度最好的颜色。


0

也许 jquery.colorhelpers.js 中的比例和添加函数会有所帮助? 我正在尝试寻找比 flot 源代码中内联示例更好的示例。


那个库没有依赖于jQuery,但仍然决定污染$命名空间? - Cobby

0

我发现了一种只用CSS的方法,与Wander Nauta的解决方案类似,但不使用图片。如果您可以更改HTML,则可以在要更改的区域后面放置一个div,并将原始颜色设置为背景。然后,您可以使用半透明的白色或黑色背景设置您关注的区域,从而使元素变亮或变暗。

我猜它有其局限性,但它对我非常有效。


此外,如果你只想要减轻权重,而不关心 IE<8,只需在悬停时设置不透明度值即可。 - Scott Mermelstein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接