배경색에 따라 흰색 또는 검은 색의 글꼴 색상을 결정하는 방법은 무엇입니까?


220

이 예제와 같은 이미지를 보여주고 싶습니다대체 텍스트

채우기 색상은 16 진수 색상 (예 : ClassX-> 색상 : # 66FFFF)으로 데이터베이스의 필드에 의해 결정됩니다. 이제 선택한 색상으로 채우기 위에 데이터를 표시하려고하지만 (위 이미지와 같이) 색상이 어둡거나 밝은 지 알아야 단어가 흰색 또는 검은 색이어야하는지 알 수 있습니다. 방법이 있습니까? tks


답변:


347

비슷한 질문 에 대한 내 대답을 바탕으로 .

개별 빨강, 녹색 및 파랑 강도를 얻으려면 16 진 코드를 3 개 조각으로 나누어야합니다. 코드의 각 2 자리 숫자는 16 진수 (기본 16) 표기법으로 값을 나타냅니다. 변환에 대한 자세한 내용은 다루지 않겠지 만 쉽게 찾을 수 있습니다.

개별 색상의 강도가 확보되면 색상의 전체 강도를 결정하고 해당 텍스트를 선택할 수 있습니다.

if (red*0.299 + green*0.587 + blue*0.114) > 186 use #000000 else use #ffffff

186의 임계 값은 이론을 기반으로하지만 취향에 따라 조정할 수 있습니다. 150 이하의 의견에 따라 귀하에게 더 효과적 일 수 있습니다.


편집 : 위의 내용은 간단하고 합리적으로 잘 작동하며 StackOverflow에서 잘 수용 된 것 같습니다. 그러나 아래 의견 중 하나는 일부 상황에서 W3C 지침을 준수하지 않을 수 있음을 보여줍니다. 여기에서는 항상 지침에 따라 가장 높은 대비를 선택하는 수정 된 양식을 도출합니다. 당신이 경우 하지 않는 W3C 규칙을 준수 할 필요가 나는 위의 간단한 공식으로 다루고 싶어요.

W3C 권장 사항 에서 대비를 위해 제공된 공식 은입니다 (L1 + 0.05) / (L2 + 0.05). 여기서 L1가장 밝은 색 L2의 휘도는 0.0-1.0의 스케일에서 가장 어두운 색 의 휘도입니다. 검은 색의 휘도는 0.0이고 흰색은 1.0이므로이 값을 대체하면 대비가 가장 높은 것을 결정할 수 있습니다. 검은 색 대비가 흰색 대비보다 높으면 검은 색을 사용하고 그렇지 않으면 흰색을 사용하십시오. 테스트가 진행됨에 L따라 테스트 중인 색상의 휘도가 주어진 경우 :

if (L + 0.05) / (0.0 + 0.05) > (1.0 + 0.05) / (L + 0.05) use #000000 else use #ffffff

이것은 다음과 같이 대수적으로 단순화됩니다.

if L > sqrt(1.05 * 0.05) - 0.05

또는 대략 :

if L > 0.179 use #000000 else use #ffffff

남은 것은 계산하는 것 L입니다. 이 공식은 지침 에도 나와 있으며 sRGB에서 선형 RGB로 변환 한 후 휘도 에 대한 ITU-R 권장 사항 BT.709 를 따르는 것처럼 보입니다 .

for each c in r,g,b:
    c = c / 255.0
    if c <= 0.03928 then c = c/12.92 else c = ((c+0.055)/1.055) ^ 2.4
L = 0.2126 * r + 0.7152 * g + 0.0722 * b

0.179의 임계 값은 W3C 지침과 관련되어 있으므로 변경해서는 안됩니다. 원하는 결과를 찾지 못하면 위의 간단한 공식을 시도하십시오.


2
Tks 마크 몇 가지 변화를 시도했습니다 : 첫 번째 숫자로만 빨강 녹색과 파랑을 계산하고 (정확하지만 무게가 더 큰 숫자입니다) 대신 186을 사용했습니다. 9, 특히 녹색으로 조금 더 잘 작동합니다.
DJPB

2
이 공식은 잘못되었습니다. 한 가지 예를 들자면, 노랑 #D6B508의 값은 171이되어 흰색의 대비가됩니다. 그러나 대비는 검은 색이어야합니다 (여기서 확인 : webaim.org/resources/contrastchecker )
McGarnagle

1
@MarkRansom 그래, 내 눈에 검은 색이 그 노란색으로 훨씬 좋아 보인다. 제한된 색상 세트로 작업하고 있기 때문에 컷오프를 186에서 더 낮은 값으로 옮길 수있었습니다.
McGarnagle

3
이 답변에 주어진 두 공식을 비교하는 또 다른 데모가 있습니다. 색상 선택기 (최근 Firefox 또는 Chrome에서)를 사용하여 모든 색상과 대비를 확인할 수 있습니다.
chetstone

3
@chetstone의 데모를 약간 사용한 후에는 임계 값 권장 사항에 동의하지 않는 것을 제외하고 간단한 수식이 가장 효과적이라고 생각합니다. 순수한 녹색의 결과를 바탕으로 임계 값을 149로 설정하려고 시도했는데 내 의견으로는 훨씬 잘 작동합니다. 나는 이것을 증명하기 위해 정말 바보 같은 바이올린을 만들었습니다 . 원래 제안을 보려면 상단에서 임계 값을 변경해보십시오.
Miral

30

이 코드는 내 코드가 아니기 때문에 크레딧을 얻지 않지만 나중에 다른 사람들이 빨리 찾을 수 있도록 여기에 남겨 둡니다.

Mark Ransoms 답변을 바탕으로 간단한 버전의 코드 스 니펫이 있습니다.

function pickTextColorBasedOnBgColorSimple(bgColor, lightColor, darkColor) {
  var color = (bgColor.charAt(0) === '#') ? bgColor.substring(1, 7) : bgColor;
  var r = parseInt(color.substring(0, 2), 16); // hexToR
  var g = parseInt(color.substring(2, 4), 16); // hexToG
  var b = parseInt(color.substring(4, 6), 16); // hexToB
  return (((r * 0.299) + (g * 0.587) + (b * 0.114)) > 186) ?
    darkColor : lightColor;
}

다음은 고급 버전의 코드 스 니펫입니다.

function pickTextColorBasedOnBgColorAdvanced(bgColor, lightColor, darkColor) {
  var color = (bgColor.charAt(0) === '#') ? bgColor.substring(1, 7) : bgColor;
  var r = parseInt(color.substring(0, 2), 16); // hexToR
  var g = parseInt(color.substring(2, 4), 16); // hexToG
  var b = parseInt(color.substring(4, 6), 16); // hexToB
  var uicolors = [r / 255, g / 255, b / 255];
  var c = uicolors.map((col) => {
    if (col <= 0.03928) {
      return col / 12.92;
    }
    return Math.pow((col + 0.055) / 1.055, 2.4);
  });
  var L = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2]);
  return (L > 0.179) ? darkColor : lightColor;
}

그것들을 사용하려면 전화하십시오 :

var color = '#EEACAE' // this can be any color
pickTextColorBasedOnBgColorSimple(color, '#FFFFFF', '#000000');

또한, 감사 Alxchetstone.


1
단순히 2 개 마지막 매개 변수를 떨어 이름 : 나는 단순한 기능을 사용하고,보다 약간 아래를 벗겨 isDark(bgColor)내 사용이 바로 그때입니다'color': isDark(color)?'white':'black'
diynevala

1
나를 위해 매력처럼 일했습니다. 대단히 감사합니다! 단순히 구문과 함수를 변환하지만 PHP에서 했습니까?
CezarBastos

18

어떻습니까 (JavaScript 코드)?

/**
 * Get color (black/white) depending on bgColor so it would be clearly seen.
 * @param bgColor
 * @returns {string}
 */
getColorByBgColor(bgColor) {
    if (!bgColor) { return ''; }
    return (parseInt(bgColor.replace('#', ''), 16) > 0xffffff / 2) ? '#000' : '#fff';
}

1
이것은 대부분의 시간에 작동하지만 i.imgur.com/3pOUDe5.jpg 와 같이 이상하게 보이는 경우가 있으며 배경색은 실제로 rgb (6, 247, 241)입니다.
madprops

색상을 RGB 값으로 변환하지 않은 경우 (이는 너무 어렵지 않고 추가 수학 단계 임) 대비 대비 계산을 수행하는 비교적 저렴한 방법입니다.
frumbert

12

산술 솔루션 외에도 AI 신경망을 사용할 수도 있습니다. 장점은 자신의 취향과 요구에 맞게 조정할 수 있다는 것입니다 (즉, 밝은 채도 빨간색의 흰색 텍스트는 좋아 보이고 검정처럼 읽을 수 있습니다).

다음은 개념을 보여주는 깔끔한 Javascript 데모입니다. 데모에서 직접 JS 공식을 생성 할 수도 있습니다.

https://harthur.github.io/brain/

아래는 문제를 해결 하는 데 도움이되는 몇 가지 차트입니다 . 첫 번째 차트에서 밝기는 128이며 상수와 채도는 다릅니다. 두 번째 차트에서 채도는 상수 255이며 색조와 밝기는 다릅니다.

첫 번째 차트에서 밝기는 상수 128이며 색조와 채도는 다양합니다.

채도는 상수 255이며 색조와 밝기는 다양합니다.


8

다음은 Java 용 Android 솔루션입니다.

// Put this method in whichever class you deem appropriate
// static or non-static, up to you.
public static int getContrastColor(int colorIntValue) {
    int red = Color.red(colorIntValue);
    int green = Color.green(colorIntValue);
    int blue = Color.blue(colorIntValue);
    double lum = (((0.299 * red) + ((0.587 * green) + (0.114 * blue))));
    return lum > 186 ? 0xFF000000 : 0xFFFFFFFF;
}

// Usage
// If Color is represented as HEX code:
String colorHex = "#484588";
int color = Color.parseColor(colorHex);

// Or if color is Integer:
int color = 0xFF484588;

// Get White (0xFFFFFFFF) or Black (0xFF000000)
int contrastColor = WhateverClass.getContrastColor(color);

2
정말 '완벽'합니까? 순수한 녹색 배경, # 00FF00을 사용해보십시오.
Andreas Rejbrand

이것이 모든 색상에 대해 테스트되지는 않았다는 것이 사실 입니다 .... 누가 사용자를 귀찮게하지 않도록 설계된 순수한 녹색 배경을 사용합니까?
mwieczorek

@mwieczorek 사용자 생성 콘텐츠 또는 무작위로 선택한 색상에 의존하는 사람들.
Marc Plano-Lesay

4

@MarkRansom의 답변을 바탕으로 여기에서 찾을 수있는 PHP 스크립트를 만들었습니다.

function calcC($c) {
    if ($c <= 0.03928) {
        return $c / 12.92;
    }
    else {
        return pow(($c + 0.055) / 1.055, 2.4);
    }
}

function cutHex($h) {
    return ($h[0] == "#") ? substr($h, 1, 7) : $h;
}

function hexToR($h) {
    return hexdec(substr(cutHex($h), 0, 2));
}

function hexToG($h) {
    return hexdec(substr(cutHex($h), 2, 2)); // Edited
}

function hexToB($h) {
    return hexdec(substr(cutHex($h), 4, 2)); // Edited
}

function computeTextColor($color) {
    $r = hexToR($color);
    $g = hexToG($color);
    $b = hexToB($color);
    $uicolors = [$r / 255, $g / 255, $b / 255];


    $c = array_map("calcC", $uicolors);

    $l = 0.2126 * $c[0] + 0.7152 * $c[1] + 0.0722 * $c[2];
    return ($l > 0.179) ? '#000000' : '#ffffff';
}

3

이것은 UIColor의 확장으로서 Mark Ransom의 빠른 답변입니다.

extension UIColor {

// Get the rgba components in CGFloat
var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
    var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0

    getRed(&red, green: &green, blue: &blue, alpha: &alpha)

    return (red, green, blue, alpha)
}

/// Return the better contrasting color, white or black
func contrastColor() -> UIColor {
    let rgbArray = [rgba.red, rgba.green, rgba.blue]

    let luminanceArray = rgbArray.map({ value -> (CGFloat) in
        if value < 0.03928 {
            return (value / 12.92)
        } else {
            return (pow( (value + 0.55) / 1.055, 2.4) )
        }
    })

    let luminance = 0.2126 * luminanceArray[0] +
        0.7152 * luminanceArray[1] +
        0.0722 * luminanceArray[2]

    return luminance > 0.179 ? UIColor.black : UIColor.white
} }

2

이것은 요소를 클릭 할 때 SVG 체크 표시의 색상을 변경하는 예제 일뿐입니다. 클릭 한 요소의 배경색을 기준으로 체크 표시 색상을 검은 색 또는 흰색으로 설정합니다.

checkmarkColor: function(el) {
    var self = el;
    var contrast = function checkContrast(rgb) {
        // @TODO check for HEX value

        // Get RGB value between parenthesis, and remove any whitespace
        rgb = rgb.split(/\(([^)]+)\)/)[1].replace(/ /g, '');

        // map RGB values to variables
        var r = parseInt(rgb.split(',')[0], 10),
            g = parseInt(rgb.split(',')[1], 10),
            b = parseInt(rgb.split(',')[2], 10),
            a;

        // if RGBA, map alpha to variable (not currently in use)
        if (rgb.split(',')[3] !== null) {
            a = parseInt(rgb.split(',')[3], 10);
        }

        // calculate contrast of color (standard grayscale algorithmic formula)
        var contrast = (Math.round(r * 299) + Math.round(g * 587) + Math.round(b * 114)) / 1000;

        return (contrast >= 128) ? 'black' : 'white';
    };

    $('#steps .step.color .color-item .icon-ui-checkmark-shadow svg').css({
        'fill': contrast($(self).css('background-color'))
    });
}

onClickExtColor: function(evt) {
    var self = this;

    self.checkmarkColor(evt.currentTarget);
}

https://gist.github.com/dcondrey/183971f17808e9277572


2

나는 변환이 자바 스크립트 기능을 사용 rgb/ rgba'white'또는 'black'.

function getTextColor(rgba) {
    rgba = rgba.match(/\d+/g);
    if ((rgba[0] * 0.299) + (rgba[1] * 0.587) + (rgba[2] * 0.114) > 186) {
        return 'black';
    } else {
        return 'white';
    }
}

이 형식 중 하나를 입력하면 출력 'black'또는'white'

  • rgb(255,255,255)
  • rgba(255,255,255,0.1)
  • color:rgba(255,255,255,0.1)
  • 255,255,255,0.1

이제 순수한 녹색 배경으로 시도하십시오 : # 00FF00.
Andreas Rejbrand

감사합니다! 스위프트로 번역하여 내 iOS 앱에서 사용했습니다!
Lucas P.

2

Mark의 자세한 답변 은 훌륭합니다. 다음은 자바 스크립트 구현입니다.

function lum(rgb) {
    var lrgb = [];
    rgb.forEach(function(c) {
        c = c / 255.0;
        if (c <= 0.03928) {
            c = c / 12.92;
        } else {
            c = Math.pow((c + 0.055) / 1.055, 2.4);
        }
        lrgb.push(c);
    });
    var lum = 0.2126 * lrgb[0] + 0.7152 * lrgb[1] + 0.0722 * lrgb[2];
    return (lum > 0.179) ? '#000000' : '#ffffff';
}

그런 다음이 함수 lum([111, 22, 255])를 호출 하여 흰색 또는 검은 색을 얻을 수 있습니다 .


1

나는 이런 식으로 아무것도 한 적이 없지만 Hex 7F (FF / 2)의 중간 색과 각 색의 값을 확인하는 함수를 작성하는 것은 어떻습니까. 세 가지 색상 중 두 가지가 7F보다 큰 경우 더 어두운 색상으로 작업하는 것입니다.


1

배경 과이 스레드 에 따라 전경색을 검은 색 또는 흰색으로 만들기 링크에서 다른 입력을 기반으로 필요한 대비 색상을 제공하는 Color 확장 클래스를 만들었습니다.

코드는 다음과 같습니다.

 public static class ColorExtension
{       
    public static int PerceivedBrightness(this Color c)
    {
        return (int)Math.Sqrt(
        c.R * c.R * .299 +
        c.G * c.G * .587 +
        c.B * c.B * .114);
    }
    public static Color ContrastColor(this Color iColor, Color darkColor,Color lightColor)
    {
        //  Counting the perceptive luminance (aka luma) - human eye favors green color... 
        double luma = (iColor.PerceivedBrightness() / 255);

        // Return black for bright colors, white for dark colors
        return luma > 0.5 ? darkColor : lightColor;
    }
    public static Color ContrastColor(this Color iColor) => iColor.ContrastColor(Color.Black);
    public static Color ContrastColor(this Color iColor, Color darkColor) => iColor.ContrastColor(darkColor, Color.White);
    // Converts a given Color to gray
    public static Color ToGray(this Color input)
    {
        int g = (int)(input.R * .299) + (int)(input.G * .587) + (int)(input.B * .114);
        return Color.FromArgb(input.A, g, g, g);
    }
}

1

나처럼 알파를 고려한 RGBA 버전을 찾고 있다면 여기 고 대비를 유지하는 데 효과적입니다.

function getContrastColor(R, G, B, A) {
  const brightness = R * 0.299 + G * 0.587 + B * 0.114 + (1 - A) * 255;

  return brightness > 186 ? "#000000" : "#FFFFFF";
}

1

이것은 기본 R 만 사용하는 Mark Ransom의 R 버전입니다.

hex_bw <- function(hex_code) {

  myrgb <- as.integer(col2rgb(hex_code))

  rgb_conv <- lapply(myrgb, function(x) {
    i <- x / 255
    if (i <= 0.03928) {
      i <- i / 12.92
    } else {
      i <- ((i + 0.055) / 1.055) ^ 2.4
    }
    return(i)
  })

 rgb_calc <- (0.2126*rgb_conv[[1]]) + (0.7152*rgb_conv[[2]]) + (0.0722*rgb_conv[[3]])

 if (rgb_calc > 0.179) return("#000000") else return("#ffffff")

}

> hex_bw("#8FBC8F")
[1] "#000000"
> hex_bw("#7fa5e3")
[1] "#000000"
> hex_bw("#0054de")
[1] "#ffffff"
> hex_bw("#2064d4")
[1] "#ffffff"
> hex_bw("#5387db")
[1] "#000000"

0

@SoBiT, 나는 당신의 대답을보고 있었는데, 그것은 좋아 보이지만 작은 실수가 있습니다. hexToG 및 hextoB 함수를 약간 편집해야합니다. substr의 마지막 숫자는 문자열의 길이이므로이 경우 4 또는 6이 아니라 "2"여야합니다.

function hexToR($h) {
    return hexdec(substr(cutHex($h), 0, 2));
}
function hexToG($h) {
    return hexdec(substr(cutHex($h), 2, 2));
}
function hexToB($h) {
    return hexdec(substr(cutHex($h), 4, 2));
}

0

LESS는 contrast()나에게 잘 작동 하는 멋진 기능을 가지고 있습니다. http://lesscss.org/functions/#color-operations-contrast를 참조 하십시오

"두 색상 중 어떤 색상을 다른 색상과 가장 대비가 좋은지 선택하십시오. 이는 배경에 대해 색상을 읽을 수 있도록하는 데 유용하며, 접근성 준수에도 유용합니다.이 기능은 SASS for Compass의 대비 기능과 동일한 방식으로 작동합니다. WCAG 2.0에 따르면 색상은 밝기가 아니라 감마 보정 된 루마 값을 사용하여 비교됩니다. "

예:

p {
    a: contrast(#bbbbbb);
    b: contrast(#222222, #101010);
    c: contrast(#222222, #101010, #dddddd);
    d: contrast(hsl(90, 100%, 50%), #000000, #ffffff, 30%);
    e: contrast(hsl(90, 100%, 50%), #000000, #ffffff, 80%);
}

산출:

p {
    a: #000000 // black
    b: #ffffff // white
    c: #dddddd
    d: #000000 // black
    e: #ffffff // white
}

0

16 진수에서 흑백으로 :

function hexToRgb(hex) {
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result
    ? [
        parseInt(result[1], 16),
        parseInt(result[2], 16),
        parseInt(result[3], 16)
      ]
    : [0, 0, 0];
}

function lum(hex) {
  var rgb = hexToRgb(hex)
  var lrgb = [];
  rgb.forEach(function(c) {
    c = c / 255.0;
    if (c <= 0.03928) {
      c = c / 12.92;
    } else {
      c = Math.pow((c + 0.055) / 1.055, 2.4);
    }
    lrgb.push(c);
  });
  var lum = 0.2126 * lrgb[0] + 0.7152 * lrgb[1] + 0.0722 * lrgb[2];
  return lum > 0.179 ? "#000000" : "#ffffff";
}

0

Mark의 답변을 기반으로하는 iOS 용 Objective-C 버전 코드 :

- (UIColor *)contrastForegroundColor {
CGFloat red = 0, green = 0, blue = 0, alpha = 0;
[self getRed:&red green:&green blue:&blue alpha:&alpha];
NSArray<NSNumber *> *rgbArray = @[@(red), @(green), @(blue)];
NSMutableArray<NSNumber *> *parsedRGBArray = [NSMutableArray arrayWithCapacity:rgbArray.count];
for (NSNumber *item in rgbArray) {
    if (item.doubleValue <= 0.03928) {
        [parsedRGBArray addObject:@(item.doubleValue / 12.92)];
    } else {
        double newValue = pow((item.doubleValue + 0.055) / 1.055, 2.4);
        [parsedRGBArray addObject:@(newValue)];
    }
}

double luminance = 0.2126 * parsedRGBArray[0].doubleValue + 0.7152 * parsedRGBArray[1].doubleValue + 0.0722 * parsedRGBArray[2].doubleValue;

return luminance > 0.179 ? UIColor.blackColor : UIColor.whiteColor;
}

0

모든 24 비트 색상으로 테스트하는 것은 어떻습니까?

YIQ 방법은 128 임계 값을 가정 할 때 AA 및 AAA WCAG2.0 테스트를 통과하지 않는 최소 명암비 1.9 : 1을 반환합니다.

W3C 방법의 경우 큰 텍스트에 대해 AA 및 AAA 테스트를 통과하는 최소 명암비 4.58 : 1을 반환하고 작은 텍스트에 대해 AA 테스트를 수행하면 모든 색상에 대해 작은 텍스트에 대해 AAA 테스트를 통과하지 않습니다.


0

여기에 내가 사용하고 지금까지 문제가 없었던 내 자신의 방법이 있습니다.

const hexCode = value.charAt(0) === '#' 
                  ? value.substr(1, 6)
                  : value;

const hexR = parseInt(hexCode.substr(0, 2), 16);
const hexG = parseInt(hexCode.substr(2, 2), 16);
const hexB = parseInt(hexCode.substr(4, 2), 16);
// Gets the average value of the colors
const contrastRatio = (hexR + hexG + hexB) / (255 * 3);

contrastRatio >= 0.5
  ? 'black'
  : 'white';


0

Mark의 놀라운 답변을 기반으로 한 Java Swing 코드는 다음과 같습니다.

public static Color getColorBasedOnBackground(Color background, Color darkColor, Color lightColor) {
    // Calculate foreground color based on background (based on https://stackoverflow.com/a/3943023/)
    Color color;
    double[] cL = new double[3];
    double[] colorRGB = new double[] {background.getRed(), background.getGreen(), background.getBlue()};

    for (int i = 0; i < colorRGB.length; i++)
        cL[i] = (colorRGB[i] / 255.0 <= 0.03928) ? colorRGB[i] / 255.0 / 12.92 :
                Math.pow(((colorRGB[i] / 255.0 + 0.055) / 1.055), 2.4);

    double L = 0.2126 * cL[0] + 0.7152 * cL[1] + 0.0722 * cL[2];
    color = (L > Math.sqrt(1.05 * 0.05) - 0.05) ? darkColor : lightColor;

    return color;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.