You are a web developer, and your boss has decided to update the company's website. He has decided that less color is better, but he wants the site to look the same. You justly decide that he has no idea what he's talking about, but you're going to try anyway, because you're bored. Since the company has thousands of webpages, and each one has its own CSS, you decide to write a script to do the necessary changes. Parsing HTML not required.

All of the pages currently use a string like rgb(255,0,0) for a color. Given the three decimal values representing the RGB values of a CSS color attribute (in that order), return or print the shortest string representation of that color, such that it's usable for CSS like so: color:<your-result-here>;.

Here is a complete table of valid CSS Color Keywords. They are case-insensitive.


Note that colors can be defined with 12 or 24 bits. The pattern #ABC is a shorter version of #AABBCC. Chuck Norris is a color.

Your program will only take in 3 integers, not a string (with the exception of the "bonus" mentioned later).

0, 0, 0         ->  #000        (same as #000000, but shorter)
255, 0, 0       ->  red
0, 128, 128     ->  TEAL
139, 0, 0       ->  DarkRed     (OR #8B0000)
72, 61, 139     ->  #483D8B
255, 255, 254   ->  #fffffe
255, 85, 255    ->  #f5f        (same as #ff55ff, but shorter)

Scoring / Rules

  • Shortest code wins!
  • Standard loopholes are disallowed, with the exception of built-ins.
  • -50% bytes (the bonus is rounded down) if you accept any* valid color selector and output the shortest. So DarkSlateBlue would output #483D8B, #F00 outputs red, etc.
    • *This only includes RGB, hex codes, and names.
    • Note that some colors have alternate names due to X11 (like Fuchsia and Magenta, or Cyan and Aqua). The alternate names are included in the linked list of CSS Color Keywords according to the W3 standard.
  • CSS3 is Turing Complete. That'd be worth a bounty.



9 Answers 9


C#6 527 bytes / 2 bonus = 264

EDIT: Woot! I finally got the bonus answer with a lower score than the basic answer!

I've written just a function. It requires a using statement (included.)

C# has a nice list of known colours to work with, but it insists on including the Alpha channel. The known colours also includes all system colours, two of which have names less than 7 characters long, so these needed to be stripped out.

Here's the bonus solution, supporting formats such as:

  • 12, 34, 56
  • #123
  • #123456
  • DarkSlateBlue

Completely golfed:

using System.Drawing;int H(string s,int i,int l)=>Convert.ToInt32(s.Substring(i*l+1,l),16)*(l<2?17:1);string D(string a){int i=17,j=a.Length/3,n;var d=a.Split(',');Color k,c=a[0]<36?Color.FromArgb(H(a,0,j),H(a,1,j),H(a,2,j)):Color.FromName(a);c=c.A>0?c:Color.FromArgb(int.Parse(d[0]),int.Parse(d[1]),int.Parse(d[2]));j=c.R%i+c.G%i+c.B%i<1?3:6;n=c.ToArgb();a="#"+(j<6?c.R/i<<8|c.G/i<<4|c.B/i:n&0xffffff).ToString("x"+j);for(i=26;i++<167;k=Color.FromKnownColor((KnownColor)i),a=n==k.ToArgb()&k.Name.Length<=j?k.Name:a);return a;}

Indentation and new lines for clarity:

using System.Drawing;
int H(string s,int i,int l)=>Convert.ToInt32(s.Substring(i*l+1,l),16)*(l<2?17:1);
string C(string a){
    int i=17,j=a.Length/3,n;
    var d=a.Split(',');
    Color k,c=a[0]<36
    return a;

C#, 265 bytes

Here's the basic solution.

using System.Drawing;string C(int r,int g,int b){int i=17,c=r<<16|g<<8|b,j=r%i+g%i+b%i<1?3:6;var o="#"+(j<6?r/i<<8|g/i<<4|b/i:c).ToString("x"+j);for(i=26;i++<167;){var k=Color.FromKnownColor((KnownColor)i);o=c<<8==k.ToArgb()<<8&k.Name.Length<=j?k.Name:o;}return o;}

Indentation and new lines for clarity:

using System.Drawing;

string C(int r,int g,int b){
    int i=17,
    var o="#"+(j<6?r/i<<8|g/i<<4|b/i:c).ToString("x"+j);
        var k=Color.FromKnownColor((KnownColor)i);
    return o;

Mathematica 207 242 500-250=250 bytes

This works with inputs consisting of rgb triples, color names, or hex numbers.

(12 bit) color-depth output now works fine, thanks to an excellent article on Color Bit Depth Reduction. The basic idea is that, if an RGB triple {r,g,b}, where r, g, and b are in the range of 0-255, (i.e. hex 00-ff) can be represented without loss as a number in the range of 0-15 (i.e. 0-f), then one may use the 3 digit hex number instead of the 6 digit number. Turns out that this will occur whenever 17 (i.e 255/15) divides r, g, and b.

Only built-in functions are used. Mathematica has rules for replacing HTML colors names with RGB triples. For example, one rule is "Teal"-> RGBColor[0, 128, 128]. When such rules are inverted, rgb values (recalibrated to the range, {0, 255}) can be replaced with color names.

j=q/.{(c_ -> RGBColor[r_,g_,b_]):> (Floor[255{r,g,b}]-> c)};
z@d_:= (If[StringQ@d,If[StringTake[d,1]=="#",e=o@d,e=m@d],e=d];f@e)


z /@ {{0, 0, 0}, {255, 0, 0}, {0, 128, 128}, {139, 0, 0}, {255, 255, 
   255}, {72, 61, 139}, {255, 255, 254}, {255, 85, 255}}

{"#000", "Red", "Teal", "#8b0000", "#fff", "#483d8b", "#fffffe","#f5f"}

z /@ {"Red", "DarkSlateBlue", "Teal", "Black"}

{"Red", "#483c8b", "Teal", "#000"}

z /@ {"#000", "#f00", "#008080", "#8b0000", "#fff", "#483d8b", "#fffffe", "#f5f"}

{"#000", "Red", "Teal", "#8b0000", "#fff", "#483d8b", "#fffffe", \ "#f5f"}

Commented, Ungolfed Code

(* rules for replacing a color name with a color swatch, e.g. RGBColor{255,17,0}


(* rules for replacing a list of 3 integers with the respective color name, if one exists. And the same rules, reversed. *)

rulesListsToColorNames=(q)/.{(c_ -> RGBColor[r_,g_,b_]):> (Floor[255{r,g,b}]-> c)};


(*tests whether a 24 bit hex color can be represented as a 12 bit color with no loss. reduce can change the 24 bit expression to a 12 bit expression. *)


(*RGB list changed to a Hex number *)


(* Hex number changed to RGB list. *)


(* More conversions *)


(* choses the shortest valid CSS expression of a color *)


(* converts any input into an RGB list and calls f *)

  • 1
    \$\begingroup\$ Isn't 255 in base 10 equal to FF in Base 16? So that should make #FFFFFF, which is longer than White. I'm finding #000 unusual but will look into the quirks of CSS to be sure. \$\endgroup\$
    – DavidC
    Commented Oct 6, 2015 at 1:53
  • 4
    \$\begingroup\$ @DavidCarraher: CSS colors may be specified as 24 bits or 12 bits. #FFF is the same as #FFFFFF (all bits one) which is the same as white. Also, #0 is invalid because it's neither 24 bits nor 12 bits \$\endgroup\$
    – slebetman
    Commented Oct 6, 2015 at 4:09
  • \$\begingroup\$ slebetman, Thanks for the clarification, which confirms @mbomb007's observation. \$\endgroup\$
    – DavidC
    Commented Oct 6, 2015 at 13:37

Perl, 212 - 50% = 106 bytes

use aliased Graphics::ColorNames,G;sub c{tie%c,G,CSS;$_=pop;$c={reverse%c}->{$_=sprintf'%02x'x(@0=/(\d+, ?)((?1))(\d+)/)||$c{s/#(.)(.)(.)$|#/\1\1\2\2\3\3/r},@0};s/(.)\1(.)\2(.)\3|/#\1\2\3/;y///c>length$c&&$c||$_}

With newlines added:

use aliased Graphics::ColorNames,G;
sub c{
    $_=sprintf'%02x'x(@0=/(\d+, ?)((?1))(\d+)/)||$c{s/#(.)(.)(.)$|#/\1\1\2\2\3\3/r},@0

Test Cases

use feature say;

say c '#f00';
say c '#FF0000';
say c '#112233';
say c '#f0ffff';
say c 'azure';
say c 'rgb(255, 127, 80)';
say c 'rgb(255, 255, 254)';
say c 'rgb(255,228,196)';



Perl, no bonus, 144 bytes

use aliased Graphics::ColorNames,G;sub c{tie%c,G,CSS;$c={reverse%c}->{$_=sprintf'%02x'x3,@_};s/(.)\1(.)\2(.)\3|/#\1\2\3/;y///c>length$c&&$c||$_}

With newlines added:

use aliased Graphics::ColorNames,G;
sub c{

Graphics::ColorNames isn't a core module, but it's been around since 2001. You may need to install it via:

cpan install Graphics::ColorNames
cpan install Graphics::ColorNames::CSS

The hex representation is preferred if the color name has the same length.

Test Cases

use feature say;

say c 0, 0, 0;
say c 255, 0, 0;
say c 0, 128, 128;
say c 139, 0, 0;
say c 72, 61, 139;
say c 255, 255, 254;
say c 255, 85, 255;


  • \$\begingroup\$ Any chance you could cut 4 bytes off for the tie? \$\endgroup\$
    – mbomb007
    Commented Oct 9, 2015 at 20:17
  • \$\begingroup\$ @mbomb007 6 bytes, in fact. \$\endgroup\$
    – primo
    Commented Oct 10, 2015 at 2:21
  • \$\begingroup\$ Do I hear 4 more? This competition is tough. \$\endgroup\$
    – mbomb007
    Commented Oct 12, 2015 at 19:12
  • 1
    \$\begingroup\$ @mbomb007 raise. \$\endgroup\$
    – primo
    Commented Oct 14, 2015 at 7:15

CoffeeScript, 411 404 388 384 382/2 = 191

UPD: Pretty sure it is final result

Hope, it's okay to use window.document.*. Check rgb function and eval call.

s=(c,rgb=(r,g,b)->(2**24+(r<<16)+(g<<8)+b).toString 16)->d=y=document.body;r=(q=(a)->y.style.color=a;d[b='#'+eval(getComputedStyle(y).color)[1...].replace /(.)\1(.)\2(.)\3/,'$1$2$3']=a;b) c;(d='NavyGreenTealIndigoMaroonPurpleOliveGraySiennaBrownSilverPeruTanOrchidPlumVioletKhakiAzureWheatBeigeSalmonLinenTomatoCoralOrangePinkGoldBisqueSnowIvoryRed'.match /.[a-z]+/g).map(q);d[r]||r

Test results

rgb(   0,   0,   0 ) -> #000
rgb( 255,   0,   0 ) -> Red
rgb(   0, 128, 128 ) -> Teal
rgb( 139,   0,   0 ) -> #8b0000
rgb(  72,  61, 139 ) -> #483d8b
rgb( 255, 255, 254 ) -> #fffffe
rgb( 255,  85, 255 ) -> #f5f
darkslateblue        -> #483d8b
indigo               -> Indigo
#f00                 -> Red

Commented code

s = ( c,
    rgb = ( r, g, b ) ->
        return ( 2 ** 24 + ( r << 16 ) + ( g << 8 ) + b )
        .toString( 16 )
) ->

This will save some bytes.

    d = y = document.body

q function will place input color to document.body.style.color and get compiled color as rgb(...). Also it will store result as hexColor:inputColor in d. Notice eval use. rgb(100,100,100) is a valid JavaScript function call with three number arguments. rgb function will convert arguments to single 24/12 HEX notation (like #fff, #f0f0f0).

    r = (
        q = ( a ) ->
            y.style.color = a
            b = '#' + eval( getComputedStyle( y ).color )[ 1... ].replace( /(.)\1(.)\2(.)\3/, '$1$2$3' )
            d[ b ] = a
            return b
    )( c )

Split string to array of color names, create lookup object.

    ( d = 'NavyGreenTeal...'.match( /.[a-z]+/g )).map( q )

And return HEX if no shorter variant in d.

    return d[ r ] or r

Stylus, 238 234/2 = 117

More CSS-like solution! Stylus already has great support for color manipulation, so desired function is pretty small and not golfed a lot.

f(c){for n in split(' ''navy green teal indigo maroon purple olive gray sienna brown silver peru tan orchid plum violet khaki azure wheat beige salmon linen tomato coral orange pink gold bisque snow ivory red'){lookup(n)==c?c=s(n):c}}

Test it here

  color f(rgb(0, 0, 0))
  color f(rgb(255, 0, 0))
  color f(rgb(0, 128, 128))
  color f(rgb(139, 0, 0))
  color f(rgb(72, 61, 139))
  color f(rgb(255, 255, 254))
  color f(rgb(255, 85, 255))
  color f(darkslateblue)
  color f(indigo)
  color f(#f00)
  color f(rgba(255,0,0,1))
  color f(rgba(255,0,0,0.5))
  • \$\begingroup\$ Welcome to PPCG! That's a really nice solution! \$\endgroup\$
    – mbomb007
    Commented Oct 7, 2015 at 21:10
  • \$\begingroup\$ not golfed a lot. You'd better try to golf it some more if you want to win. Someone is beating you by one. \$\endgroup\$
    – mbomb007
    Commented Oct 10, 2015 at 18:16
  • \$\begingroup\$ @mbomb007, alright, golfed a bit. \$\endgroup\$
    – argh-argh
    Commented Oct 11, 2015 at 8:25
  • \$\begingroup\$ It looks as though you've been beaten. Maybe you can try cramming the colors together without spaces, but padded to five characters, then split every five and trim? Not sure if that would save bytes? \$\endgroup\$
    – mbomb007
    Commented Oct 14, 2015 at 13:45

Matlab 617

A lot of preprocessing and hardcoding. The minimal set of colour names you have to consider are these. Too bad Matlab does not have built in color names=/

function s=f(r,g,b);
a=[0 t t;240 t t;245 245 220;t 228 196;0 0 t;165 42 42;t 127 80;0 t t;t 215 0;75 0 130;t t 240;240 230 140;0 t 0;250 240 230;t 165 0;218 112 214;205 133 63;t 192 203;221 160 221;t 0 0;250 128 114;160 82 45;t 250 250;210 180 140;t 99 71;238 130 238;245 222 179;t t t;t t 0];
s=textscan('aqua azure beige bisque blue brown coral cyan gold indigo ivory khaki lime linen orange orchid peru pink plum red salmon sienna snow tan tomato violet wheat white yellow','%s');
if i>0;s=s{1}{i};elseif ~any(mod(c,16));k=16;end;d=dec2hex(c/k,2-(k>1))';s=['#',d(:)']
  • \$\begingroup\$ You've left the hardcoded r=0;g=16;b=0; in there, though it's not counted in your score. \$\endgroup\$ Commented Oct 6, 2015 at 0:34
  • \$\begingroup\$ Oh, I pasted the wrong version, thanks for letting me know! \$\endgroup\$
    – flawr
    Commented Oct 6, 2015 at 7:54

Python 3, 857 795 bytes

Having to manually specify all of the accepted colours required did increase the byte count on this one :/

c(a) takes one argument, a, which comes in the form of rgb(#,#,#). From that, the rgb and brackets are removed and the string is then split by commas into an array. c(x,y,z) takes 3 ints, the r, g and b values of the rgb colour to process. We put those together in an array a. We then use Python's built-in hex function which converts a Base 10 number to a Base 16 number on our array and create a hex string (this is done in the for loop). The if statements convert colours like 000000 to 000, and replace the known colours using a dictionary.

Here it is (thanks to @undergroundmonorail for tip about ; in Python):

def c(x,y,z):
  for i in a:
    if len(i)<2:i="0"+i;
  if b[:3]==b[3:]:b=b[:3];
  if b in k:b=k[b];
  return b

Old Version:

def c(a):
  for i in a:
    if len(i)<2:
  k = {"00ffff":"AQUA","f0ffff":"AZURE","f5f5dc":"BEIGE","ffe4c4":"BISQUE","0000ff":"BLUE","a52a2a":"BROWN","ff7f50":"CORAL","ffd700":"GOLD","808080":"GRAY","008000":"GREEN","4b0082":"INDIGO","fffff0":"IVORY","f0e68c":"KHAKI","00ff00":"LIME","faf0e6":"LINEN","800000":"MAROON","000080":"NAVY","808000":"OLIVE","ffa500":"ORANGE","da70d6":"ORCHID","cd853f":"PERU","ffc0cb":"PINK","dda0dd":"PLUM","800080":"PURPLE","ff0000":"RED","fa8072":"SALMON","a0522d":"SIENNA","c0c0c0":"SILVER","fffafa":"SNOW","d2b48c":"TAN","008080":"TEAL","ff6347":"TOMATO","ee82ee":"VIOLET","f5deb3":"WHEAT","ffff00":"YELLOW"}
  if b[:3]==b[3:]:
  if b in k:
  return "color:"+b+";"

Maybe I'll add the bonus to it, I don't know yet. It could definitly do with 50% bytes off!


  • 2
    \$\begingroup\$ general python golfing tips: many of your newlines can be replaced by ;, saving the indentation. for example: a=a[4:-1].split(",");b="". any if, else, for, while, etc block with only one line can be written as if b in k:b=k[b].finally, you can lose a lot of your whitespace in the middle of lines, e.g. k = { -> k={ and return "color: -> return"color: \$\endgroup\$ Commented Oct 6, 2015 at 8:32
  • \$\begingroup\$ also, welcome to PPCG :) \$\endgroup\$ Commented Oct 6, 2015 at 8:32
  • 2
    \$\begingroup\$ That literal k is huge. As all color codes are in lowercase and all color names are in uppercase, you could just write it as a single string, then parse it with re.findall() (so will also need import re): pastebin.com/rQHqgxXS \$\endgroup\$
    – manatwork
    Commented Oct 6, 2015 at 9:37
  • \$\begingroup\$ @undergroundmonorail Thanks for that, should save a lot of space :D \$\endgroup\$ Commented Oct 8, 2015 at 5:03
  • \$\begingroup\$ @mbomb007 OK, I wasn't quite sure how you wanted the output or input - got a little confused there :P I did run the code on the test cases to ensure it works properly, do you want me to upload my results? \$\endgroup\$ Commented Oct 8, 2015 at 5:05

JavaScript (ES6), 499 611

Edit Added the test cases in the question

Note: I kept just the color names that are shorter than the hex equivalent.

Note 2: this can surely be golfed more...


.forEach(([r,g,b,t])=>(x=f(r,g,b),o+=r+','+g+','+b+' -> '+x+' '+(x.toUpperCase()==t.toUpperCase()?'ok':'error('+t+')')+'\n'),o='')

function go()
  var r,g,b
  [r,g,b] = I.value.match(/\d+/g)
  O.innerHTML=r+','+g+','+b+' -> '+f(r,g,b)+'\n'+O.innerHTML
R,G,B: <input id=I><button onclick="go()">--></button>
<pre id=O></pre>

Less golfed

f=(r,g,b) => (
     ? 1<<24|r<<16|g<<8|b
     : 4096|r/17<<8|g/17<<4|b/17
   s = "#d2b48cTAN#f00RED#ff7f50CORAL#f5deb3WHEAT#ff6347TOMATO#ffd700GOLD#008000GREEN#faf0e6LINEN#f5f5dcBEIGE#da70d6ORCHID#4b0082INDIGO#ffc0cbPINK#f0e68cKHAKI#008080TEAL#ee82eeVIOLET#dda0ddPLUM#fa8072SALMON#ffa500ORANGE#a0522dSIENNA#800000MAROON#800080PURPLE#ffe4c4BISQUE#f0ffffAZURE#fffff0IVORY#cd853fPERU#808000OLIVE#c0c0c0SILVER#fffafaSNOW#a52a2aBROWN#000080NAVY#808080GRAY",
   m = s.match(k+'([A-Z]+)'), // names are upper, hex codes are lower
   (m || [,k])[1] // if no match use the code
  • \$\begingroup\$ Those underscores… According to my counting, would be shorter without them. Just quote the codes starting with a digit and keep the others unquoted: {f00:"red";"008000":"green"}. \$\endgroup\$
    – manatwork
    Commented Oct 6, 2015 at 10:12
  • \$\begingroup\$ @manatwork nice trick. But a literal object is rarely a good choice for code golf. A simple string is better \$\endgroup\$
    – edc65
    Commented Oct 6, 2015 at 10:52
  • \$\begingroup\$ Correct. I already made a comment in that sense to our fresh sitemate. \$\endgroup\$
    – manatwork
    Commented Oct 6, 2015 at 10:56
  • 1
    \$\begingroup\$ @mbomb007 Test cases added. The snippet won't work in chrome being EcmaScript 6, and Chrome is not fully compliant (quite tired to repeat this again and again). Test in Firefox. \$\endgroup\$
    – edc65
    Commented Oct 6, 2015 at 14:35

Python 3 + matplotlib, 193 bytes

import matplotlib.colors as M
def f(c):
 H=h=M.rgb2hex([i/255for i in c]).upper()
 if all(v%17<1for v in c):h=h[::2]
 for n,x in M.CSS4_COLORS.items():
  if H==x and len(n)<len(h):h=n
 return h

Input is taken as a tuple or array of integers.

Try it here

Less golfed:

import matplotlib.colors as mcolors

def f(c):
  # Save two copies of the uppercase hex value.
  # Inconvenient, but it takes decimals instead of integers,
  # and it returns lowercase, but the dictionary has uppercase. :'(
  H=h=mcolors.rgb2hex([i/255 for i in c]).upper()

  # Check if all 3 integers are divisible by 17,
  # because that means in hex the digits are the same,
  # similar to how that works for multiples of 11 in base 10,
  # or multiple of N+1 in base N.
  if all(v%17<1 for v in c):
    # Get every other character from the hex string

  # Loop through the dictionary. Way too verbose for me to appreciate.
  for n,x in mcolors.CSS4_COLORS.items():
    # If the name is shorter, use it.
    # H is needed, because "h" is the shortened.
    if H==x and len(n)<len(h):h=n

  return h

CSS4_COLORS contains a dictionary of the color names and hex values. Unfortunately, the dictionary is "backwards" from what I'd like. Also, this could likely be used to create a better score using the bonus, though I don't think it'd win.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.