2010-10-15 84 views
94

Tôi muốn hiển thị một số hình ảnh như ví dụ này alt textLàm thế nào để quyết định màu phông chữ màu trắng hoặc đen tùy thuộc vào màu nền?

Màu tô được quyết định bởi trường trong cơ sở dữ liệu có màu hex (ví dụ: ClassX -> Màu: # 66FFFF). Bây giờ, tôi muốn hiển thị dữ liệu ở trên tô màu với màu đã chọn (như trong hình ở trên) nhưng tôi cần biết nếu màu tối hoặc sáng để tôi biết các từ phải có màu trắng hay đen. Có cách nào không? tks

+0

Xem ở đây: http://stackoverflow.com/questions/946544/good-text-foreground-color-for-a-given-background-color/946734#946734 –

+0

Có liên quan (nhưng cũng có hai mặt): http://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color http: // stackoverflow. com/questions/3116260/given-a-background-color-how-to-get-a-foreground-color-that-make-it-readable-on – JYelton

Trả lời

173

Xây dựng trên số answer to a similar question của tôi.

Bạn cần phải chia mã hex thành 3 phần để có được cường độ màu đỏ, xanh lục và xanh riêng lẻ. Mỗi 2 chữ số của mã đại diện cho một giá trị theo ký hiệu thập lục phân (base-16). Tôi sẽ không đi vào chi tiết của việc chuyển đổi ở đây, họ dễ dàng tìm kiếm.

Khi bạn có cường độ cho từng màu, bạn có thể xác định cường độ tổng thể của màu và chọn văn bản tương ứng.

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


Edit: Trên đây là đơn giản và hoạt động khá tốt, và dường như có sự chấp nhận tốt ở đây tại StackOverflow. Tuy nhiên, một trong những ý kiến ​​dưới đây cho thấy nó có thể dẫn đến việc không tuân thủ các nguyên tắc của W3C trong một số trường hợp. Theo Thông tư này tôi lấy được một hình thức sửa đổi luôn chọn độ tương phản cao nhất dựa trên các nguyên tắc.

Công thức đưa ra cho tương phản trong W3C Recommendations(L1 + 0.05)/(L2 + 0.05), nơi L1 là độ sáng của màu sắc nhẹ và L2 là độ sáng của đen tối nhất trên thang điểm từ 0.0-1.0. Độ sáng của màu đen là 0,0 và màu trắng là 1,0, do đó thay thế các giá trị đó cho phép bạn xác định giá trị có độ tương phản cao nhất. Nếu độ tương phản của màu đen lớn hơn độ tương phản của màu trắng, hãy sử dụng màu đen, nếu không thì sẽ sử dụng màu trắng. Căn cứ vào độ sáng của màu sắc mà bạn đang thử nghiệm như L bài kiểm tra trở thành:

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

này đơn giản hóa xuống đại số để:

if L > sqrt(1.05 * 0.05) - 0.05 

Hoặc khoảng:

if L > 0.179 use #000000 else use #ffffff 

Điều duy nhất còn lại là để tính L. Công thức đó cũng là given in the guidelines và có vẻ như chuyển đổi từ sRGB sang RGB tuyến tính theo sau là ITU-R recommendation BT.709 cho độ sáng.

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 
+3

Cách tốt hơn câu trả lời của tôi –

+2

Tks Mark. Đã thử một vài thay đổi: tính màu đỏ xanh lục và xanh dương bằng chữ số đầu tiên (ít chính xác hơn nhưng là chữ số có trọng lượng hơn) và thay vì 186 đã sử dụng 9. hoạt động tốt hơn một chút đối với tôi, đặc biệt với rau xanh. – DJPB

+0

@DJPB, có vẻ như đơn giản hóa rất lớn. Việc chuyển đổi từ RGB sang màu xám gần như chắc chắn giới thiệu nhiều lỗi hơn việc giảm số thứ hai, và tất cả những gì bạn cần là một phép tính xấp xỉ. Sự lựa chọn của ngưỡng có rất nhiều thời gian quá, nhận thức của con người là khó khăn để pin xuống. –

1

Tôi chưa bao giờ làm bất cứ điều gì như thế này, nhưng còn cách viết một hàm để kiểm tra các giá trị của từng màu đối với màu trung bình của Hex 7F (FF/2). Nếu hai trong số ba màu lớn hơn 7F, thì bạn đang làm việc với màu tối hơn.

2

Đây chỉ là ví dụ sẽ thay đổi màu của dấu kiểm SVG khi nhấp vào phần tử. Nó sẽ đặt màu dấu kiểm thành màu đen hoặc trắng dựa trên màu nền của phần tử được nhấp.

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

13

Làm thế nào về vấn đề này (mã 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'; 
} 
+0

Điều này hoạt động hầu hết thời gian nhưng có những trường hợp như http://i.imgur.com/3pOUDe5.jpg trông kỳ lạ, màu nền thực sự là rgb (6, 247, 241); – madprops

+0

Tôi đánh giá cao đây là một cách tương đối rẻ để thực hiện tính toán độ tương phản trong trường hợp bạn chưa chuyển đổi màu thành giá trị rgb (không quá khó, chỉ cần thêm các bước toán) – frumbert

4

Đây là giải pháp của tôi trong Java dành cho 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); 
+0

Giải pháp hoàn hảo –

+0

Thực sự là 'hoàn hảo '? Hãy thử nền màu xanh lục tinh khiết, # 00FF00. –

+0

Đúng là điều này không được thử nghiệm cho tất cả * màu * .... nhưng ai sẽ sử dụng nền màu xanh lục tinh khiết cho bất kỳ thứ gì không được thiết kế để làm phiền người dùng? – mwieczorek

1

tôi sử dụng hàm JavaScript này để chuyển đổi rgb/rgba-'white' hoặc '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'; 
    } 
} 

Bạn có thể nhập bất kỳ các định dạng và nó sẽ ra 'black' hoặc 'white'

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

Bây giờ hãy thử điều này với nền màu xanh lục tinh khiết: # 00FF00. –

7

Tôi sẽ không có tín dụng cho mã này vì nó không phải là của tôi, nhưng tôi để nó ở đây cho những người khác để tìm một cách nhanh chóng trong tương lai:

Dựa trên Đánh dấu chuộc câu trả lời, đây là một đoạn mã cho phiên bản đơn giản:

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; 
} 

và đây là đoạn mã cho phiên bản cao cấp:

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; 
} 

để sử dụng chúng chỉ cần gọi:

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

Ngoài ra, cảm ơn Alxchetstone.

+0

Tôi sử dụng chức năng đơn giản, và tước nó xuống một chút nữa: bỏ 2 tham số cuối cùng và đổi tên chỉ đơn giản là 'isDark (bgColor)' Sử dụng của tôi sau đó chỉ là '' màu ': isDark (màu)?' Trắng ':' black'' – diynevala

1

Dựa trên câu trả lời của @MarkRansom, tôi tạo ra một kịch bản PHP bạn có thể tìm thấy ở đây:

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, 4)); 
} 

function hexToB($h) { 
    return hexdec(substr(cutHex($h), 4, 6)); 
} 

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'; 
} 
0

@SoBiT, tôi đã nhìn vào câu trả lời của bạn, mà có vẻ tốt, nhưng có một sai lầm nhỏ trong nó. Hàm hexToG của bạn và hàm hextoB cần chỉnh sửa nhỏ. Số cuối cùng trong substr là chiều dài của chuỗi, và như vậy trong trường hợp này itshould là "2", chứ không phải là 4 hoặc 6.

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 có contrast() chức năng thoải mái mà làm việc độc đáo cho tôi, xem http://lesscss.org/functions/#color-operations-contrast

"Chọn một trong hai màu cung cấp độ tương phản lớn nhất với màu khác Điều này rất hữu ích để đảm bảo rằng một màu có thể đọc được trên nền, cũng hữu ích cho việc tuân thủ khả năng truy cập. Chức năng này hoạt động tương tự như độ tương phản chức năng trong Compass cho SASS.Đối với WCAG 2.0, màu sắc được so sánh bằng cách sử dụng giá trị luma gamma-sửa chữa của họ, không phải của họ li ghtness."

Ví dụ:

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%); 
} 

Output:

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

Ngoài ra các giải pháp số học, nó cũng có thể sử dụng một mạng lưới thần kinh AI Ưu điểm là bạn có thể chỉnh nó để bạn. sở thích và nhu cầu của riêng bạn (ví dụ: văn bản màu trắng trên các màu đỏ bão hòa tươi sáng có vẻ tốt và chỉ có thể đọc được như màu đen)

Đây là một bản trình diễn Javascript gọn gàng minh họa khái niệm. Bạn cũng có thể tạo công thức JS của riêng bạn ngay trong bản trình diễn.

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

Dưới đây là một số bảng xếp hạng đã giúp tôi có được tâm trí của tôi around the problem. Trong biểu đồ đầu tiên, độ sáng là một hằng số 128, trong khi màu sắc và độ bão hòa khác nhau. Trong biểu đồ thứ hai, độ bão hòa là hằng số 255, trong khi màu sắc và độ sáng thay đổi.

In the first chart, lightness is a constant 128, while hue and saturation vary:

Saturation is a constant 255, while hue and lightness vary:

Các vấn đề liên quan