Introduction
In CSS, HTML, WPF XAML, and many other files, color is specified in the following forms:
- a color name - like red
- '#' followed by 6-bit hex value - like #123456
- '#' followed by 3-bit hex value - like #123, which will be expanded to #112233 by system
- rgb color - like RGB(255, 0, 0)
I found many times, especially when I read other's code, I have to figure out which color these numbers really represent. So, I developed a JavaScript color viewer, which can be downloaded and used in your local computer. An online version can also be found here.
Background
The color is entered dynamically by the user. The program has no idea of what it will be in advance. However, the program has to pick a color for the foreground text. No matter which color we pick, it could be the same as the background color, so we could not be able to see it. For that reason, we need to use at least two contrast colors for the text. In the program, we use black or white as the text color. And use a function to calculate background color brightness based on its RGB value. The function is based on this article which refers to this article.
We can also display text below the color block and use black as the only text color. But I feel that makes this program quite boring.
Using the Code
The program has 3 files, one HTML file, one JavaScript file and one CSS file. The HTML file is easy, it is listed below:
<div id="controls">
<span>Color</span>
<input type="text" id="txt" size="30"/>
<input type="button" id="btn" value="Display"/>
</div>
<div id="message">Input is invalid!</div>
<div id="view"></div>
The "message
" is displayed when user entered some invalid color. The "view
" is where the color blocks will be inserted.
The JavaScript file contains the following parts:
- Two text brightness calculation functions
- A text parser, which is used to parse the input text, validate it, and find RGB channel values
- A display function, which insert squares into the HTML DOM tree
The JavaScript code to calculate the color brightness from RGB channel is:
function getTextColor2(red, green, blue) {
var brightness = ((red * 299) + (green * 587) + (blue * 114)) / 1000;
if(brightness < 125) {
return 'white';
} else {
return 'black';
}
}
In my humble opinion, for programmers, knowing this function exists is more important than knowing why it works. However, if you really want to know why, please refer to the previously mentioned articles to see the details.
You can also calculate the brightness from hex values:
function getTextColor(hex) {
if(hex.length == 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
var red = parseInt(hex.substring(0, 2), 16);
var green = parseInt(hex.substring(2, 4), 16);
var blue = parseInt(hex.substring(4, 6), 16);
return getTextColor2(red, green, blue);
}
The 3-bit hex color value like #123 is expanded to #112233. JavaScript parseInt
function can take the second parameter, which is the radix (base) of the number to be parsed. The radix can be any number from 2 to 36. In our case, we use 16 to parse hex strings.
JavaScript has both substr
and substring
function. substr
is not in the ECMAScript standard. So, we are not using it here. However, substr
is supported by most web browsers. The usage of these 2 string
functions is:
s.substr(start, length)
s.substr(start) // to end
s.substring(start, end) // 2 indices
The difference is substr
goes from an index to some length, and substring
goes from index to index. The way I remember it is: "ing" of substring is index.
The text parser uses the following regular expression to parse the input.
var regHex6 = /^#?([a-f\d]{6})$/;
var regHex3 = /^#?([a-f\d]{3})$/;
var regRgb = /^rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/;
The beginning "#" is optional for hex input, this is for some lazy people like me. \d{1,3} means a digit repeat 1, 2 or 3 times.
The text parser also needs a giant dictionary "standardColors
" to check all the standard colors. This dictionary is at the end of the JavaScript file and not listed here. The parser will check whether the color exists, and what is the hex value of the color, so the program can calculate the text color.
The code for text parser is below, it returns an object of 2 properties. One property, text
, will be displayed as the foreground text. The other property, textColor
, will be either black or white, which is calculated from previously mentioned brightness functions and will be used as the text color. The 3 regular expressions will be used to match the input one by one, if no one matches, the function will assume the input is a color name. And the "standardColors
" dictionary will be checked.
function parseInput(text) {
var textLower = text.trim().toLowerCase();
var result = textLower.match(regHex6);
var hex;
if(result) {
hex = result[1];
return {
text: '#' + hex,
textColor: getTextColor(hex)
};
}
result = textLower.match(regHex3);
if(result) {
hex = result[1];
return {
text: '#' + hex,
textColor: getTextColor(hex)
};
}
result = textLower.match(regRgb);
if(result) {
var red = result[1];
var green = result[2];
var blue = result[3];
if(red < 256 && green < 256 && blue < 256) {
return {
text: 'RGB(' + red + ', ' + green + ', ' + blue + ')',
textColor: getTextColor2(red, green, blue)
};
}
}
hex = standardColors[textLower];
if(hex) return {
text: textLower,
textColor: getTextColor(hex)
};
return null;
}
Finally, after user entered the color, the following function inserts a color block into the HTML DOM.
var displayColor = function() {
var result = parseInput(txt.value);
if(result) {
msg.style.display = "none";
view.innerHTML =
'<div class="' + result.textColor + '">' +
'<div class="inner">' +
'<span>' + result.text + '</span>' +
'</div>' +
'</div>' + view.innerHTML;
view.firstChild.style.backgroundColor = result.text;
txt.value = "";
} else {
msg.style.display = "block";
}
};
view is a <div>
element in HTML file. The following line adds a new block into the view.
view.innerHTML = [something] + view.innerHTML;
The inserted <div>
elements will be displayed according to the CSS file, which is listed below:
#view > div {
width: 100px;
height: 100px;
margin: 5px;
float: left;
display: table;
text-align: center;
font-weight: bold;
font-size: 16px;
font-family: "Courier New";
}
.white {
color: white;
}
.black {
color: black;
border: 1px solid #eee;
}
.inner {
display: table-cell;
vertical-align: middle;
}
To vertically center the text display, the outer <div>
uses the style display: table;
, and inner <div>
uses the style display: table-cell;
and vertical-align: middle;
. This works for most browsers.
Points of Interest
The displayColor
function has a lot of string
plus operations. In the first draft, I used a string
format function, which makes the code much cleaner. It works in most browsers. However, Internet Explorer just doesn't like it for some unknown reason. My string
format function is listed here:
String.prototype.format = function() {
var result = this;
for(arg in arguments) {
result = result.replace("{" + arg + "}", arguments[arg]);
}
return result;
};
If you know why this function doesn't work on Internet Explorer, please let me know.
History
- First version: May 19, 2011