【发布时间】:2010-10-12 17:03:40
【问题描述】:
在我们目前正在处理的其中一个页面上,用户可以更改所显示文本的背景。
我们希望自动更改前景色以保持文本的合理对比度。
我们还希望颜色范围可以自行决定。例如,如果背景以 255 个增量从白色变为黑色,我们不希望看到 255 种前景色。在这种情况下,可能是 2 到 4,只是为了保持合理的对比度。
是否有任何 UI/设计/色彩专家/画家来制定公式?
【问题讨论】:
在我们目前正在处理的其中一个页面上,用户可以更改所显示文本的背景。
我们希望自动更改前景色以保持文本的合理对比度。
我们还希望颜色范围可以自行决定。例如,如果背景以 255 个增量从白色变为黑色,我们不希望看到 255 种前景色。在这种情况下,可能是 2 到 4,只是为了保持合理的对比度。
是否有任何 UI/设计/色彩专家/画家来制定公式?
【问题讨论】:
您可能想要改变色调,而不是饱和度或值。
因此,将您的 RGB 值转换为 HSV,将 180 度添加到 H(当然是模 360 度),然后转换回 RGB。
【讨论】:
就纯粹的可读性而言,您希望在任何背景上使用黑白文本。因此将 RGB 转换为 HSV,只需检查 V 是否
先尝试一下,看看你是否觉得它有吸引力。
如果你不这样做,那么当你的背景太亮或太暗时,你可能希望白色和黑色不要太鲜明。要将其调低,请保持相同的色调和饱和度,并将这些值用于亮度:
background V foreground V
0.0-0.25 0.75
0.25-0.5 1.0
0.5-0.75 0.0
0.75-1.0 0.25
在中等颜色上,您仍会看到清晰易读的黑色或白色文本。在深色或浅色上,您会看到相同的颜色文本,但亮度至少相差 3/4,因此仍然可读。我希望它看起来不错:)
【讨论】:
由于 javascript 处理十进制值的方式,实现起来有点复杂。 为此,我发现让背景更改任何颜色但文本只是在黑白之间切换会更好。 如果你使用对比色,很多组合将很难忍受。另请注意,有些人是色盲,因此从可访问性的角度来看,这不是一个好主意。
【讨论】:
试试this example,它只是根据 r、g 和 b 值的平均值将其设置为黑色或白色。也适合测试!如果发现效果不佳的情况,请在其中替换更好的算法。
<html>
<head>
<script>
function rgbstringToTriplet(rgbstring)
{
var commadelim = rgbstring.substring(4,rgbstring.length-1);
var strings = commadelim.split(",");
var numeric = [];
for(var i=0; i<3; i++) { numeric[i] = parseInt(strings[i]); }
return numeric;
}
function adjustColour(someelement)
{
var rgbstring = someelement.style.backgroundColor;
var triplet = rgbstringToTriplet(rgbstring);
var newtriplet = [];
// black or white:
var total = 0; for (var i=0; i<triplet.length; i++) { total += triplet[i]; }
if(total > (3*256/2)) {
newtriplet = [0,0,0];
} else {
newtriplet = [255,255,255];
}
var newstring = "rgb("+newtriplet.join(",")+")";
someelement.style.color = newstring;
return true;
}
function randomiseBackground(someelement)
{
var vals = [];
for(var i=0; i<3; i++) { vals[i]=Math.floor(Math.random()*256+1); }
someelement.style.backgroundColor="rgb("+vals.join(",")+")";
return true;
}
</script>
</head>
<body onload="adjustColour(document.getElementById('mypara'));">
<p id="mypara" style="background-color:#2287ea">Some text</p>
<form>
<input type=button onclick="var elem=document.getElementById('mypara'); randomiseBackground(elem); adjustColour(elem);" value="randomise background" />
</form>
</body>
</html>
【讨论】:
根据亮度做出黑白决定对我来说效果很好。亮度是 R、G 和 B 值的加权和,根据人类对相对亮度的感知进行调整,这在视频应用中显然很常见。亮度的官方定义随着时间的推移而改变,具有不同的权重;见这里:http://en.wikipedia.org/wiki/Luma_(video)。我使用 Rec 获得了最好的结果。 709 版本,如下面的代码所示。 165 左右的黑白阈值似乎不错。
function contrastingColor(color)
{
return (luma(color) >= 165) ? '000' : 'fff';
}
function luma(color) // color can be a hx string or an array of RGB values 0-255
{
var rgb = (typeof color === 'string') ? hexToRGBArray(color) : color;
return (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]); // SMPTE C, Rec. 709 weightings
}
function hexToRGBArray(color)
{
if (color.length === 3)
color = color.charAt(0) + color.charAt(0) + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2);
else if (color.length !== 6)
throw('Invalid hex color: ' + color);
var rgb = [];
for (var i = 0; i <= 2; i++)
rgb[i] = parseInt(color.substr(i * 2, 2), 16);
return rgb;
}
【讨论】:
如果你使用的是d3.js,你可以做一些判断
d3.hsl(d3.color("black")).l > 0.5 ? "#000" : "fff"(简单但未必完美)
或
getLuma(r, g, b, fmt) > 165 ? "#000" : "#fff"见示例 2
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
const bgColorList = ["black", "purple", "#cc1515", "green", "blue", "red", "yellow", "white"]
window.onload = () => {
d3.select("body").append("section")
.selectAll("div")
.data(bgColorList)
.enter().append("div")
.text((bgColor, idx, arr) => {
const div = arr[idx]
const {h, l} = d3.hsl(d3.color(bgColor))
const foreColor = l > 0.5 ? "#000" : "#fff"
div.outerHTML = `<div style="width:100px;height:50px;
background-color: ${bgColor};
color:${foreColor}
">Hello world</div>`
})
}
</script>
但是当l等于0.5(例如:黄色、蓝色)时,就会有争议。
<script src="https://d3js.org/d3.v7.min.js"></script>
<table>
<tr>
<th>601</th>
<th>709</th>
<th>240</th>
</tr>
<tr id="output"></tr>
</table>
<script>
/**
* https://en.wikipedia.org/wiki/Luma_%28video%29
* @param {"601"|"709"|"240"|"145"} format
*/
function getLuma(r, g, b, format) {
switch (format) {
case "601":
return 0.2999 * r + 0.587 * g + 0.114 * b
case "709":
return 0.2126 * r + 0.7152 * g + 0.0722 * b
case "145":
case "240":
return 0.212 * r + 0.701 * g + 0.087 * b
}
}
const bgColorList = [...Array(100).keys()].map(t => d3.scaleSequential(d3.interpolateTurbo)(t / 100))
.concat(["black", "purple", "#cc1515", "green", "blue", "red", "white", "yellow"])
window.onload = () => {
const tdArr = []
d3.select("#output")
.selectAll("td")
.data(["601", "709", "240"])
.enter().append("td")
.text((fmt, _idx, _arr) => {
const td = _arr[_idx]
tdArr.push([td, fmt])
})
tdArr.forEach(([td, fmt]) => {
d3.select(td).append("section")
.selectAll("div")
.data(bgColorList)
.enter().append("div")
.text((bgColor, idx, arr) => {
const div = arr[idx]
const {r, g, b} = d3.color(bgColor)
const foreColor = getLuma(r, g, b, fmt) > 165 ? "#000" : "#fff"
// const coefficient = [0.2126, 0.7152, 0.0722]
// const foreColor = [r, g, b].reduce((sum, color, i) => sum + color * coefficient[i], 0) > 165 ? "#000" : "#fff"
div.outerHTML = `<div style="width:100px;height:26px;
background-color: ${bgColor};
color:${foreColor}
">Hello</div>`
})
})
}
</script>
【讨论】: