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


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

또한, 감사 Alx와 chetstone.


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.