【问题标题】:Adjust color based on contrast根据对比度调整颜色
【发布时间】:2021-12-29 19:20:50
【问题描述】:

对于我正在开发的模组,我想结合播放器的主题颜色并使用它们来生成 UI 元素。但是,我遇到了一个问题,即并非所有颜色主题都具有提供 good contrast ratio 的颜色,如 Web Content Accessibility Guidelines (WCAG) 2.11.4.3 Contrast (Minimum) 中所述。

我目前可以通过以下方式检查对比度:

float RelativeLuminance(Color color)
{
    float ColorPartValue(float part)
    {
        return part <= 0.03928f ? part / 12.92f : Mathf.Pow((part + 0.055f) / 1.055f, 2.4f);
    }
    var r = ColorPartValue(color.r);
    var g = ColorPartValue(color.g);
    var b = ColorPartValue(color.b);

    var l = 0.2126f * r + 0.7152f * g + 0.0722f * b;
    return l;
}

private float ColorContrast(Color a, Color b)
{
    float result = 0f;
    var La = RelativeLuminance(a) + 0.05f;
    var Lb = RelativeLuminance(b) + 0.05f;

    result = Mathf.Max(La, Lb) / Mathf.Min(La, Lb);

    return result;
}

我使用找到的颜色对比来确定初始文本颜色是否足够好。

public Color GetContrastingColors(Color backgroundColor, Color textColor)
{
    Color contrastColor;

    // See if we have good enough contrast already
    if (!(ColorContrast(backgroundColor, textColor) < 4.5f))
    {
        return textColor;
    }

    Color.RGBToHSV(textColor, out var textH, out var textS, out var textV);
    Color.RGBToHSV(backgroundColor, out var bgH, out var bgS, out var bgV);

    // Modify textV by some value to provide enough contrast.

    contrastColor = Color.HSVToRGB(textH, textS, textV);

    return contrastColor;
}

但是,我不确定如何调整颜色以使文本颜色变亮(或变暗)以达到 4.5:1 的对比度。最初,我正在考虑将亮度和对比度方程的代数工作到sRGB 值乘以某个值 X 的程度。不过我记得 HSV,调整颜色的亮度对我来说似乎要简单得多。问题是,我不确定如何比较 2 种 HSV 颜色的对比度,更不用说使用它们的值来操纵颜色的亮度以达到所需的对比度。

我目前的想法是做这样的蠢事:

float targetL;
bool brighter = false;
var backL = RelativeLuminance(backgroundColor);
var textL = RelativeLuminance(textColor);
var ratio = 4.5f;

// Try to go in the direction of brightness originally.
if (textL > backL)
{
    targetL = ((backL + 0.05f) * ratio) - 0.05f;
    brighter = true;

    if (targetL > 1f)
    {
        targetL = ((backL + 0.05f) / ratio) - 0.05f;
        brighter = false;
    }
}
else
{
    targetL = ((backL + 0.05f) / ratio) - 0.05f;
    if (targetL > 0f)
    {
        targetL = ((backL + 0.05f) * ratio) - 0.05f;
        brighter = true;
    }
}

Color adjustedColor = textColor;

while ((!brighter && textL > targetL) || (brighter && textL < targetL))
{
    Color.RGBToHSV(adjustedColor, out var textH, out var textS, out var textV);

    textV += brighter ? 0.01f : -0.01f;

    adjustedColor = Color.HSVToRGB(textH, textS, textV);
    textL = RelativeLuminance(adjustedColor);
}

contrastColor = adjustedColor;

但这并不是很有效,那么我该如何操作文本颜色以使其“保持不变”但提供足够的对比度?

编辑:

为了给我正在尝试做的事情提供更多背景信息,假设我有以下 4 种颜色作为玩家的主题。

就 HTML 代码而言,就是:

#32263d #3d1c70
#7347b6 #320d68

在为他们创建 UI 时,我想从他们的主题中加入其中 2 种颜色。但是,并非所有这些都易于区分,您可以在此处查看本例中的各种对比:

现在每个主题都包含较深和较浅的颜色,就像本示例中的中间 2 行一样,但也像本示例一样,最终用户可能无法始终阅读它们的对比度。继续看示例,在本例中,我们将使用 #32263d#7347b6 来构建我们的 UI。

虽然我可以尝试随机创建类似的紫色阴影,但我希望使其尽可能接近原始颜色并使其变亮。我们可以在这里看到它在不同层次的光线下的样子:

如果我们将#7347b6 设置为#a163ff 的最大亮度,我们现在得到以下一对:

虽然比以前更好,但这仍然只是 3.88 : 1 的对比度。所以现在我想缩小#32263d 的亮度。如果我们把它减少到#251B2D,我们就会得到这样的结果:

这两种新颜色的颜色对比度为 4.51 : 1。

现在,我可以手动浏览每个主题,但考虑到它们的数量,我更愿意编写一个算法来动态生成更新的颜色。

【问题讨论】:

  • “我想合并播放器的主题颜色并使用它们来生成 UI 元素。但是,我遇到了一个问题,并非所有颜色主题都有提供良好的颜色对比度” - 你说的是"Complementary - Two colors that are on opposite sides of the color wheel. This combination provides a high contrast and high impact color combination – together, these colors will appear brighter and more prominent."吗?
  • @MickyD 不,我指的是玩家对象主题中的一对颜色,例如new Color(0.1647059f, 0.3098039f, 0.5843138f, 1f)new Color(0.2196078f, 0.254902f, 0.3098039f, 1f)。它们不一定是互补的,也不一定如此。
  • 快速查看Adobe Color - Accessibility Tools - Contrast Checker 表明您选择#2A4E95#37414E 只需将背景 颜色更改为#A8C5E9 即可。这将实现 4.5:1 的对比度。听起来您的问题只是如何计算给定文本颜色的可访问性背景颜色Possibility relevant
  • @MickyD “听起来你的问题只是如何计算给定文本颜色的可访问性背景颜色。”是/否。我可以这样做,但这只是变相的相同问题(我仍然需要根据另一种颜色计算颜色)。我的问题是我试图保持“相同”的颜色,只需在 HSV 比例上调整它的亮度(与我将 RGB 分量乘以一个因子x 的结果相同)。更改为#A8C5E9 实际上会以与我的意图不同的方式调整它们。 (1/2)
  • 举个例子,如果给我#80b9ff#5b6b80(对比度为2.67),我想降低#5b6b80的亮度直到它变成#505d70(对比度为 4.55,#80b9ff)。它仍然具有相同的色调和饱和度,只是亮度不同。现在,我扔在那里的这些颜色只是游戏中内置的几种颜色。我无法修改它们,所以我需要使用它们。我的问题是如何调整它们? (2/2)

标签: c# unity3d colors accessibility


【解决方案1】:

查看我对Adapt given color pairs to adhere to W3C Accessibility standard for ePubs的回答

你可以跳过我谈论对比度公式的部分,因为你已经有了,但我谈论的是如何调整颜色以获得更好的对比度。

如果我要根据上一个答案实际编写我的建议,我会更有效率,而不是从每个 RGB 分量中添加或减去 1 并重新计算亮度,我可能会添加/减去 10 并重新计算。如果对比度不够,再做 10 次。一旦我得到足够的对比度,我就可以重新调整值,也许每次调整 2,在相反的方向,直到我接近 4.5 而不会下降。

【讨论】:

    【解决方案2】:

    我最终还是为我的代码使用了循环。虽然slugolicious 的答案接近我想要的,但我发现将所有 RGB 分量调整相同的量并不是我想要的,因为实际上会影响色调,所以我最终改用 HSV。

    public Color[] GetContrastingColors(Color backgroundColor, Color textColor, float ratio)
    {
        Color[] colors = new Color[2];
    
        var backL = RelativeLuminance(backgroundColor);
        var textL = RelativeLuminance(textColor);
    
        if (textL > backL)
        {
            colors[0] = textColor;
            colors[1] = backgroundColor;
        }
        else
        {
            colors[1] = textColor;
            colors[0] = backgroundColor;
        }
    
        // See if we have good enough contrast already
        if (!(ColorContrast(backgroundColor, textColor) < ratio))
        {
            return colors;
        }
    
        Color.RGBToHSV(colors[0], out var lightH, out var lightS, out var lightV);
        Color.RGBToHSV(colors[1], out var darkH, out var darkS, out var darkV);
    
        // If the darkest color can be darkened enough to have enough contrast after brightening the color.
        if (ColorContrast(Color.HSVToRGB(darkH, darkS, 0f), Color.HSVToRGB(lightH, lightS, 1f)) >= ratio)
        {
            var lightDiff = 1f - lightV;
            var darkDiff = darkV;
    
            var steps = new float[] { 0.12f, 0.1f, 0.08f, 0.05f, 0.04f, 0.03f, 0.02f, 0.01f, 0.005f };
            var step = 0;
    
            var lightRatio = (lightDiff / (lightDiff + darkDiff));
            var darkRatio = (darkDiff / (lightDiff + darkDiff));
    
            while (ColorContrast(Color.HSVToRGB(lightH, lightS, lightV), Color.HSVToRGB(darkH, darkS, darkV)) < ratio)
            {
                while (ColorContrast(Color.HSVToRGB(lightH, lightS, lightV + lightRatio * steps[step]), Color.HSVToRGB(darkH, darkS, darkV - darkRatio * steps[step])) > ratio && step < steps.Length - 1)
                {
                    step++;
                }
                lightV += lightRatio * steps[step];
                darkV -= darkRatio * steps[step];
            }
    
            colors[0] = Color.HSVToRGB(lightH, lightS, lightV);
            colors[1] = Color.HSVToRGB(darkH, darkS, darkV);
        }
        // Fall back to using white.
        else
        {
            colors[0] = Color.white;
    
            while (ColorContrast(Color.white, Color.HSVToRGB(darkH, darkS, darkV)) < ratio)
            {
                darkV -= 0.01f;
            }
    
            colors[1] = Color.HSVToRGB(darkH, darkS, darkV);
        }
    
        return colors;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-11
      • 2013-06-25
      • 2011-10-19
      • 1970-01-01
      • 1970-01-01
      • 2011-10-09
      • 2017-06-13
      相关资源
      最近更新 更多