reptile7's JavaScript blog
Wednesday, August 08, 2007
 
Dialing for Colors
Blog Entry #84

Visual browsers are capable of rendering a broad array of nice colors on a Web page, and the CSS background-color property can theoretically apply these colors to "all" HTML elements. In choosing a color for this or that purpose, I for my part would consult the color chart of HTML Goodies' "So, You Want A Basic Color Code, Huh?" or perhaps Wikipedia's List of colors. You, however, might be a DIY-type who would rather create your own colors; HTML Goodies' JavaScript Script Tips #65, #66, #67, and #68, our focus for the next few posts, discuss a pair of related scripts that will help you do just that.

The W3C has deprecated all of HTML's color-related attributes - e.g., the color attribute of the font element and the bgcolor attribute of the body element - and recommends that Web page colors (more generally, colors for any visual media type) be set via CSS. For specifying colors and color values, both HTML and CSS use an additive color model in which red (R), green (G), and blue (B) are primary colors and are combined to give other colors.

Joe takes a not-so-successful stab at a description of the RGB color space in HTML Goodies' "A Quick Color Explanation". This article does not meaningfully distinguish between additive color and subtractive color, incorrectly states that red, blue, and yellow (Y) are "the" primary colors (when defined strictly, R, B, and Y collectively are not primary colors even in a subtractive sense), and misleadingly labels green a "composite color" (this can be true in a subtractive sense but is not true with respect to the additive RGB model). But perhaps I should cut Joe some slack here - the science of color and its perception is not so easily picked up on the fly. And do check out the article's "Basic Hexadecimal Notation" section, which is worth reading.

In their effects, the Script Tips #65-68 Scripts emulate a device that uses 24 bits per screen pixel - 1 byte each for R, G, and B - to display color. The scripts code separate "Red", "Green", and "Blue" selection lists, each comprising 256 options. For these lists:
(a) the contents of the option elements are three-digit decimal numbers running from 000 to 255, inclusive, and
(b) the values of the option elements are the corresponding two-digit hexadecimal numbers running from 00 to ff, inclusive, e.g.:

<option value='0a'>010</option>
<!-- The corresponding bit sequence would be: 00001010 -->

The user makes selections from the Red, Green, and/or Blue menus; the values of the user's chosen or unchosen options from all three menus are concatenated and appended to a number sign (#) to give a hexadecimal #RRGGBB color value.
(1) Script Tips #65-67 cover a script that was written specifically for Internet Explorer and that assigns the #RRGGBB value to the CSS background(-color) property of a td (table cell) element.
(2) In Script Tip #68, Joe presents a cross-browser script that assigns the #RRGGBB value to the bgColor property of the document object.

The Script Tips #65-67 Script

The main script of Script Tips #65-67 can be accessed via the "Here's the Code" links in all three script tips and is reproduced in the div below:

<script language="javascript">

// This javascript is property of the Silicon Valley Garage.

function mix( )
{
if (document.all)
{
document.all("box").style.background = "#" + document.ColorMix.red.options[document.ColorMix.red.selectedIndex].value + document.ColorMix.green.options[document.ColorMix.green.selectedIndex].value + document.ColorMix.blue.options[document.ColorMix.blue.selectedIndex].value;

document.ColorMix.code.value = "#" + document.ColorMix.red.options[document.ColorMix.red.selectedIndex].value + document.ColorMix.green.options[document.ColorMix.green.selectedIndex].value + document.ColorMix.blue.options[document.ColorMix.blue.selectedIndex].value;
}
else
{
alert("Sorry, your browser does not support the programming needed to run this script.");
}
}

if (document.all)
{
var menu = "
<option value=\"ff\">255</option>
<option value=\"fe\">254</option>
<option value=\"fd\">253</option>
<option value=\"fc\">253</option>
<option value=\"fb\">252</option>
<option value=\"fa\">251</option>
<option value=\"f9\">250</option>
<option value=\"f8\">249</option>
<option value=\"f7\">248</option>
<option value=\"f6\">247</option>
<option value=\"f5\">246</option>
<option value=\"f4\">245</option>
<option value=\"f3\">244</option>
<option value=\"f2\">243</option>
<option value=\"f1\">242</option>
<option value=\"f0\">241</option>
<option value=\"ef\">240</option>
<option value=\"ee\">239</option>
<option value=\"ed\">238</option>
<option value=\"ec\">237</option>
<option value=\"eb\">236</option>
<option value=\"ea\">234</option>
<option value=\"e9\">233</option>
<option value=\"e8\">232</option>
<option value=\"e7\">231</option>
<option value=\"e6\">230</option>
<option value=\"e5\">229</option>
<option value=\"e4\">228</option>
<option value=\"e3\">227</option>
<option value=\"e2\">226</option>
<option value=\"e1\">225</option>
<option value=\"e0\">224</option>
<option value=\"df\">223</option>
<option value=\"de\">222</option>
<option value=\"dd\">221</option>
<option value=\"dc\">220</option>
<option value=\"db\">219</option>
<option value=\"da\">218</option>
<option value=\"d9\">217</option>
<option value=\"d8\">216</option>
<option value=\"d7\">215</option>
<option value=\"d6\">214</option>
<option value=\"d5\">213</option>
<option value=\"d4\">212</option>
<option value=\"d3\">211</option>
<option value=\"d2\">210</option>
<option value=\"d1\">209</option>
<option value=\"d0\">208</option>
<option value=\"cf\">207</option>
<option value=\"ce\">206</option>
<option value=\"cd\">205</option>
<option value=\"cc\">204</option>
<option value=\"cb\">203</option>
<option value=\"ca\">202</option>
<option value=\"c9\">201</option>
<option value=\"c8\">200</option>
<option value=\"c7\">199</option>
<option value=\"c6\">198</option>
<option value=\"c5\">197</option>
<option value=\"c4\">196</option>
<option value=\"c3\">195</option>
<option value=\"c2\">194</option>
<option value=\"c1\">193</option>
<option value=\"c0\">192</option>
<option value=\"bf\">191</option>
<option value=\"be\">190</option>
<option value=\"bd\">189</option>
<option value=\"bc\">188</option>
<option value=\"bb\">187</option>
<option value=\"ba\">186</option>
<option value=\"b9\">185</option>
<option value=\"b8\">184</option>
<option value=\"b7\">183</option>
<option value=\"b6\">182</option>
<option value=\"b5\">181</option>
<option value=\"b4\">180</option>
<option value=\"b3\">179</option>
<option value=\"b2\">178</option>
<option value=\"b1\">177</option>
<option value=\"b0\">176</option>
<option value=\"af\">175</option>
<option value=\"ae\">174</option>
<option value=\"ad\">173</option>
<option value=\"ac\">172</option>
<option value=\"ab\">171</option>
<option value=\"aa\">170</option>
<option value=\"a9\">169</option>
<option value=\"a8\">168</option>
<option value=\"a7\">167</option>
<option value=\"a6\">166</option>
<option value=\"a5\">165</option>
<option value=\"a4\">164</option>
<option value=\"a3\">163</option>
<option value=\"a2\">162</option>
<option value=\"a1\">161</option>
<option value=\"a0\">160</option>
<option value=\"9f\">159</option>
<option value=\"9e\">158</option>
<option value=\"9d\">157</option>
<option value=\"9c\">156</option>
<option value=\"9b\">155</option>
<option value=\"9a\">154</option>
<option value=\"99\">153</option>
<option value=\"98\">152</option>
<option value=\"97\">151</option>
<option value=\"96\">150</option>
<option value=\"95\">149</option>
<option value=\"94\">148</option>
<option value=\"93\">147</option>
<option value=\"92\">146</option>
<option value=\"91\">145</option>
<option value=\"90\">144</option>
<option value=\"8f\">143</option>
<option value=\"8e\">142</option>
<option value=\"8d\">141</option>
<option value=\"8c\">140</option>
<option value=\"8b\">139</option>
<option value=\"8a\">138</option>
<option value=\"89\">137</option>
<option value=\"88\">136</option>
<option value=\"87\">135</option>
<option value=\"86\">134</option>
<option value=\"85\">133</option>
<option value=\"84\">132</option>
<option value=\"83\">131</option>
<option value=\"82\">130</option>
<option value=\"81\">129</option>
<option value=\"80\">128</option>
<option value=\"7f\">127</option>
<option value=\"7e\">126</option>
<option value=\"7d\">125</option>
<option value=\"7c\">124</option>
<option value=\"7b\">123</option>
<option value=\"7a\">122</option>
<option value=\"79\">121</option>
<option value=\"78\">120</option>
<option value=\"77\">119</option>
<option value=\"76\">118</option>
<option value=\"75\">117</option>
<option value=\"74\">116</option>
<option value=\"73\">115</option>
<option value=\"72\">114</option>
<option value=\"71\">113</option>
<option value=\"70\">112</option>
<option value=\"6f\">111</option>
<option value=\"6e\">110</option>
<option value=\"6d\">109</option>
<option value=\"6c\">108</option>
<option value=\"6b\">107</option>
<option value=\"6a\">106</option>
<option value=\"69\">105</option>
<option value=\"68\">104</option>
<option value=\"67\">103</option>
<option value=\"66\">102</option>
<option value=\"65\">101</option>
<option value=\"64\">100</option>
<option value=\"63\">099</option>
<option value=\"62\">098</option>
<option value=\"61\">097</option>
<option value=\"60\">096</option>
<option value=\"5f\">095</option>
<option value=\"5e\">094</option>
<option value=\"5d\">093</option>
<option value=\"5c\">092</option>
<option value=\"5b\">091</option>
<option value=\"5a\">090</option>
<option value=\"59\">089</option>
<option value=\"58\">088</option>
<option value=\"57\">087</option>
<option value=\"56\">086</option>
<option value=\"55\">085</option>
<option value=\"54\">084</option>
<option value=\"53\">083</option>
<option value=\"52\">082</option>
<option value=\"51\">081</option>
<option value=\"50\">080</option>
<option value=\"4f\">079</option>
<option value=\"4e\">078</option>
<option value=\"4d\">077</option>
<option value=\"4c\">076</option>
<option value=\"4b\">075</option>
<option value=\"4a\">074</option>
<option value=\"49\">073</option>
<option value=\"48\">072</option>
<option value=\"47\">071</option>
<option value=\"46\">070</option>
<option value=\"45\">069</option>
<option value=\"44\">068</option>
<option value=\"43\">067</option>
<option value=\"42\">066</option>
<option value=\"41\">065</option>
<option value=\"40\">064</option>
<option value=\"3f\">063</option>
<option value=\"3e\">062</option>
<option value=\"3d\">061</option>
<option value=\"3c\">060</option>
<option value=\"3b\">059</option>
<option value=\"3a\">058</option>
<option value=\"39\">057</option>
<option value=\"38\">056</option>
<option value=\"37\">055</option>
<option value=\"36\">054</option>
<option value=\"35\">053</option>
<option value=\"34\">052</option>
<option value=\"33\">051</option>
<option value=\"32\">050</option>
<option value=\"31\">049</option>
<option value=\"30\">048</option>
<option value=\"2f\">047</option>
<option value=\"2e\">046</option>
<option value=\"2d\">045</option>
<option value=\"2c\">044</option>
<option value=\"2b\">043</option>
<option value=\"2a\">042</option>
<option value=\"29\">041</option>
<option value=\"28\">040</option>
<option value=\"27\">039</option>
<option value=\"26\">038</option>
<option value=\"25\">037</option>
<option value=\"24\">036</option>
<option value=\"23\">035</option>
<option value=\"22\">034</option>
<option value=\"21\">033</option>
<option value=\"20\">032</option>
<option value=\"1f\">031</option>
<option value=\"1e\">030</option>
<option value=\"1d\">029</option>
<option value=\"1c\">028</option>
<option value=\"1b\">027</option>
<option value=\"1a\">026</option>
<option value=\"19\">025</option>
<option value=\"18\">024</option>
<option value=\"17\">023</option>
<option value=\"16\">022</option>
<option value=\"15\">021</option>
<option value=\"14\">020</option>
<option value=\"13\">019</option>
<option value=\"12\">018</option>
<option value=\"11\">017</option>
<option value=\"10\">016</option>
<option value=\"0f\">015</option>
<option value=\"0e\">014</option>
<option value=\"0d\">013</option>
<option value=\"0c\">012</option>
<option value=\"0b\">011</option>
<option value=\"0a\">010</option>
<option value=\"09\">009</option>
<option value=\"08\">008</option>
<option value=\"07\">007</option>
<option value=\"06\">006</option>
<option value=\"05\">005</option>
<option value=\"04\">004</option>
<option value=\"03\">003</option>
<option value=\"02\">002</option>
<option value=\"01\">001</option>
<option selected value=\"00\">000</option>";
document.write("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">");
document.write("<form name=\"ColorMix\">");
document.write("<td bgcolor=\"#000000\" height=\"25\" id=\"box\" colspan=\"4\"></td><tr>");
document.write("<td width=\"25%\"><font color=\"#ffffff\" face=\"arial, geneva, times new roman\" size=\"2\"><b>Red: </b></font><select name=\"red\" onchange=\"mix( );\" size=\"1\">" + menu + "</select></td><td width=\"25%\"><font color=\"#ffffff\" face=\"arial, geneva, times new roman\" size=\"2\"><b>Green: </b></font><select name=\"green\" onchange=\"mix( );\" size=\"1\">" + menu + "</select></td><td width=\"25%\"><font color=\"#ffffff\" face=\"arial, geneva, times new roman\" size=\"2\"><b>blue: </b></font><select name=\"blue\" onchange=\"mix( );\" size=\"1\">" + menu + "</select></td><td width=\"25%\"><input name=\"code\" maxlength=\"7\" size=\"10\" type=\"text\" value=\"#000000\"></td><tr>");
document.write("</form>");
document.write("</table>");
}
</script>

The Script Tips #65-67 Script comprises one large script element - there's no separation between the script's HTML and JavaScript. Relatedly, the script makes compulsive use of the \" escape sequence to quote HTML attribute values; the script would definitely be easier to read if the script's author(s) had used single quotes for this purpose. (The author could have simply written the code without any quotes, Joe remarks in Script Tip #65, but if we want the script to be XHTML-compliant, then the attribute values must be quoted.)

The Script Tips #65-67 Script's demo page is here. The script's display is housed in a two-row, five-cell table. The first table row, whose (required) tr element start-tag has sloppily been omitted, contains a contentless cell that spans the width of the browser window (because the parent table element's width attribute is set to %100):

document.write("<td bgcolor='#000000' height='25' id='box' colspan='4'></td>");

This cell will "receive the color" of the #RRGGBB value described above. As noted earlier, the td bgcolor attribute is now deprecated, as is the td height attribute; we'll write a style block for the Script Tips #65-67 Script in due course.

The four cells of the second table row each span 25% of the width of the browser window. The first three of these cells each have two immediate 'children':
(1) a (deprecated) font element containing a boldened Red, Green, or Blue label; and
(2) a select element containing the 000-to-255 set of options described above, e.g.:

document.write("<td width='25%'><font color='#ffffff' face='arial, geneva, times new roman' size='2'><b>Red: </b></font><select name='red' onchange='mix( );' size='1'>" + menu + "</select></td>");

Quick comments:
The td width attribute is deprecated.
• Bizarrely, the color attribute of the font element is set to white; consequently, the Red/Green/Blue labels will be 'invisible' unless the user's default browser background color is set to a non-white color.

All of the selection list options are lumped into a single, humongously long string that is variabilized with the identifier menu. Notwithstanding menu's appearance on the "Here's the Code" page and in the iframe above, the menu string must be all on one command line (check the demo page's source), or the browser will throw an error:

Unterminated string constant error message

Specifically, you'll see this error when using MSIE but not when using Netscape - we'll explain why in just a bit. JavaScript can be surprisingly tolerant of line breaks (we demonstrated this early on in Blog Entry #3), but strings in JavaScript cannot contain line breaks. It's rather odd that Joe doesn't make a 'You need to put this all on one line' comment here, given his penchant for doing so.

Anyway, menu is plugged into all three select elements and thus the menu option string need only appear once in the script. Of course, the menu string itself might still be too long for your tastes, and we'll detail an automated generation of the select element options in a subsequent post.

The last cell in the second table row contains a text field -

<input name='code' maxlength='7' size='10' type='text' value='#000000' />

- to which the #RRGGBB color value will also be written.

When the page loads: MSIE vs. Netscape

The script's display differs radically depending on whether the user's browser is MSIE or not. The menu options and the document.write( ) commands that write the display table to the page sit in a

if (document.all) { ... }

conditional. The document.all condition references the proprietary, MSIE-specific all collection/property of the document object. We'll have more to say about the all collection in the following entry, but for our present purposes, the if (document.all) command line merely tests the browser's support for the all collection; if the user is using MSIE4+, then document.all converts to true and the display table renders normally.

For non-MSIE4+ browsers, the document.all condition converts to false. (On my computer, Netscape 7.02 returns undefined for document.all, although JavaScript Kit claims that the return here should be null. However, both undefined and null convert to false in a Boolean context.) So what happens? The browser skips over the if (document.all) { ... } block, which runs to the end of the script and is not followed by an alternate-code-containing else block. As a result, we see...nothing. Just a blank page.

The display table code is not MSIE-specific and thus there's no point in enveloping it with the if (document.all), {, and } command lines, which should be removed so that the non-MSIE4+ folks can at least see the script's initial display, even if they can't make subsequent use of the script as originally written.

We'll go through the 'action' parts of the Script Tips #65-68 Scripts in the next entry.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)