Refactoring the JavaScript Color Picker – Step 1: Clean up the HTML and CSS

On of the most popular posts on this blog was a color picker (demo) I created about 4 years ago and then released 2 years ago. It was based on the Prototype library which at the time was the only major mega-JavaScript library. Since then, others have ported the color picker to jQuery, MooTools, YUI, and other libraries, and it’s popularity can be seen by searching for “javascript color picker” on Google.

The Original Color Picker (mimics Photoshop)

Color Picker Example

Rebuilding Goals

If the original color picker was popular, it was because of it’s functionality, not so much pretty code. So, I’d like to rebuild the color picker with a few goals in mind:

  1. Be library independent – I’ll have to add a little bit of extra code for things like event management, but this will allow it to work for everyone.
  2. Small and fast – The original JavaScript isn’t too slow, but the color picker uses lots of separate images (27!). Originally, I hid these inside a <div> so that the browser would keep them cached, but I’d like to combine them into a few sprites to speed up the load time.
  3. Clean up the HTML/CSS – The original has a lot of inline styles and unnecessary complexity, making it ugly and unwieldy.
  4. Clean up the JavaScript – The original code separated out some functionality which makes it harder to figure out what’s going on. I plan bring these together, so that I have one class for color conversion, one class for slider functionality, and one class for the color picker. The new code will also include code to function as a plugin to the major existing libraries (jQuery, Prototype, Mootools, YUI, etc.).

The first big step is to clean up the HTML and CSS. To get a feel for the old HTML/CSS, check out the version 1 example page. Here’s what I’ve come up with so far:

Color Picker CSS

.color-picker
    { border: 0; padding: 0; margin: 0; font-family: Tahoma; font-size: 12px;}
.color-picker table, .color-picker td
    { border: 0; margin: 0; padding: 0; vertical-align: top;}   
.color-picker label
    { margin: 4px 0; display: block;}
.cp-container
    { position: relative; float: left; border: solid 1px #000; padding: 0px; }
.cp-layer1, .cp-layer2, .cp-layer3, .cp-layer4
    { display: block; position: absolute; top: 0px; left: 0px; }   
.cp-map
    { width: 256px; height: 256px; margin: 0px; }
.cp-map div
    { width: 256px; height: 256px; position: absolute; top: 0; left: 0; background: transparent url(maps.png) 0px 0px no-repeat;}
.cp-bar
    { width: 20px; height: 256px; margin: 0px 9px;}
.cp-bar div
    { width: 20px; height: 256px; position: absolute; top: 0; left: 0; background: transparent url(bars.png) 0px 0px no-repeat;}
.cp-preview
    { width: 60px; height: 60px; padding: 0px; margin: 0px; border: solid 1px #000; }
.cp-hsv, .cp-rgb
    { width: 40px; }
.cp-hex
    { width: 55px; }
.cp-map-arrow
    { background: transparent url(map-arrow.gif) 0px 0px no-repeat; width: 40px; height: 9px; position: absolute;}
.cp-bar-arrow
    { background: transparent url(bar-arrow.gif) 0px 0px no-repeat; width: 15px; height: 15px; position: absolute;}

Color Picker HTML

<div id=”cp1″ class=”color-picker”>
    <table cellpadding=”0″>
    <tbody><tr>
        <td>
            <div class=”cp-container cp-map”>
                <div class=”cp-layer1″></div>
                <div class=”cp-layer2″></div>       
            </div>
        </td>
        <td>
            <div class=”cp-container cp-bar”>
                <div class=”cp-layer1″></div>
                <div class=”cp-layer2″></div>
                <div class=”cp-layer3″></div>
                <div class=”cp-layer4″></div>                   
            </div>
        </td>
        <td valign=”top”>
            <table><tbody>
            <tr>
                <td colspan=”3″>
                    <div class=”cp-preview”></div>
                </td>
            </tr>
            <tr>
                <td><input type=”radio” /></td>
                <td><label>H:</label></td>
                <td><input class=”cp-hsv” type=”text” /> &#176;</td>
            </tr>
            <tr>
                <td><input type=”radio” /></td>
                <td><label>S:</label></td>
                <td><input class=”cp-hsv” type=”text” /> %</td>
            </tr>
            <tr>
                <td><input type=”radio” /></td>
                <td><label>B:</label></td>
                <td><input class=”cp-hsv” type=”text” /> %</td>
            </tr>
            <tr>
                <td><input type=”radio” /></td>
                <td><label>R:</label></td>
                <td><input class=”cp-rgb” type=”text” /></td>
            </tr>
            <tr>
                <td><input type=”radio” /></td>
                <td><label>G:</label></td>
                <td><input class=”cp-rgb” type=”text” /></td>
            </tr>
            <tr>
                <td><input type=”radio” /></td>
                <td><label>B:</label></td>
                <td><input class=”cp-rgb” type=”text” /></td>
            </tr>
            <tr>
                <td>#</td>
                <td colspan=”2″>
                    <input class=”cp-hex” type=”text” />
                </td>
            </tr>
        </tbody></table>
        </td>
    </tr></tbody>
    <div class=”cp-map-arrow”></div>
    <div class=”cp-slider-arrow”></div>
</div>

Cleanup Comments

To make it more readable, I’ve removed all the id attributes except for the single id on the containing div, taken out all inline styles, and moved the CSS to a separate file. I also changed the layers to <div> tags with background images instead of <img> tags. This may present some problems with IE6 opacity down the road, so I might need to change it back. I’ve also removed z-index values from the CSS to prevent problems with other JavaScript controls on the page. I was not careful with DOCTYPE in the past, but the new HTML and CSS should work in any DOCTYPE (I’ll be using the HTML5 DOCTYPE in all the examples). Finally, the arrows are created using <div> that are inside the main block, which will make it easer to show and hide the entire color picker.

Bar Sprite

As a preview, I’m including the sprite for the value bar of the color picker. This combines 14 different bars into one 1.77KB file. Next time, we’ll talk about memory consumption and sprites and see if the sprite usage is actually helpful.

new color bars sprite

10 thoughts on “Refactoring the JavaScript Color Picker – Step 1: Clean up the HTML and CSS

  1. Very cool. thanks for all the hard work, I find your color picker very useful.
    I think all the HTML for the color picker shouldn’t be in the actual HTML, but inserted into the DOM from javascript code.
    the only HTML would be <div id="colorpicker"></div>, than passing the div element to the script which would create all the HTML needed

  2. It appears that you’ve put a good amount of effort into your article and I require a lot more of these on the web these days. I sincerely got a kick out of your post. I do not have a bunch to to say in reply, I only wanted to register to say tremendous work.

  3. How do send the color hex value to my form input. I want the user select the code and the code will be stored in mysql so that it can be used as a template color for that user. Just need to know how to get the code from javas to form input.

  4. It seems to be very usefull, but the link is dead .. Only the old one demo works, which is usefull but quite old code. Are You thinking about porting this to Jquery ?

  5. Thanks brother
    your colorpicker rocks !
    I have a small question for you
    Like you set the default hex value is it possible to set the default Saturation and Luminosity (or B) Values ?
    thanks a lot — hope to hear back from you

    1. Hey brother
      please ignore my previous question.. i just figured out that specifying a default hex in itself does define the default HSV values.
      Comes after gap but i am intelligent, you see 🙂

Comments are closed.