Rainbow Coding

Introducing How to create rainbow text in HTML & CSS & JavaScript

Update February 4th, 2014: Added a way to use Modernizr to detect the backgroundclip support, since jQuery 1.9 has dropped the support for $.browser.

This article teaches how to create rainbow texts in various ways

Rainbows are colorful things. They make wonderful backgrounds, logos, but I think they are especially cool in texts. I'm certain that many people would like to use them in their web sites, but until lately there hasn't been a easy and reliable way to achieve it.

In this post I introduce three ways to create rainbow texts for web.

1. Image editor

Almost any image editor is capable of creating Rainbow Text. Gimp, Pixelmator, Photoshop - maybe anything except MS Paint. Just create a text and apply gradient for it. The exact way to achieve this varies depending on application you use, so I won't be going into details here. Basically you create image and use it:

<img src="rainbowtext.png" />

However, this way has two big problems: the text won't be searchable and the text will be difficult to change.

In other words, we should avoid this way.

2. Separate elements

More straightforward way is to create the text with separate elements. It means wrapping each letter in it's own element.

<span style="color: #f00;">R</span>
<span style="color: #f50;">a</span>
<span style="color: #ff0;">i</span>
<span style="color: #5f0;">n</span>
...

<span style="color: #f00;">R</span><span style="color: #f50;">a</span><span style="color: #ff0;">i</span><span style="color: #5f0;">n</span>...

As you can see, it's definitely NOT meant to be done manually. Basically you need to write some javascript to generate the codes. We'll take a look into that later.

3. CSS magic

The best way I have found is with CSS, because text will be easy to read and modify after you hide the style to .css file. This way includes creating a gradient that we use as background, and then clipping mask with text that shows background only where text is present.

.rainbow {
  background-image: -webkit-gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );
  background-image: gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );
  color:transparent;
  -webkit-background-clip: text;
  background-clip: text;
}

With above text we can do:

Rainbows are colorful and scalable and lovely

Rainbows are colorful and scalable and lovely

This method works without JavaScript and is the cleanest solution because it's just few simple lines of CSS.

Note: If you use this in any other than display:inline element (such as span), it will spread the spectrum across the whole width, which may make it not making it not so rainbowish. For example:

Not rainbow!

Not rainbow!

You can get around this with span element:

Colorful rainbow.

Colorful rainbow.

However, even this way is not perfect, and there's one there's this one weak point: Older browsers do not support it! More information here

Since we need this to run perfectly in all browsers, we need...

THE ULTIMATE RAINBOW SOLUTION!

In other words, use CSS if browser supports it, or use JavaScript if not.

This means using both methods, 2 and 3.

So here's how to achieve it. First we need JavaScript to to get the colors.

function color_from_hue(hue)
{
  var h = hue/60;
  var c = 255;
  var x = (1 - Math.abs(h%2 - 1))*255;
  var color;

  var i = Math.floor(h);
  if (i == 0) color = rgb_to_hex(c, x, 0);
  else if (i == 1) color = rgb_to_hex(x, c, 0);
  else if (i == 2) color = rgb_to_hex(0, c, x);
  else if (i == 3) color = rgb_to_hex(0, x, c);
  else if (i == 4) color = rgb_to_hex(x, 0, c);
  else color = rgb_to_hex(c, 0, x);

  return color;
}

function rgb_to_hex(red, green, blue)
{
  var h = ((red << 16) | (green << 8) | (blue)).toString(16);
  // add the beginning zeros
  while (h.length < 6) h = '0' + h;
  return '#' + h;
}

This has some mysterious looking HSL conversion math behind it. If you are interested about the details, check what Wikipedia says about converting HSL to RGB.

Next, we can wrap this into jQuery to make it easy to use.

(function( $ ) {

  $.fn.rainbowize = function() {
    return this.each(function() {
      var rainbowtext = '';
      var hue=0;
      var step=0;

      // get the current text inside element
      var text = $(this).text();

      // hue is 360 degrees
      if (text.length > 0)
        step = 360 / (text.length);

      // iterate the whole 360 degrees
      for (var i = 0; i < text.length; i++)
      {
        rainbowtext = rainbowtext + '' + text.charAt(i) + '';
        hue += step;
      }

      $(this).html(rainbowtext);
    });
  };
})( jQuery );

Then to the CSS, we add rainbowize class for webkit browsers.

.rainbowize {
  background-image: -webkit-gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );
  background-image: gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );
  color:transparent;
  -webkit-background-clip: text;
  background-clip: text;
}

Detecting the support

Old versions of jQuery contained checks for browser support, such as webkit or firefox, but even then you could never be sure if the browser supports it. To detect if the browser support is available, we need to use Modernizr.

You can download the latest version from here: http://www.modernizr.com/downloads/modernizr-latest.js.

Then include it into your page.

However, modernizr does not contain test for background-clip by default, so you should add one:

  Modernizr.addTest('backgroundclip',function() {

    var div = document.createElement('div');

    if ('backgroundClip' in div.style)
      return true;

    'Webkit Moz O ms Khtml'.replace(/([A-Za-z]*)/g,function(val) {
      if (val+'BackgroundClip' in div.style) return true;
    });

  });

Basically this means, that if the support exists, it will add "backgroundclip" class for the html element. Finally we connect everything to document's ready function.

$(document).ready(function() {
    if( !$("html").hasClass("backgroundclip") )
       $(".rainbow").addClass("rainbowize");
    else
       $(".rainbow").rainbowize();
});

Now, whenever you write something like

I love rainbows because they are so colorful!

it will show up as "I love rainbows because they are so colorful!" and will look like rainbow in any browser.

© RainbowCoding 2010-2021