Home > javascript > Random hex color code generator in JavaScript

Random hex color code generator in JavaScript

June 19th, 2009

For fun I asked a few friends for ideas on a random color generator in a single line of javascript. You know, these guys: #0afec0, #c9f2d0, #9b923e.

Here's what we came up in about two minutes (in chronological order)…

'#' + (function co(lor){   return (lor += 
  [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'][Math.floor(Math.random()*16)]) 
  && (lor.length == 6) ?  lor : co(lor); })('');

Similar recursive technique, but using a string instead of an array and aliasing the Math object:

(function(m,s,c){return (c ? arguments.callee(m,s,c-1) : '#') + 
  s[m.floor(m.random() * s.length)]})(Math,'0123456789ABCDEF',5)

Using a named function expression instead of arguments.callee.

'#'+(function lol(m,s,c){return s[m.floor(m.random() * s.length)] +
  (c && lol(m,s,c-1));})(Math,'0123456789ABCDEF',4)

If we assume JavaScript 1.6, then we could just use Array.map():

'#'+'0123456789abcdef'.split('').map(function(v,i,a){
  return i>5 ? null : a[Math.floor(Math.random()*16)] }).join('');

But then, the magic of Math struck (16777215 == ffffff in decimal):

'#'+Math.floor(Math.random()*16777215).toString(16);
Thx to ben alman, nlogax, and temp01 for their smarts.

Paul Irish javascript

  1. | #1

    oh wow, i absolutely love that final solution, i would have never thought of that

  2. | #2

    Very nice. Though you might want to pad with zeros for when the random value is less than 0×100000.

  3. | #3

    nlogax just offered a revision to the last one to use a bit-wise shift left operator, plus FFFFFFF in hex for clarity.

    '#'+(Math.random()*0xFFFFFF<<0).toString(16);
  4. | #4

    Excellent tip, I could have used this just the other day. The 0xFFFFFF is clearer, and good comment about padding to the left because either way you will occasionally get 5 (or fewer) digit colors.

  5. | #5

    Man, there are two problems here:

    1 - Math.random()*1<<0 will never produce 1. For a range 0,N with virtually same possibilities you need Math.random()*(N+1)<<0 so the right one is:

    (Math.random()*(0xFFFFFF+1)<<0).toString(16)

    otherwise 0xFFFFFF will never happen

    2 - as somebody said already you need to pad the string so the quick one is:

    '#'+(function(h){return new Array(7-h.length).join("0")+h})((Math.random()*(0xFFFFFF+1)<<0).toString(16))

    Regards

  6. | #6

    Obviously, this is even better (could be confusing though):

    '#'+(function(h){return new Array(7-h.length).join("0")+h})((Math.random()*0x1000000<<0).toString(16))

    Just for fun, I add a quick and dirty pad function as well:

    function pad(s,i,c,r){
        i=i+1-s.length;
        if(i<1)return s;
        c=new Array(i).join(c||" ");
        return r?s+c:c+s;
    };
     
    pad("ff",6,"0"); // 0000FF
    pad("ff",6,"0",true); // FF0000

    so, the color is

    "#"+pad((Math.random()*0x1000000<<0).toString(16),6,"0");

    and we can reuse the pad function everytime we need.

  7. nulogaksu
    | #7

    Stretching the original "quick, dirty one-liner" concept a bit, and fixing the obvious problems with it:

    function lolColor(){var h=(Math.random()*0xFFFFFF+1<<0).toString(16); while(h.length<6){h="0"+h;} return "#"+h;}
  8. | #8

    nulogaksu: Nope, because that algorithm will never generate uniform black (#000000)!

    Also, you can't just multiply Math.random() by a number and round it*, that doesn't produce a truly random range. But, picking a random colour isn't like drawing random cards for a poker game - it doesn't need perfect uniformity (or at least: as perfect a randomness as your RNG can muster).

    *) The reason is the pigeon hole principle: An IEEE double has a 52-bit mantissa, so that's how much randomness you generally start out with (52 bits worth). Lets say you now want to generate a random number between 0 and 2^52-2. Then, exactly one number in your supposed uniform range shows up twice as often as any other number - after all, there are 2^52 input numbers which map to 2^52-1 numbers, so exactly two of the 2^52 numbers map to the same output number. In practice its worse, and some output numbers can never be attained. I also oversimplified how IEEE doubles work, but this is enough detail to explain why Math.random()*max is a flawed way to generate random integers. In java, you should use Random.nextInt(maxNum), but that method isn't available in javascript.

    Again, mostly an academic point - the flawed random number generation is still decently random, if not entirely uniform, and I can't think of any situations where strict uniformity is an absolute requirement when picking a random colour!

  9. nulogaksu
    | #9

    Reinier: You're right, that's missing a pair of parens. No idea why I didn't just use 16777216 when I aimed for compact rather than readable. :)
    I was wondering on IRC earlier when someone would say "It's not random enough!" but as you said, it's good enough for this purpose.

  10. | #10

    Reinier, nobody rounded numbers here … <<0 is like a Math.floor … but I already wrote how to obtain a virtually correct random, no?

    Math.floor(Math.random() * (N + 1));

    which is exactly like:
    Math.random() * (N + 1) << 0
    since bitwise has less precedence than multiply operator

    again, 0×000000 to 0xFFFFFF is:
    (Math.random()*0×1000000<<0).toString(16)

    no? Regards

  11. | #11

    Your padding solutions are quite general, but not small enough!

    Here's the shortest random hex color code I could come up with:

    '#'+('00000'+(Math.random()*16777216<<0).toString(16)).substr(-6)

    And this is even shorter, if #ABC colors are fine (vs #ABCDEF) :P

    '#'+('00'+(Math.random()*4096<<0).toString(16)).substr(-3)
  12. MTyson
    | #12

    Now, what's the shortest and best algorithm for generating a good contrast color with the random color (one that is visible against the base color)?

  13. | #13

    @MTyson, I did some research on this. From this particletree article (with a shoutout to friend BarelyFitz), the below would be the best for calculating:

    function contrast(color){ return '#' + 
       (Number('0x'+color.substr(1)).toString(10) > 0xffffff/2 ? '000000' :  'ffffff'); 
    }
     
    contrast('#BADA55'); // '#000000'

    I'll leave it up to the community to shorten. :)

  14. MTyson
    | #14

    Interesting read. That's essentially what I came up with also, check the brightness and use white or black accordingly (and blend in a little color from the base for spice). Thanks!

  15. yannis
    | #15
     $('a#cbutton4').click(function(){
       var  red = Math.round(Math.random()*254+1);
       var  green = Math.round(Math.random()*254+1);
       var   blue=Math.round(Math.random()*254+1);
       var color='rgb('+red+','+green+','+blue+')';
       var reverse='rgb('+ (255-red) + ','+ (255-green) + ',' + (255-blue) +')';
     
    $('p#rnumber4').css('background',color)
                   .css('color',reverse)
                   .fadeTo('slow','0.35')
                   .fadeTo('slow',1.0);
         return false;
       });

    Not exactly one line but of you go for rgb() easier to understand! Can be put in one line if need be. Leave it for you Ninjas

  1. No trackbacks yet.

For code blocks, use <pre lang="javascript" escaped="true">. css and html4strict are also accepted.

Comments for this post will be closed on 14 June 2010.