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.

javascript

  1. June 20th, 2009 at 06:41 #1

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

  2. June 20th, 2009 at 09:48 #2

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

  3. June 20th, 2009 at 16:53 #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. June 21st, 2009 at 02:51 #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. June 21st, 2009 at 04:00 #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. June 21st, 2009 at 04:30 #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
    June 21st, 2009 at 06:22 #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. June 21st, 2009 at 08:27 #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
    June 21st, 2009 at 14:44 #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. June 22nd, 2009 at 18:30 #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. June 25th, 2009 at 06:59 #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
    June 25th, 2009 at 17:58 #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. June 27th, 2009 at 10:35 #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
    June 27th, 2009 at 10:56 #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
    August 20th, 2009 at 06:31 #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

  16. Hans
    March 22nd, 2010 at 05:47 #16
  17. George
    May 18th, 2010 at 13:23 #17

    Does it have to be hex? Colors can also be defined using plain integers via rgb():

    color = 'rgb(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ')';

  18. August 16th, 2010 at 16:25 #18

    Hey Paul – randomly landed on your post looking for something – look what I post on Twitter two weeks before you blogged: http://twitter.com/rem/status/15427387974 – spooky!

  19. August 16th, 2010 at 16:30 #19

    @Remy Sharp
    "look what I post on Twitter two weeks before the one year anniversary that you blogged:"

    FTFY.
    :)

  20. August 16th, 2010 at 16:39 #20

    face => palm. Okay, so you worked this out just 50 weeks before I did! :-D

  21. August 17th, 2010 at 02:29 #21

    I think there's a flaw in both Paul's and Remy's scripts. You're multiplying Math.random() by 16777215, which is FFFFFF (hex) in decimal. Then, you’re rounding the whole thing down using Math.floor() (or in Remy’s case, a double bitwise NOT).

    However, Math.random() returns a pseudo-random number in the range [0,1) — that is, between 0 (inclusive) and 1 (exclusive).

    Since Math.floor() will never return 1, the random color generator will never return #FFFFFF, since Math.floor(1 * 16777215) === 16777215.

    The solution is simple: just use 16777216 instead of 16777215. This number has the added advantage of being a power of 2 (2^24), so using some bitwise left shiftin’ love you can shorten it to 1<<24.

    '#'+~~(Math.random()*(1<<24)).toString(16);
  22. August 20th, 2010 at 03:51 #22

    So using a combination of Mathias' mega strength and my recent desire to ensure that every value produces a genuine colour, I've fixed the generator as such:

    (function(h){return '#000000'.substr(0,7-h.length)+h})((~~(Math.random()*(1<<24))).toString(16))

    working example

    This ensures that if the number generated via random is less than or equal to 1048575 like 255 for instance, it will still produce a real colour and not generate a short invalid hex value that will then default to black.

  23. Kniggles
    November 5th, 2010 at 15:41 #23

    how would you make this work so that on each click the text box w2 will change colour if E is divsable by 2 ?

    StartA X:

    Two B Y:
    Three D W:

    W2+:

    W3:

    Total Z:

    function calculate()
    {
    var randomnumber=Math.floor(Math.random()*99)
    A = document.frmOne.x.value
    B = document.frmOne.y.value
    D = document.frmOne.w. value

    A = Number(A)
    B = Number(B)
    D = Number(D)
    C = (A + B)
    D = (D + 1)
    E = randomnumber

    document.frmOne.w3.value = A+B+C+D+E
    document.frmOne.z.value = C + 1
    document.frmOne.x.value = B
    document.frmOne.w.value = D
    document.frmOne.w2.value = E
    document.frmOne.y.value = A+1

    }

    function colourchange()
    '#'+Math.floor(Math.random()*16777215).toString(16);
    if
    E = /2
    then
    w2 style="background-color:#random_colour;" SIZE = 5 value = ("0")
    else
    w2 style="background-color:#654321;" SIZE = 5 value = ("0")

    thanks.

  24. January 23rd, 2011 at 19:47 #24

    Here are my two versions for a random hex code generator.

    /* Slowest but shortest. */
    "#000000".replace(/0/g,function(){return (~~(Math.random()*16)).toString(16);});	
     
    /* Good performance with small size. */
    "#"+(function(a,b){while(a--){b+=""+(~~(Math.random()*16)).toString(16);} return b;})(6,"");
     
    /* Remy Sharp provided one that's the fastest but a little bit too long */
    (function(h){return '#000000'.substr(0,7-h.length)+h})((~~(Math.random()*(1&lt;&lt;24))).toString(16))

  25. dhensche
    May 5th, 2011 at 22:35 #25

    One liner that is padded with zeros

    '#' + ('000000' + Math.floor(Math.random() * 0xFFFFFF).toString(16)).substr(-6);
  26. May 5th, 2011 at 23:55 #26

    Hey Paul,

    I need an HSL based one with h, s and l controls. like randColor(h_from, h_to, s_from, s_to, l_from, l_to)

    I could make something like this:

    function rand(min, max) {
        return parseInt(Math.random() * (max-min+1), 10) + min;
    }
     
    function get_random_color(hue_i,sat_i,lit_i,hue_x,sat_x,lit_x) {
        var h = rand(hue_i, hue_x);
        var s = rand(sat_i, sat_x);
        var l = rand(lit_i, lit_x);
        return 'hsl(' + h + ',' + s + '%,' + l + '%)';
    }

    Can you please spend a little time to make a good one?

    Thanks

  27. June 27th, 2011 at 07:25 #27

    I rlaely needed to find this info, thank God!

  28. Mainak
    November 1st, 2011 at 22:46 #28

    Final Solution is awesome.

  29. Aaron
    December 16th, 2011 at 10:59 #29

    is there a way to embed this js into a css stylesheet file?

    my page has links that activate new stylesheets. i want to use the random color generator on every style in my stylesheet called "random"

  30. January 10th, 2012 at 00:10 #30

    Late here. But awesome

  31. January 30th, 2012 at 19:04 #31

    Thanks man!

  32. February 20th, 2012 at 23:57 #32

    Awesome post, I did something similar here. https://gist.github.com/e784bc7693c56a8a63cb

  33. February 26th, 2012 at 13:39 #33

    Here is my version with notes. Most of this has been mentioned in earlier comments but here it is all in one place.

    '#'+('00000'+(Math.random()*(1&lt;&lt;24)|0).toString(16)).slice(-6);

    1) Math.random() really needs to be multiplied by 0xFFFFFF + 1 or 16777216, which can be represented by 1<<24.

    2) <<0 works just fine for flooring the value, but so does |0. As long as we are going for conciseness why not save a character.

    3) The random value needs to be padded with at most 5 additional zeros on the left. To get the last 6 characters other commenters are using substr(-6) which works in most browsers, but some (ahem IE) don't handle negative indexes on substr correctly. The slice method can handle the job without compatibility issues.

  34. March 9th, 2012 at 09:41 #34

    Man, sure am glad you guys shaved off a couple of milliseconds. :)

    What do I do with my extra time? Hmmm.

    In all seriousness, this thread is a great read for someone who thinks they understand number base systems to realize that they don't.

  1. January 13th, 2011 at 10:34 | #1
  2. June 9th, 2011 at 12:04 | #2
  3. February 15th, 2012 at 09:42 | #3

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