252

I want to create a function that will accept any old string (will usually be a single word) and from that somehow generate a hexadecimal value between #000000 and #FFFFFF, so I can use it as a colour for a HTML element.

Maybe even a shorthand hex value (e.g: #FFF) if that's less complicated. In fact, a colour from a 'web-safe' palette would be ideal.

3
  • 2
    Could give some sample input and/or links to the similar questions? Commented Aug 6, 2010 at 17:59
  • 2
    Not an answer, but you may find the following useful: To convert a hexadecimal to an integer, use parseInt(hexstr, 10). To convert an integer to a hexadecimal, use n.toString(16), where n is a integer. Commented Aug 6, 2010 at 18:00
  • @qw3n - sample input: just short, plain old text strings... like 'Medicine', 'Surgery', 'Neurology', 'General Practice' etc. Ranging between 3 and say, 20 characters... can't find the other one but here's the java question: stackoverflow.com/questions/2464745/… @Daniel - Thanks. I need to sit down and have another serious go at this. could be useful. Commented Aug 6, 2010 at 18:42

19 Answers 19

337

Here's an adaptation of CD Sanchez' answer that consistently returns a 6-digit colour code:

const stringToColour = (str: string) => {
  let hash = 0;
  str.split('').forEach(char => {
    hash = char.charCodeAt(0) + ((hash << 5) - hash)
  })
  let colour = '#'
  for (let i = 0; i < 3; i++) {
    const value = (hash >> (i * 8)) & 0xff
    colour += value.toString(16).padStart(2, '0')
  }
  return colour
}

If you are using Eslint, you want to wrap this function in the

/* eslint-disable no-bitwise */
>> stringToColour func. definition here" <<
/* eslint-enable no-bitwise */

Usage:

stringToColour("greenish");
// -> #9bc63b

Example:

http://jsfiddle.net/sUK45/

(An alternative/simpler solution might involve returning an 'rgb(...)'-style colour code.)

Sign up to request clarification or add additional context in comments.

7 Comments

This code works awesome in conjunction with NoSQL auto-generated ID's, your colour will be the same every time for the same user.
I needed the alpha channel for transparency in my hex codes as well. This helped (adding two digits for the alpha channel at the end of my hex code): gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
@Tjorriemorrie Upvoted for pointing out that it's colour and not color. Yes, yes, it's not really on topic but it's something that's important to me (in fact when typing it originally I spelt it 'colour' both times!). Thank you.
Interesting that the colour is different for the same string on different browsers/oss - e.g. Chrome+Windows and Chrome+Android - my e-mail=>colour is blue on one and green on the other. Any idea why?
Thanks! an adaptation to this to generate pastel / bright colors from a string only stackoverflow.com/a/64490863/403372
|
244

Just porting over the Java from Compute hex color code for an arbitrary string to Javascript:

function hashCode(str) { // java String#hashCode
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
       hash = str.charCodeAt(i) + ((hash << 5) - hash);
    }
    return hash;
} 

function intToRGB(i){
    var c = (i & 0x00FFFFFF)
        .toString(16)
        .toUpperCase();

    return "00000".substring(0, 6 - c.length) + c;
}

To convert you would do:

intToRGB(hashCode(your_string))

5 Comments

It needs to pad the hex strings, such as: ("00" + ((this >> 24) & 0xFF).toString(16)).slice(-2) + ("00" + ((this >> 16) & 0xFF).toString(16)).slice(-2) + ("00" + ((this >> 8) & 0xFF).toString(16)).slice(-2) + ("00" + (this & 0xFF).toString(16)).slice(-2);
I'm converting a bunch of music genre tags to background colors and this saved me a lot of time.
I wish I could convert this to php.
I have some problems with almost same colours for similar strings, for example: intToRGB(hashCode('hello1')) -> "3A019F" intToRGB(hashCode('hello2')) -> "3A01A0" And I enhance your code by adding multiplication for final hash value: return 100 * hash;
Don't forget to add '#' like return "#" + "00000".substring(0, 6 - c.length) + c;
78

I wanted similar richness in colors for HTML elements, I was surprised to find that CSS now supports hsl() colors, so a full solution for me is below:

Also see How to automatically generate N "distinct" colors? for more alternatives more similar to this.

Edit: updating based on @zei's version (with american spelling)

var stringToColor = (string, saturation = 100, lightness = 75) => {
  let hash = 0;
  for (let i = 0; i < string.length; i++) {
hash = string.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
  }
  return `hsl(${(hash % 360)}, ${saturation}%, ${lightness}%)`;
}


// For the sample on stackoverflow
function colorByHashCode(value) {
return "<span style='color:" + stringToColor(value) + "'>" + value + "</span>";
}

document.body.innerHTML = [
  "javascript",
  "is",
  "nice",
].map(colorByHashCode).join("<br/>");
span {
  font-size: 50px;
  font-weight: 800;
}

In HSL its Hue, Saturation, Lightness. So the hue between 0-359 will get all colors, saturation is how rich you want the color, 100% works for me. And Lightness determines the deepness, 50% is normal, 25% is dark colors, 75% is pastel. I have 30% because it fit with my color scheme best.

8 Comments

A very versatile solution.
Thx for sharing a solution, where you can decide how colorful the colors should be!
@haykam Thanks for making it into a snippet!
This solution returns too little colors, won't do.
@cbreezier that is because this uses the same hash function it appears. Feel free to change the hash function to something else, multiply by a large prime number and/or XOR with large prime number should move it around. But this example is aiming for a range of 360 colors of a similar tone, yes duplicates will happen, cheers
|
43

Here is my 2021 version with Reduce Function and HSL Color.

function getBackgroundColor(stringInput) {
    let stringUniqueHash = [...stringInput].reduce((acc, char) => {
        return char.charCodeAt(0) + ((acc << 5) - acc);
    }, 0);
    return `hsl(${stringUniqueHash % 360}, 95%, 35%)`;
}

1 Comment

Haha! How could I miss that answer? Pretty similar to the solution I came up with ;-)
18

Using the hashCode as in Cristian Sanchez's answer with hsl and modern javascript, you can create a color picker with good contrast like this:

function hashCode(str) {
  let hash = 0;
  for (var i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
  }
  return hash;
}

function pickColor(str) {
  return `hsl(${hashCode(str) % 360}, 100%, 80%)`;
}

one.style.backgroundColor = pickColor(one.innerText)
two.style.backgroundColor = pickColor(two.innerText)
div {
  padding: 10px;
}
<div id="one">One</div>
<div id="two">Two</div>

Since it's hsl, you can scale luminance to get the contrast you're looking for.

function hashCode(str) {
  let hash = 0;
  for (var i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
  }
  return hash;
}

function pickColor(str) {
  // Note the last value here is now 50% instead of 80%
  return `hsl(${hashCode(str) % 360}, 100%, 50%)`;
}

one.style.backgroundColor = pickColor(one.innerText)
two.style.backgroundColor = pickColor(two.innerText)
div {
  color: white;
  padding: 10px;
}
<div id="one">One</div>
<div id="two">Two</div>

Comments

10

I find that generating random colors tends to create colors that do not have enough contrast for my taste. The easiest way I have found to get around that is to pre-populate a list of very different colors. For every new string, assign the next color in the list:

// Takes any string and converts it into a #RRGGBB color.
var StringToColor = (function(){
    var instance = null;

    return {
    next: function stringToColor(str) {
        if(instance === null) {
            instance = {};
            instance.stringToColorHash = {};
            instance.nextVeryDifferntColorIdx = 0;
            instance.veryDifferentColors = ["#000000","#00FF00","#0000FF","#FF0000","#01FFFE","#FFA6FE","#FFDB66","#006401","#010067","#95003A","#007DB5","#FF00F6","#FFEEE8","#774D00","#90FB92","#0076FF","#D5FF00","#FF937E","#6A826C","#FF029D","#FE8900","#7A4782","#7E2DD2","#85A900","#FF0056","#A42400","#00AE7E","#683D3B","#BDC6FF","#263400","#BDD393","#00B917","#9E008E","#001544","#C28C9F","#FF74A3","#01D0FF","#004754","#E56FFE","#788231","#0E4CA1","#91D0CB","#BE9970","#968AE8","#BB8800","#43002C","#DEFF74","#00FFC6","#FFE502","#620E00","#008F9C","#98FF52","#7544B1","#B500FF","#00FF78","#FF6E41","#005F39","#6B6882","#5FAD4E","#A75740","#A5FFD2","#FFB167","#009BFF","#E85EBE"];
        }

        if(!instance.stringToColorHash[str])
            instance.stringToColorHash[str] = instance.veryDifferentColors[instance.nextVeryDifferntColorIdx++];

            return instance.stringToColorHash[str];
        }
    }
})();

// Get a new color for each string
StringToColor.next("get first color");
StringToColor.next("get second color");

// Will return the same color as the first time
StringToColor.next("get first color");

While this has a limit to only 64 colors, I find most humans can't really tell the difference after that anyway. I suppose you could always add more colors.

While this code uses hard-coded colors, you are at least guaranteed to know during development exactly how much contrast you will see between colors in production.

Color list has been lifted from this SO answer, there are other lists with more colors.

2 Comments

Fwiw there's an algorithm out there to determine contrast. I wrote something with it years ago (but in C). Too much going on to worry about it and it's an old answer anyway but figured I'd point out that there is a way to determine contrast.
supplement: to wrap colours back to first after all are used, replace the 2nd if with: if(!instance.stringToColorHash[str]) { instance.nextVeryDifferntColorIdx++; instance.nextVeryDifferntColorIdx %= instance.veryDifferentColors.length; instance.stringToColorHash[str] = instance.veryDifferentColors[instance.nextVeryDifferntColorIdx]; }
8

I have opened a pull request to Please.js that allows generating a color from a hash.

You can map the string to a color like so:

const color = Please.make_color({
    from_hash: "any string goes here"
});

For example, "any string goes here" will return as "#47291b"
and "another!" returns as "#1f0c3d"

2 Comments

Really cool thanks for adding that. Hi wanting to generate circles with letters in based on a name like Google inbox does:)
when I saw this answer, I thought, perfect, now I have to think about the color schema so it doesn't generate very random colors, then I read about the Please.js make_color options and it put a beautiful smile in my face.
7

If your inputs are not different enough for a simple hash to use the entire color spectrum, you can use a seeded random number generator instead of a hash function.

I'm using the color coder from Joe Freeman's answer, and David Bau's seeded random number generator.

function stringToColour(str) {
    Math.seedrandom(str);
    var rand = Math.random() * Math.pow(255,3);
    Math.seedrandom(); // don't leave a non-random seed in the generator
    for (var i = 0, colour = "#"; i < 3; colour += ("00" + ((rand >> i++ * 8) & 0xFF).toString(16)).slice(-2));
    return colour;
}

Comments

7

Javascript Solution inspired by Aslam's solution but returns a color in hex color code

/**
 * 
 * @param {String} - stringInput - 'xyz'
 * @returns {String} - color in hex color code - '#ae6204'
 */
function getBackgroundColor(stringInput) {
    const h = [...stringInput].reduce((acc, char) => {
        return char.charCodeAt(0) + ((acc << 5) - acc);
    }, 0);
    const s = 95, l = 35 / 100;
    const a = s * Math.min(l, 1 - l) / 100;
    const f = n => {
        const k = (n + h / 30) % 12;
        const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
        return Math.round(255 * color).toString(16).padStart(2, '0');   // convert to Hex and prefix "0" if needed
    };
    return `#${f(0)}${f(8)}${f(4)}`;
}

3 Comments

This is really nice. May I use this code?
of course, you can.
For those you encounter that some hashes turn negative and the color is always gray. It turns our js converts to int32 and stuff, see SA. So I have changes the line from return char.charCodeAt(0) + ((acc << 5) - acc); to return char.charCodeAt(0) + ((acc << 5 >>> 0) - acc);
7

2025 version - Plain and simple TypeScript arrow function that returns HSL color.

const stringToColor = (value: string) => {
  let hash = 0;
  for (let i = 0; i < value.length; i++) {
    hash = value.charCodeAt(i) + ((hash << 5) - hash);
  }

  return `hsl(${hash % 360}, 85%, 35%)`;
};

Comments

5

Yet another solution for random colors:

function colorize(str) {
    for (var i = 0, hash = 0; i < str.length; hash = str.charCodeAt(i++) + ((hash << 5) - hash));
    color = Math.floor(Math.abs((Math.sin(hash) * 10000) % 1 * 16777216)).toString(16);
    return '#' + Array(6 - color.length + 1).join('0') + color;
}

It's a mixed of things that does the job for me. I used JFreeman Hash function (also an answer in this thread) and Asykäri pseudo random function from here and some padding and math from myself.

I doubt the function produces evenly distributed colors, though it looks nice and does that what it should do.

3 Comments

'0'.repeat(...) is not valid javascript
@kikito fair enough, probably I had the prototype extended somehow (JQuery?). Anyway, I've edited the function so it's javascript only... thanks for pointing that out.
@kikito it's valid ES6, though using it would be neglecting cross-browser compatibility.
4

Here's a solution I came up with to generate aesthetically pleasing pastel colours based on an input string. It uses the first two chars of the string as a random seed, then generates R/G/B based on that seed.

It could be easily extended so that the seed is the XOR of all chars in the string, rather than just the first two.

Inspired by David Crow's answer here: Algorithm to randomly generate an aesthetically-pleasing color palette

//magic to convert strings to a nice pastel colour based on first two chars
//
// every string with the same first two chars will generate the same pastel colour
function pastel_colour(input_str) {

    //TODO: adjust base colour values below based on theme
    var baseRed = 128;
    var baseGreen = 128;
    var baseBlue = 128;

    //lazy seeded random hack to get values from 0 - 256
    //for seed just take bitwise XOR of first two chars
    var seed = input_str.charCodeAt(0) ^ input_str.charCodeAt(1);
    var rand_1 = Math.abs((Math.sin(seed++) * 10000)) % 256;
    var rand_2 = Math.abs((Math.sin(seed++) * 10000)) % 256;
    var rand_3 = Math.abs((Math.sin(seed++) * 10000)) % 256;

    //build colour
    var red = Math.round((rand_1 + baseRed) / 2);
    var green = Math.round((rand_2 + baseGreen) / 2);
    var blue = Math.round((rand_3 + baseBlue) / 2);

    return { red: red, green: green, blue: blue };
}

GIST is here: https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd

2 Comments

I must say that this is a really odd way of doing it. It kind of works but there aren't very many colors available. XOR of the first two colors makes no distinction of order so there are just combinations of letters. A simple addition I did to increase the number of colors was var seed = 0; for (var i in input_str) { seed ^= i; }
Yes, it really depends how many colours you'd like to generate. I recall in this instance I was creating different panes in a UI and wanted a limited number of colours rather than a rainbow :)
1

Here is another try:

function stringToColor(str){
  var hash = 0;
  for(var i=0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 3) - hash);
  }
  var color = Math.abs(hash).toString(16).substring(0, 6);

  return "#" + '000000'.substring(0, 6 - color.length) + color;
}

Comments

1

All you really need is a good hash function. On node, I just use

const crypto = require('crypto');
function strToColor(str) {
    return '#' + crypto.createHash('md5').update(str).digest('hex').substr(0, 6);
}

Comments

1

After having a look at the rather code intensive and rather old answers, I thought I'd review this issue from a 2021 standpoint just for fun, hope it is of use to anyone. Having the HSL color model and the crypto API implemented in pretty much all browsers (except IE of course) today, it could be solved as simple as that:

async function getColor(text, minLightness = 40, maxLightness = 80, minSaturation = 30, maxSaturation = 100) {
  let hash = await window.crypto.subtle.digest("SHA-1", new TextEncoder().encode(text));
  hash = new Uint8Array(hash).join("").slice(16);

  return "hsl(" + (hash % 360) + ", " + (hash % (maxSaturation - minSaturation) + minSaturation) + "%, " + (hash % (maxLightness - minLightness) + minLightness) + "%)";
}

function generateColor() {
  getColor(document.getElementById("text-input").value).then(color => document.querySelector(".swatch").style.backgroundColor = color);
}
input {
  padding: 5px;
}

.swatch {
  margin-left: 10px;
  width: 28px;
  height: 28px;
  background-color: white;
  border: 1px solid gray;
}

.flex {
  display: flex;
}
<html>

<body>
  <div class="flex">
    <form>
      <input id="text-input" type="text" onInput="generateColor()" placeholder="Type here"></input>
    </form>
    <div class="swatch"></div>
  </div>
</body>

</html>

This should be way faster than generating hashes manually, and also offers a way to define saturation and lightness in case you don't want colors that are too flat or too bright or too dark (e.g. if you want to write text on those colors).

Comments

0

I have a situation where i want to display a background based on the username of the user and display the username's first letter on top. i used the belove code for that it worked well for me

var stringToColour = function (str) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
  hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
var colour = '#';
for (var i = 0; i < 3; i++) {
  var value = (hash >> (i * 8)) & 0xff;
  colour += ('00' + value.toString(16)).substr(-2);
}
return colour;}

To find the appropriate colour you can use

function lightOrDark(color) {
// Check the format of the color, HEX or RGB?
if (color.match(/^rgb/)) {
  // If HEX --> store the red, green, blue values in separate variables
  color = color.match(
    /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/,
  );

  var r = color[1];
  var g = color[2];
  var b = color[3];
} else {
  // If RGB --> Convert it to HEX: http://gist.github.com/983661
  color = +(
    '0x' + color.slice(1).replace(color.length < 5 && /./g, '$&$&')
  );

  r = color >> 16;
  g = (color >> 8) & 255;
  b = color & 255;
}

// HSP equation from http://alienryderflex.com/hsp.html
var hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));

// Using the HSP value, determine whether the color is light or dark
if (hsp > 127.5) {
  return 'light';
} else {
  return 'dark';
}

}

Comments

0

my code is for Java.

Thanks for all.

public static int getColorFromText(String text)
    {
        if(text == null || text.length() < 1)
            return Color.BLACK;

        int hash = 0;

        for (int i = 0; i < text.length(); i++)
        {
            hash = text.charAt(i) + ((hash << 5) - hash);
        }

        int c = (hash & 0x00FFFFFF);
        c = c - 16777216;

        return c;
    }

Comments

-1

This function does the trick. It's an adaptation of this, fairly longer implementation this repo ..

const color = (str) => {
    let rgb = [];
    // Changing non-hexadecimal characters to 0
    str = [...str].map(c => (/[0-9A-Fa-f]/g.test(c)) ? c : 0).join('');
    // Padding string with zeroes until it adds up to 3
    while (str.length % 3) str += '0';

    // Dividing string into 3 equally large arrays
    for (i = 0; i < str.length; i += str.length / 3)
        rgb.push(str.slice(i, i + str.length / 3));

    // Formatting a hex color from the first two letters of each portion
    return `#${rgb.map(string => string.slice(0, 2)).join('')}`;
}

1 Comment

This generates a lot of very dark values.
-7

I convert this in one line for Python

import hashlib

hash = hashlib.sha1(b'[email protected]').hexdigest()

print("#" + hash[0:6])

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.