开发者

Validating css color names

I've written a jQuery plugin that accepts css colors for some of its parameters.

I want to validate them. If it was just a hex or rgb value I could do that with a regular expression, but how do I validate all 147 valid color names without bloating the plugin?

I was wondering if there is some way of attempting to apply a style (maybe with jquery) and then catching an error from the browser if it is not valid?

Edit: powtac and Pantelis came up with a solution, but they both missed edge cases, so I am including a full solution here:

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;
};


I know this question is fairly old but I came up with a pure javascript solution for checking colors which seems to work in every browser and wanted to share it

This function uses the browser to convert any input string into a CSS color string (if possible)

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

UPDATE: The beauty of using the browser itself to render color strings is that it continues to work with newer formats like 8 digit hex (where the last 2 digits represent alpha)...

Validating css color names


Let's take a look at the function output based on different inputs...

INVALID INPUTS

Basically anytime the browser can't figure out how to render the input string as a color an empty string is returned which makes this tiny function perfect for detecting invalid color strings!

  • 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

 

VALID INPUTS

  • 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) . . . chrome converts rgba to rgb anytime alpha is 1.0 or greater since it's fully opaque anyway (probably for performance)
    • rgb(255,0,0) . . . firefox does the same thing as chrome
    • rgba(255,0,0,1) . . . internet explorer converts the alpha param from 1.0 or greater to 1

 

  • rgba(0,255,0,0.5)

    • rgba(0,255,0,0.498039) . . . chrome returns something different than the other browsers (possibly trading accuracy for performance)
    • rgba(0,255,0,0.5) . . . firefox
    • rgba(0,255,0,0.5) . . . internet explorer

 

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

    • rgba(0,0,255,0) . . . chrome converts the alpha param from 0.0 or lower to 0
    • rgba(0,0,255,0) . . . firefox does the same
    • rgba(0,0,255,0) . . . internet explorer does the same

 

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

    • rgba(0,0,0,0) . . . chrome
    • transparent . . . firefox converts only this one rgba instance with all parameters set to 0 to the word transparent (strange)
    • rgba(0,0,0,0) . . . internet explorer

 

  • hsl(180,50%,50%)

    • rgb(63,191,191) . . . chrome
    • ff rgb(63,191,191) . . . firefox
    • ie hsl(180,50%,50%) . . . internet explorer

 

  • hsl(x,x,0%)

    • rgb(0,0,0) . . . chrome
    • rgb(0,0,0) . . . firefox
    • hsl(0,0%,0%) . . . internet explorer converts any hsl representation of black to this

 

  • hsl(x,x,100%)

    • rgb(255,255,255) . . . chrome
    • rgb(255,255,255) . . . firefox
    • hsl(0,0%,100%) . . . internet explorer converts any hsl representation of white to this

 

  • 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

Wow, I can hardly believe I just spent 2 hours testing that function in different browsers!

I guess I may as well demo using the function while I'm at it...

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>


All of the solutions posted on this page are incorrect when the string in question is the same colour as the test colour. Granted, you could use a very unlikely choice of colour, but I would prefer to go for 100% success rate.

OP has a single typo in his code (see condition with colon), and does not test for "#28e32a", so that colour will fail, and the regex will collapse whitespace within the colour, so "#28e 32a" would (incorrectly) pass.

In normal JavaScript, this should have 100% success:

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/


You could simply set the color to a dummy element and then check if the element's value is something other than white.

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');
}


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>

It is hastily written but it works.


I think you can use the script from this page that does exactly what you want: you pass a string to it and tries to figure out the color. Ok, it's not exactly what you wanted to do but it should work.

I think that in any case at some point you should do a name lookup (i don't think there is some magic way to determine the hex value from the string "light blue") so just snatch the work some one else has done (the script is by Stoyan Stefanov which is very good at javascript, i've read some good books from him, and if he does a lookup, well, i don't think there is another solution)


Short JavaScript version

Inspired by Valen's answer:

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

More readably:

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


crazy thought

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
}

I believe it works (only not when your pages doesn't not have a head element, somehow)

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>


I'm arriving a little bit late but now I'm using validate-color library on npm

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜