Skip to content

August 2, 2013

Make Rainbow-Colored Lists (and other HTML elements) – jQuery plugin

How to make rainbow-colored lists? I started searching for a solution and found a plugin for rainbow text, which inspired me to write my own jQuery plugin to rainbow-ify lists and other sets of HTML elements.

I’m used to working with RGB hex color codes.  But there is no intuitive way to generate a spectrum of color using RGB, so I turned to HSL (hue, saturation and lightness).  Most modern browsers support colors specified with hsl(hue, saturation%, lightness%), although IE versions prior to 9 do not. So I started out using HSL, adding IE support later. I found that keeping the saturation and lightness constant at 100% and 80% respectively while increasing the hue in steps produces a really nice rainbow effect.

Let’s back up a bit. Consider the following styled list:

rainbow list w/o rainbow!

I’d like to color this list to look like a rainbow. Using CSS alone is unwieldy; without knowing in advance the number of elements in the list, it’s impossible.  We need to use Javascript to get this result:

rainbow-colored list

Here’s how I did it–my rainbow plugin code (~1KB when minified):

(function($) {
    'use strict';

    //the plugin function
    $.rainbow = $.fn.rainbow = function(options) {
        if (this.length !== 0) {
            //initialize settings & vars
            var settings = $.extend(
                {   hueStart:   0,
                    selector:   '> *',
                    saturation: 100,
                    lightness:  80,
                    rgb: true },
                options),
                $rainbowed  = this,
                //ensure values are within proper range
                hstart      = ensure(settings.hueStart, 0, Number.MAX_VALUE) % 360,
                sat         = ensure(settings.saturation, 0, 100),
                light       = ensure(settings.lightness, 0, 100);

            return $rainbowed.each(function() {
                var $selected   = $(this).find(settings.selector),
                    hue         = hstart,
                    step        = $selected.length === 0 ? 0 : 360 / ($selected.length);

                // iterate over selected elements to colorize
                $selected.each(function() {
                  if (!settings.rgb) {
                      $(this).css({'background-color': 'hsl('+ hue +', '+ sat +'%, '+ light +'%)',
                                   'border-color': 'hsl('+ hue +', '+ (sat / 2) +'%, '+ (light / 2) +'%)'});
                  }
                  else {
                      $(this).css({'background-color': hslToRgb(hue, sat, light),
                                   'border-color': hslToRgb(hue, sat / 2 , light / 2)});
                  }
                  hue += step;
                });
            });
        }
    };

    function ensure(val, min, max) {
        val = parseInt(val, 10);
        if (isNaN(val) || val < min)
            return min;
        else if (val > max)
            return max;
        else
            return val;
    }

    function hslToRgb(h, s, l) {
        var r, g, b;
        h = h / 360;
        s = s / 100;
        l = l / 100;

        if (s === 0)
            r = g = b = l; // achromatic
        else {
            var q = l < 0.5 ? l * (1 + s) : l + s - l * s,
                p = 2 * l - q;
            r = hue2rgb(p, q, h + 1 / 3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1 / 3);
        }

        return 'rgb('+ Math.round(r * 255) +','+ Math.round(g * 255) +','+ Math.round(b * 255) +')';
    }

    function hue2rgb(p, q, t) {
        if (t < 0) t += 1;
        if (t > 1) t -= 1;
        if (t < 1 / 6) return p + (q - p) * 6 * t;
        if (t < 1 / 2) return q;
        if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
        return p;
    }

})(jQuery);

This plugin accepts several optional arguments:

  • hueStart – a value from 0 to 360 representing the start of the rainbow, defaulted to 0 which is red.
  • selector – a jQuery selector that grabs the set of elements to colorize, defaulted to “> *”, i.e. all children.
  • saturation – a value from 0 to 100 representing the saturation percentage, defaulted to 100.
  • lightness – a value from 0 to 100 representing the lightness percentage, defaulted to 80.
  • rgb – a boolean value instructing the plugin to use CSS RGB syntax instead of HSL, defaulted to true.

Note that rgb = true requires some additional overhead to convert HSL to RGB, but is necessary if you are supporting IE versions prior to 9.  Credit for the conversion function goes to Mohsen @ SO.

This is the HTML for the list:

<ul id="rainbowList">
  <li>Java</li>
  <li>JavaScript</li>
  <li>PHP</li>
  <li>Python</li>
  <li>C#</li>
  <li>C++</li>
  <li>SQL</li>
  <li>Objective-C</li>
  <li>Visual Basic</li>
  <li>Ruby on Rails</li>
  <li>Scala</li>
  <li>jQuery</li>
  <li>HTML5</li>
</ul>

The initial CSS:

  #rainbowList    { list-style: none; width: 270px; margin: 10px; }
  #rainbowList li { background-color: #ddd;
                    border: 1px solid #999;
                    border-radius: 3px 3px 3px 3px;
                    color: #333;
                    padding: 3px 7px;
                    text-align: center;
                    text-decoration: none;
                    width: 200px;
                    font: bold 1em Georgia,serif;
                    margin: 6px; }

And calling the plugin to turn it from gray to rainbow:

$(document).ready(function() {
    $('#rainbowList').rainbow();
});

Notice in this example I’m using all the plugin defaults. The rainbow colors are applied to the li tags. The number of rainbowized elements can be arbitrary; the plugin will step through the color spectrum with a finer or coarser grain depending on how many elements there are. Note as well that there is no requirement to use a list. Any HTML structure can be used.

The result here looks good, but it’s not quite good enough.  Some CSS shadowing effects will make it pop, so I added this to the li’s style:

                    box-shadow: 1px 1px 1px 1px rgba(255, 255, 255, 0.5) inset,
                                -1px -1px 1px 0 rgba(0, 0, 0, 0.3) inset,
                                1px 1px 1px 1px rgba(33, 33, 33, 0.14);
                    text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.5);

That’s three box shadows for each li tag. The first adds a light inner shine from the upper left, the second adds a bit of an inner shadow on the bottom right, and the last adds a subtle drop shadow. I included a text shadow as well. This is the final result:

a shiny rainbow list

Rainbow demo page!

Try the demo to adjust the rainbow plugin settings and view the results. You can play around with the starting hue, the saturation and lightness.

I hope you find this plugin useful! Feel free to use it in your projects. A link back here is not required, but always appreciated!

Read more from Javascript

Share your thoughts, post a comment.

(required)
(required)

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments