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