Create a hexadecimal colour based on a string with JavaScript

JavascriptStringColorsHex

Javascript Problem Overview


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.

Javascript Solutions


Solution 1 - Javascript

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

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;
}

Usage:

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

Example:

http://jsfiddle.net/sUK45/

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

Solution 2 - Javascript

Just porting over the Java from https://stackoverflow.com/questions/2464745/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))

Solution 3 - Javascript

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 https://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors/4382138#4382138 for more alternatives more similar to this.

function colorByHashCode(value) {
    return "<span style='color:" + value.getHashCode().intToHSL() + "'>" + value + "</span>";
}
String.prototype.getHashCode = function() {
    var hash = 0;
    if (this.length == 0) return hash;
    for (var i = 0; i < this.length; i++) {
        hash = this.charCodeAt(i) + ((hash << 5) - hash);
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
};
Number.prototype.intToHSL = function() {
    var shortened = this % 360;
    return "hsl(" + shortened + ",100%,30%)";
};

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.

Solution 4 - Javascript

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%)`;
}

Solution 5 - Javascript

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>

Solution 6 - Javascript

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.

Solution 7 - Javascript

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"

Solution 8 - Javascript

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;
}

Solution 9 - Javascript

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.

Solution 10 - Javascript

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: https://stackoverflow.com/questions/43044/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

Solution 11 - Javascript

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)}`;
}

Solution 12 - Javascript

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;
}

Solution 13 - Javascript

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);
}

Solution 14 - Javascript

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).

Solution 15 - Javascript

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('')}`;
}

Solution 16 - Javascript

I convert this for Java.

Tanks 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;
	}

Solution 17 - Javascript

I convert this in one line for Python

import hashlib

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDarragh EnrightView Question on Stackoverflow
Solution 1 - JavascriptJoe FreemanView Answer on Stackoverflow
Solution 2 - JavascriptCristian SanchezView Answer on Stackoverflow
Solution 3 - JavascriptThymineView Answer on Stackoverflow
Solution 4 - JavascriptAslamView Answer on Stackoverflow
Solution 5 - JavascriptKyle KelleyView Answer on Stackoverflow
Solution 6 - JavascriptRick SmithView Answer on Stackoverflow
Solution 7 - JavascriptJosue Alexander IbarraView Answer on Stackoverflow
Solution 8 - JavascriptNathanView Answer on Stackoverflow
Solution 9 - JavascriptestaniView Answer on Stackoverflow
Solution 10 - JavascriptRobert SharpView Answer on Stackoverflow
Solution 11 - JavascriptViraj SinghView Answer on Stackoverflow
Solution 12 - JavascriptkikitoView Answer on Stackoverflow
Solution 13 - JavascriptpulsejetView Answer on Stackoverflow
Solution 14 - JavascriptLupinity LabsView Answer on Stackoverflow
Solution 15 - JavascriptTheódór Ágúst MagnússonView Answer on Stackoverflow
Solution 16 - JavascriptAli BagheriView Answer on Stackoverflow
Solution 17 - JavascriptfoadView Answer on Stackoverflow