验证CSS颜色名称

27

我编写了一个jQuery插件,其中一些参数接受css颜色。

我想要验证这些颜色。如果只是十六进制或rgb值,我可以用正则表达式来做到这一点,但是如何验证所有147种有效的颜色名称而不会使插件变得臃肿呢?

我在想是否有一种方法尝试应用样式(也许是使用jquery),然后从浏览器捕获错误(如果不是有效的话)?

编辑:powtac和Pantelis提出了一种解决方案,但他们都错过了一些边缘情况,所以我在此包含了完整的解决方案:

var validateCssColour = function(colour){
    var rgb = $('<div style="color:#28e32a">');     // Use a non standard dummy colour to ease checking for edge cases
    var valid_rgb = "rgb(40, 227, 42)";
    rgb.css("color", colour);
    if(rgb.css('color') == valid_rgb && colour != ':#28e32a' && colour.replace(/ /g,"") != valid_rgb.replace(/ /g,""))
        return false;
    else
        return true;
};

非常有趣的问题。我喜欢它。 - Patricia
我以为只有17个(算上橙色)? - kennebec
@kennebec:请参阅http://www.w3schools.com/css/css_colornames.asp。 - SystemicPlural
由于新的CSS.supports API可用于此操作,因此重复了如何检查浏览器是否支持CSS值? - Sebastian Simon
8个回答

31

我知道这个问题很旧,但我提出了一种使用纯 JavaScript 解决方案来检查颜色的方法,似乎可以在每个浏览器中运行,并且想分享一下。

此函数使用浏览器将任何输入字符串转换为 CSS 颜色字符串(如果可能)

function getColorCSS(c) {
    const ele = document.createElement("div");
    ele.style.color = c;
    return ele.style.color.replace(/\s+/,'').toLowerCase();
}

更新: 使用浏览器自身渲染颜色字符串的美妙之处在于它可以继续处理新的格式,比如8位16进制(其中最后2位表示透明度)...

eight digit hex example


让我们来看一下根据不同输入而生成的函数输出...

无效输入

基本上,任何时候浏览器都不能将输入字符串解释为颜色时,将返回空字符串,这使得这个小函数非常适合检测无效的颜色字符串!

  • redd, #f0gf0g, #1234, f00, rgb(1,2), rgb(1,2,3.0), rgb(1,2,3,4), rgba(100,150,200)

    • . . . chrome
    • . . . firefox
    • . . . internet explorer

 

有效输入

  • tomato

    • tomato . . . chrome
    • tomato . . . firefox
    • tomato . . . internet explorer

 

  • #f00, #ff0000, rgb(255,0,0)

    • rgb(255,0,0) . . . chrome
    • rgb(255,0,0) . . . firefox
    • rgb(255,0,0) . . . internet explorer

 

  • rgba(255,0,0,1.0), rgba(255,0,0,100)

    • rgb(255,0,0) . . . ChromeFirefox会在alpha参数等于或大于1.0时将rgba转换为rgb,因为此时它已经完全不透明了,这可能是出于性能方面的考虑。
    • rgba(255,0,0,1) . . . Internet Explorer会将alpha参数从1.0或更大的值转换为1

 

  • rgba(0,255,0,0.5)

    • rgba(0,255,0,0.498039) . . . Chrome返回的结果与其他浏览器不同(可能是以精度换取性能)
    • rgba(0,255,0,0.5) . . . FirefoxInternet Explorer返回相同的结果

 

  • rgba(0,0,255,0.0), rgba(0,0,255,-100)

    • rgba(0,0,255,0) . . . ChromeFirefoxInternet Explorer会将alpha参数从0.0或更小的值转换为0
  • rgba(0,0,0,0), rgba(0,0,0,-100)

    • rgba(0,0,0,0)chrome中被解释为完全透明
    • firefox仅将所有参数设置为0的单个rgba实例转换为单词transparent(奇怪)
    • rgba(0,0,0,0)internet explorer中被解释为完全透明

 

  • hsl(180,50%,50%)

    • rgb(63,191,191)chrome中被解释为相应的hsl颜色
    • ff rgb(63,191,191)firefox中被解释为相应的hsl颜色
    • hsl(180,50%,50%)internet explorer中被解释为相应的rgb颜色

 

  • hsl(x,x,0%)

    • rgb(0,0,0)chrome中被解释为相应的hsl颜色
    • rgb(0,0,0)firefox中被解释为相应的hsl颜色
    • hsl(0,0%,0%)internet explorer中被用来表示任何blackhsl表示形式

 

  • hsl(x,x,100%)

    • rgb(255,255,255)chrome中被解释为相应的hsl颜色
    • rgb(255,255,255)firefox中被解释为相应的hsl颜色
    • hsl(0,0%,100%)internet explorer中被用来表示任何whitehsl表示形式
  • hsla(180,50%,50%,1.0), hsla(180,50%,50%,100)

    • rgba(63,191,191,1) . . . Chrome
    • rgba(63,191,191,1) . . . Firefox
    • hsla(180,50%,50%,1) . . . Internet Explorer

 

  • hsla(180,50%,50%,0.5)

    • rgba(63,191,191,0.498039) . . . Chrome
    • rgba(63,191,191,0.5) . . . Firefox
    • hsla(180,50%,50%,0.5) . . . Internet Explorer

 

  • hsla(0,0%,0%,0.0), hsla(0,0%,0%,-100)

    • rgba(0,0,0,0) . . . Chrome
    • transparent . . . Firefox is consistent but this conversion still seems strange
    • hsla(180,50%,50%,0) . . . Internet Explorer

function getColorCSS(c) {
    var ele = document.createElement("div");
    ele.style.color = c;
    return ele.style.color.split(/\s+/).join('').toLowerCase();
}

function isColorValid(c) {
    var s = getColorCSS(c);
    return (s) ? true : false;
}

function isColorTransparent(c) {
    var s = getColorCSS(c);
    return (
        s === "transparent" || 
        s.substring(0,4) === "rgba" && +s.replace(/^.*,(.+)\)/,'$1') <= 0 ||
        s.substring(0,4) === "hsla" && +s.replace(/^.*,(.+)\)/,'$1') <= 0
    );
}

function isColorWhite(c) {
    var s = getColorCSS(c);
    return [
        "white",
        "rgb(255,255,255)",
        "rgba(255,255,255,1)",
        "hsl(0,0%,100%)",
        "hsla(0,0%,100%,1)"
    ].indexOf(s) > -1;
}

function isColorBlack(c) {
    var s = getColorCSS(c);
    return [
        "black",
        "rgb(0,0,0)",
        "rgba(0,0,0,1)",
        "hsl(0,0%,0%)",
        "hsla(0,0%,0%,1)"
    ].indexOf(s) > -1;
}

function checkColorString() {
  var c = document.getElementById("c").value;
  
  if (c === "") {
    document.getElementsByTagName("body")[0].style.backgroundColor = 'transparent';
    document.getElementById("result").innerHTML = '';
  }
  else if (isColorValid(c)) {
    if (isColorTransparent(c)) {
      document.getElementsByTagName("body")[0].style.backgroundColor = 'transparent';
      document.getElementById("result").innerHTML = '<span style="color:#dadada;">TRANSPARENT</span>';
    }
    else if (isColorWhite(c)) {
      document.getElementsByTagName("body")[0].style.backgroundColor = getColorCSS(c);
      document.getElementById("result").innerHTML = '<span style="color:black;">WHITE</span>';
    }
    else if (isColorBlack(c)) {
      document.getElementsByTagName("body")[0].style.backgroundColor = getColorCSS(c);
      document.getElementById("result").innerHTML = '<span style="color:white;">BLACK</span>';
    }
    else {
      document.getElementsByTagName("body")[0].style.backgroundColor = getColorCSS(c);
      document.getElementById("result").innerHTML = getColorCSS(c);
    }
  }
  else {
    document.getElementsByTagName("body")[0].style.backgroundColor = 'transparent';
    document.getElementById("result").innerHTML = '<span style="font-size:42px;color:#dadada;">&#9785</span>';
  }
}

var eventList = ["change", "keyup", "paste", "input", "propertychange"];
for(event of eventList) {
    document.getElementById("c").addEventListener(event, function() {
      checkColorString();
    });
}
#c {
  width: 300px;
  padding: 6px;
  font-family: courier;
}

#result {
  font-family: courier;
  font-size: 24px;
  padding: 12px 6px;
}
<input id="c" placeholder="Enter any valid CSS color..."></input>
<div id="result"></div>


有一件事我不太明白... 为什么要用 str.split(/\s+/).join("") 而不是简单地使用 str.replace(/\s+/g, "") - Valen
如果有人真的不喜欢每次创建元素,可以尝试使用 document.head.style.color(但很遗憾,如果你的页面没有头部,这个方法就行不通了)。还有一种方法是:return [document.head.style.color = "I am color", document.head.style.color][1](我相信替换空格是不必要的)。 - Valen
好的,我已经更新了这个函数,改为使用替换而不是分割/连接。 - DaveAlger
@Valen - 也许替换空格有些过度,但由于我无法控制每个浏览器返回的内容,我认为最好删除空格以确保无效转换返回假值。 - DaveAlger

28

在这个页面上发布的所有解决方案都是错误的,当疑问字符串与测试颜色相同时。诚然,您可以选择非常不可能的颜色,但我更喜欢选择100%的成功率。

OP 在他的代码中有一个拼写错误(请参见带有冒号的条件),并且没有测试“#28e32a”,因此该颜色将失败,而正则表达式将折叠颜色内的空格,因此“#28e 32a”会(不正确地)通过。

在正常的 JavaScript 中,应该有100%的成功:

function validTextColour(stringToTest) {
    //Alter the following conditions according to your need.
    if (stringToTest === "") { return false; }
    if (stringToTest === "inherit") { return false; }
    if (stringToTest === "transparent") { return false; }

    var image = document.createElement("img");
    image.style.color = "rgb(0, 0, 0)";
    image.style.color = stringToTest;
    if (image.style.color !== "rgb(0, 0, 0)") { return true; }
    image.style.color = "rgb(255, 255, 255)";
    image.style.color = stringToTest;
    return image.style.color !== "rgb(255, 255, 255)";
}

JSFiddle:http://jsfiddle.net/WK_of_Angmar/xgA5C/


1
我喜欢你的思维方式,但这对于“rgb(0,0,0)”无法奏效。 - Simon Sarris
1
为什么你有最后两行而不是只有 return false 呢? - Simon Sarris
1
这是因为我错过了一行(请参见编辑)。最后两行基本上是针对“rgb(0,0,0)”的情况,无论是否有空格。换句话说,我们首先假设用户给出的颜色不是白色,因此如果图像的颜色发生了变化,则它是有效的输入。最后两行假设它可能是有效的输入,但它是白色的,因此图像的颜色应从黑色更改为其他颜色。 - Wk_of_Angmar
现在它应该适用于“rgb(0,0,0)” - 无论是否有空格。 - Wk_of_Angmar
这也会返回rgb(0, 0, 0的真值 - 即使) 缺失了。 - Miha Šušteršič
1
当输入 #000black 时仍然无法正常工作,你的函数存在种族主义错误。 - Sam

13

您可以将颜色设置为虚拟元素,然后检查该元素的值是否不是白色。

colorToTest = 'lime'; // 'lightgray' does not work for IE

$('#dummy').css('backgroundColor', 'white');
$('#dummy').css('backgroundColor', colorToTest);
if ($('#dummy').css('backgroundColor') != 'rgb(255, 255, 255)' || colorToTest == 'white') {
    alert(colorToTest+' is valid');
}

谢谢。我要进行一个修正;使用一种无法用三位十六进制或RGB表示的非标准颜色进行检查。你提供的代码对于colorToTest = '#fff'和'#ffffff'将失败。使用一种非标准颜色可以简化它。 - SystemicPlural
还需要在检查 RGB 值时包括去除空格。 - SystemicPlural
1
对此进行微调的方法是将color和backgroundColor字段都设置为新颜色。如果之后这两个CSS元素相同,则这是一种有效的颜色。 - robbrit

7

function test(myColor) {
  var valid = $('#test').css('color');

  $('#test').css('color', myColor);

  if (valid == $('#test').css('color')) alert("INVALID COLOR");
  else {
    alert("VALID");
    $('#test').css('color', valid);
  }
}


test("TATATA");
test("white");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="test">asdasdasdasd</div>

这段文本可能是匆忙书写的,但它确实有效。

2
失败于“black”... 但您可以检查:“if (color ==“black” ) OK else validation_code” - BrunoLM
是的,你说得百分之百正确。它失败是因为它检查的是 valid== $('#test').css('color'),而 black 是其默认值。可以按照你提到的方法来修复。谢谢! - Pantelis
谢谢。你的想法和powtacs一样。只是他比你早30秒到达,所以我授予了他信用。这是一个很好的解决方案。 - SystemicPlural

1

0

我认为你可以使用来自页面的脚本,它可以完全满足你的需求:你将一个字符串传递给它,然后它会尝试找出颜色。好吧,这不是你想要做的事情,但应该可以工作。

我认为无论如何,在某个时候你都应该进行名称查找(我不认为有什么神奇的方法可以从字符串“浅蓝色”中确定十六进制值),所以只需借鉴别人已经完成的工作(脚本由非常擅长JavaScript的Stoyan Stefanov编写,我读过他的一些好书,如果他进行了查找,那么我认为没有其他解决方案)。


0

疯狂的想法

function isValidCssColor(c){
    // put !! to normalize to boolean
    return [
            document.head.style.color = c,
            document.head.style.color,
            document.head.style.color = null
    ][1]; // split it in 3 lines is fine, see snippet
}

我相信它能正常工作(只有当您的页面没有元素时,它才无法工作,不知为何)

function isValidCssColor(c){
  document.head.style.color = c;
  let result = document.head.style.color;
  document.head.style.color = null;
  return result;
}

console.log(isValidCssColor("asdf"));       // <empty string>
console.log(isValidCssColor("black"));      // black
console.log(isValidCssColor("#abcdee"));    // rgb(171, 205, 238) // this is browser dependent I guess
console.log(isValidCssColor("asssdf"));     // <empty string>


这个不起作用。它只会返回最后一次成功调用的值。但我喜欢设置头元素颜色的想法! - Steve Bennett
@SteveBennett 容易修复 - Valen

0

简短的JavaScript版本

受Valen答案的启发:

v=c=>((s=document.head.style).color=c,q=s.color,s.color='',!!q);
// v('red') => true
// v('reeeed') => false

更易读:
const validColor = c => {
  document.head.style.color = c;
  const q = document.head.style.color;
  document.head.style.color = '';
  return !!q
};

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