使用 JavaScript 根据字符串创建十六进制颜色

Posted

技术标签:

【中文标题】使用 JavaScript 根据字符串创建十六进制颜色【英文标题】:Create a hexadecimal colour based on a string with JavaScript 【发布时间】:2011-03-26 11:31:08 【问题描述】:

我想创建一个可以接受任何旧字符串(通常是单个单词)的函数,并从该函数以某种方式#000000#FFFFFF 之间生成一个十六进制值,所以我可以将其用作 html 元素的颜色。

如果不那么复杂,甚至可以是一个简写的十六进制值(例如:#FFF)。事实上,来自“网络安全”调色板的颜色将是理想的。

【问题讨论】:

能否提供一些示例输入和/或类似问题的链接? 不是答案,但您可能会发现以下内容很有用:要将十六进制转换为整数,请使用 parseInt(hexstr, 10)。要将整数转换为十六进制,请使用n.toString(16),其中 n 是整数。 @qw3n - 示例输入:只是简短的、普通的旧文本字符串...例如“医学”、“外科”、“神经病学”、“全科医学”等。范围在 3 到 20 之间字符...找不到另一个,但这是 java 问题:***.com/questions/2464745/…@Daniel - 谢谢。我需要坐下来再认真考虑一下。可能有用。 【参考方案1】:

这是对 CD Sanchez 答案的改编,始终返回 6 位颜色代码:

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;

用法:

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

例子:

http://jsfiddle.net/sUK45/

(另一种/更简单的解决方案可能涉及返回 'rgb(...)' 样式的颜色代码。)

【讨论】:

这段代码与 NoSQL 自动生成的 ID 结合使用非常棒,对于同一个用户,您的颜色每次都相同。 我还需要 Alpha 通道来提高十六进制代码的透明度。这有帮助(在我的十六进制代码末尾为 alpha 通道添加两位数字):gist.github.com/lopspower/03fb1cc0ac9f32ef38f4 @Tjorriemorrie Upvoted 指出它是颜色而不是颜色。是的,是的,它不是真正的主题,但它对我来说很重要(事实上,在最初输入它时,我两次都拼写为“颜色”!)。谢谢。 有趣的是不同浏览器/oss上相同字符串的颜色不同 - 例如Chrome+Windows 和 Chrome+android - 我的电子邮件=>颜色是蓝色的,另一种是绿色的。知道为什么吗? 谢谢!对此进行了改编,仅从字符串中生成柔和/明亮的颜色***.com/a/64490863/403372【参考方案2】:

只需将 Java 从 Compute hex color code for an arbitrary string 移植到 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;

要转换你会这样做:

intToRGB(hashCode(your_string))

【讨论】:

需要填充十六进制字符串,如:("00" + ((this &gt;&gt; 24) &amp; 0xFF).toString(16)).slice(-2) + ("00" + ((this &gt;&gt; 16) &amp; 0xFF).toString(16)).slice(-2) + ("00" + ((this &gt;&gt; 8) &amp; 0xFF).toString(16)).slice(-2) + ("00" + (this &amp; 0xFF).toString(16)).slice(-2); 我正在将一堆音乐流派标签转换为背景颜色,这为我节省了很多时间。 我希望我可以将其转换为 php 我对相似字符串的颜色几乎相同有一些问题,例如:intToRGB(hashCode('hello1')) -&gt; "3A019F" intToRGB(hashCode('hello2')) -&gt; "3A01A0" 我通过为最终哈希值添加乘法来增强您的代码:return 100 * hash; 别忘了加 '#' 比如 return "#" + "00000".substring(0, 6 - c.length) + c;【参考方案3】:

我希望 HTML 元素的颜色具有类似的丰富性,我惊讶地发现 CSS 现在支持 hsl() 颜色,所以下面是一个完整的解决方案:

另请参阅How to automatically generate N "distinct" colors?,了解更多与此类似的替代方案。

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;

在 HSL 中,它的色相、饱和度、亮度。所以0-359之间的色调会得到所有的颜色,饱和度是你想要的颜色有多丰富,100%对我有用。而Lightness决定了深度,50%是正常的,25%是深色的,75%是柔和的。我有 30%,因为它最适合我的配色方案。

【讨论】:

一个非常通用的解决方案。 感谢分享一个解决方案,您可以在其中决定颜色应该有多多彩! @haykam 感谢您将其制作成 sn-p! 这种方法非常有用,可以提供我的应用所需的活力/微妙。随机十六进制的饱和度和亮度变化太大,在大多数情况下都没有用。谢谢! 这个解决方案返回的颜色太少,不行。【参考方案4】:

这是我的 2021 版本,带有缩减功能和 HSL 颜色。

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

【讨论】:

优雅的解决方案。谢谢。 哈哈!我怎么会错过这个答案?与我提出的解决方案非常相似;-)【参考方案5】:

使用hashCode 和 Cristian Sanchez 的回答中的 hsl 和现代 javascript,您可以创建一个具有良好对比度的颜色选择器,如下所示:

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>

由于它是 hsl,因此您可以缩放亮度以获得所需的对比度。

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>

【讨论】:

【参考方案6】:

我发现生成随机颜色往往会产生对比度不足以满足我口味的颜色。我发现解决这个问题的最简单方法是预先填充一个非常不同颜色的列表。对于每个 new 字符串,分配列表中的下一个颜色:

// 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");

虽然这仅限于 64 种颜色,但我发现大多数人在此之后都无法真正区分它们。我想你总是可以添加更多的颜色。

虽然此代码使用硬编码颜色,但至少可以保证您在开发过程中确切地知道生产中颜色之间的对比度。

颜色列表已从this SO answer 提升,还有其他颜色列表。

【讨论】:

Fwiw 有一种算法可以确定对比度。几年前我用它写了一些东西(但在 C 中)。太多的事情要担心,无论如何这是一个旧答案,但我想指出有一种方法可以确定对比度。 补充:全部用完后将颜色换回第一个,如果用:if(!instance.stringToColorHash[str]) instance.nextVeryDifferntColorIdx++; instance.nextVeryDifferntColorIdx %= instance.veryDifferentColors.length; instance.stringToColorHash[str] = instance.veryDifferentColors[instance.nextVeryDifferntColorIdx]; 替换第二个【参考方案7】:

我打开了a pull request 到Please.js,它允许从哈希中生成颜色。

你可以把字符串映射成这样的颜色:

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

例如,"any string goes here" 将返回为 "#47291b""another!" 返回为 "#1f0c3d"

【讨论】:

真的很酷感谢添加。您好,想根据 Google 收件箱之类的名称生成带有字母的圈子:) 当我看到这个答案时,我想,完美,现在我必须考虑颜色模式,这样它就不会生成非常随机的颜色,然后我阅读了有关 Please.js make_color 选项和它的信息在我脸上露出美丽的笑容。【参考方案8】:

如果您的输入差异不足以让简单哈希使用整个色谱,您可以使用种子随机数生成器而不是哈希函数。

我正在使用 Joe Freeman 的回答中的颜色编码器和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;

【讨论】:

【参考方案9】:

另一种随机颜色的解决方案:

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;

这对我来说是一个混合的工作。 我使用了来自 here 的 JFreeman Hash 函数(也是这个线程中的答案)和 Asykäri 伪随机函数,以及我自己的一些填充和数学。

我怀疑该函数会产生均匀分布的颜色,尽管它看起来不错并且可以做到它应该做的。

【讨论】:

'0'.repeat(...) 不是有效的 javascript @kikito 很公平,可能我以某种方式扩展了原型(JQuery?)。无论如何,我已经编辑了函数,所以它只是 javascript...感谢您指出这一点。 @kikito 它是有效的 ES6,尽管使用它会忽略跨浏览器兼容性。【参考方案10】:

这是我想出的一种解决方案,可以根据输入字符串生成美观的柔和颜色。它使用字符串的前两个字符作为随机种子,然后根据该种子生成 R/G/B。

它可以很容易地扩展,以便种子是字符串中所有字符的 XOR,而不仅仅是前两个。

受到 David Crow 在此处的回答的启发: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 在这里:https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd

【讨论】:

我必须说这是一种非常奇怪的做法。它有点工作,但没有很多颜色可用。前两种颜色的 XOR 不区分顺序,因此只有字母组合。我为增加颜色数量所做的一个简单添加是 var seed = 0; for (var i in input_str) 种子 ^= i; 是的,这真的取决于您想要生成多少种颜色。我记得在这种情况下,我在 UI 中创建了不同的窗格,并且想要有限数量的颜色而不是彩虹:)【参考方案11】:

这是另一个尝试:

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;

【讨论】:

【参考方案12】:

您真正需要的只是一个好的散列函数。在节点上,我只是使用

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

【讨论】:

【参考方案13】:

这个函数可以解决问题。这是对此的改编,相当长的实现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('')`;

【讨论】:

这会产生很多非常暗的值。【参考方案14】:

我将其转换为 Java。

所有人的坦克。

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;
    

【讨论】:

【参考方案15】:

在查看了相当密集的代码和相当老的答案之后,我想我会从 2021 年的角度来回顾这个问题,只是为了好玩,希望它对任何人都有用。现在几乎所有浏览器(当然除了 IE)都实现了 HSL 颜色模型和加密 API,它可以像这样简单地解决:

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>

这应该比手动生成哈希快得多,并且还提供了一种定义饱和度和亮度的方法,以防您不希望颜色太平、太亮或太暗(例如,如果您想在那些颜色)。

【讨论】:

【参考方案16】:

受 Aslam 解决方案启发的 Javascript 解决方案,但以十六进制颜色代码返回颜色

/**
 * 
 * @param String - stringInput 
 * @returns String - color in hex color code 
 */
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)`;

【讨论】:

【参考方案17】:

我将其转换为 Python 的一行

import hashlib

hash = hashlib.sha1(b'user@email.com').hexdigest()

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

【讨论】:

以上是关于使用 JavaScript 根据字符串创建十六进制颜色的主要内容,如果未能解决你的问题,请参考以下文章

如何将 javascript regexp 中的 Euro € 符号与八进制、十六进制或 unicode 元字符匹配?

Java学习总计(二十六)——JavaScript正则表达式,Js表单验证,原生js+css页面时钟

在Javascript中将rgb字符串转换为十六进制

JavaScript字符串概述

JavaScript中进制和字符编码问题

如何使用 javascript 从 Web 服务返回的二进制字符串构建 PDF 文件