Определите цвет шрифта на основе цвета фона
При наличии системы (например, веб-сайта), которая позволяет пользователю настраивать цвет фона для некоторого раздела, но не цвет шрифта (чтобы свести к минимуму количество параметров), существует ли способ программно определить, является ли "свет" или " темный цвет шрифта нужен?
Я уверен, что есть какой-то алгоритм, но я не знаю достаточно о цветах, яркости и т. Д., Чтобы понять это самостоятельно.
23 ответа
Я столкнулся с подобной проблемой. Мне пришлось найти хороший метод выбора цвета контрастного шрифта для отображения текстовых меток на цветовых шкалах / тепловых картах. Это должен был быть универсальный метод, а генерируемый цвет должен был быть "хорошо выглядящим", а это значит, что простое генерирование дополнительного цвета не было хорошим решением - иногда оно генерировало странные, очень интенсивные цвета, которые было трудно смотреть и читать.
После долгих часов тестирования и попыток решить эту проблему, я обнаружил, что лучшее решение - выбрать белый шрифт для "темных" цветов и черный шрифт для "ярких" цветов.
Вот пример функции, которую я использую в C#:
Color ContrastColor(Color color)
{
int d = 0;
// Counting the perceptive luminance - human eye favors green color...
double luminance = ( 0.299 * color.R + 0.587 * color.G + 0.114 * color.B)/255;
if (luminance > 0.5)
d = 0; // bright colors - black font
else
d = 255; // dark colors - white font
return Color.FromArgb(d, d, d);
}
Это было проверено для многих различных цветовых шкал (радуга, оттенки серого, жара, лед и многие другие) и является единственным "универсальным" методом, который я обнаружил.
редактировать
Изменена формула подсчета a
на "перцептивную яркость" - это действительно выглядит лучше! Уже реализовал это в моем программном обеспечении, выглядит великолепно.
Edit 2@WebSeed предоставил отличный рабочий пример этого алгоритма: http://codepen.io/WebSeed/full/pvgqEq/
На тот случай, если кому-то понравится более короткая, возможно, более понятная версия ответа GaceK:
public Color ContrastColor(Color iColor)
{
// Calculate the perceptive luminance (aka luma) - human eye favors green color...
double luma = ((0.299 * iColor.R) + (0.587 * iColor.G) + (0.114 * iColor.B)) / 255;
// Return black for bright colors, white for dark colors
return luma > 0.5 ? Color.Black : Color.White;
}
Примечание: я убрал инверсию значения яркости (чтобы яркие цвета имели более высокое значение, что мне кажется более естественным, а также метод расчета по умолчанию).
Я использовал те же самые константы, что и GaceK, поскольку они отлично сработали для меня.
(Вы также можете реализовать это как метод расширения, используя следующую подпись:
public static Color ContrastColor(this Color iColor)
Вы можете позвонить через foregroundColor = background.ContrastColor()
.)
Спасибо @Gacek. Вот версия для Android:
@ColorInt
public static int getContrastColor(@ColorInt int color) {
// Counting the perceptive luminance - human eye favors green color...
double a = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
int d;
if (a < 0.5) {
d = 0; // bright colors - black font
} else {
d = 255; // dark colors - white font
}
return Color.rgb(d, d, d);
}
И улучшенная (более короткая) версия:
@ColorInt
public static int getContrastColor(@ColorInt int color) {
// Counting the perceptive luminance - human eye favors green color...
double a = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
return a < 0.5 ? Color.BLACK : Color.WHITE;
}
Моя быстрая реализация ответа Гацека:
func contrastColor(color: UIColor) -> UIColor {
var d = CGFloat(0)
var r = CGFloat(0)
var g = CGFloat(0)
var b = CGFloat(0)
var a = CGFloat(0)
color.getRed(&r, green: &g, blue: &b, alpha: &a)
// Counting the perceptive luminance - human eye favors green color...
let luminance = 1 - ((0.299 * r) + (0.587 * g) + (0.114 * b))
if luminance < 0.5 {
d = CGFloat(0) // bright colors - black font
} else {
d = CGFloat(1) // dark colors - white font
}
return UIColor( red: d, green: d, blue: d, alpha: a)
}
Короткий ответ:
Вычислите яркость (Y) данного цвета и переверните текст в черный или белый цвет на основе заранее определенного среднего значения контрастности. Для типичного дисплея sRGB переключитесь на белый, если Y <0,4 (т. Е. 40%).
Более длинный ответ
Неудивительно, что почти каждый ответ здесь представляет собой какое-то недоразумение и / или цитирует неверные коэффициенты. Единственный ответ, который на самом деле близок, - это ответ Seirios , хотя он полагается на контраст WCAG 2, который, как известно, сам по себе неверен.
Если я говорю «неудивительно», то отчасти это связано с огромным количеством дезинформации в Интернете по этой конкретной теме. Тот факт, что эта область все еще является предметом активных исследований и нерешенной науки, добавляет удовольствия. Я пришел к такому выводу в результате последних нескольких лет исследований нового метода прогнозирования контрастности для удобочитаемости.
Поле зрительного восприятия плотное и абстрактное, а также развивающееся, поэтому часто возникают недопонимания. Например, HSV и HSL даже близко не являются точными с точки зрения восприятия. Для этого вам нужна единообразная модель восприятия, такая как CIELAB, CIELUV или CIECAM02 и т. Д.
Некоторые недоразумения даже проникли в стандарты, такие как контрастная часть WCAG 2 (1.4.3), которая показала себя неверной на большей части своего диапазона.
Первое исправление:
Коэффициенты, показанные здесь во многих ответах (.299, .587, .114), неверны, поскольку они относятся к давно устаревшей системе, известной как NTSC YIQ, системе аналогового вещания в Северной Америке несколько десятилетий назад. Хотя они все еще могут использоваться в некоторых спецификациях кодирования YCC для обратной совместимости, их не следует использовать в контексте sRGB.
Коэффициенты для sRGB и Rec.709 (HDTV):
- Красный: 0,2126
- Зеленый: 0,7152
- Синий: 0,0722
Другие цветовые пространства, такие как Rec2020 или AdobeRGB, используют другие коэффициенты, и важно использовать правильные коэффициенты для данного цветового пространства.
Коэффициенты нельзя применять непосредственно к 8-битному изображению или данным цвета в кодировке sRGB. Кодированные данные должны быть сначала линеаризованы, а затем применены коэффициенты для определения яркости (значения освещенности) данного пикселя или цвета.
Для sRGB существует кусочное преобразование, но поскольку нас интересует только воспринимаемый контраст яркости, чтобы найти точку для «переворачивания» текста с черного на белый, мы можем сократить путь с помощью простого гамма-метода.
Яркость и легкость Энди
Разделите каждый цвет sRGB на 255,0, затем увеличьте до степени 2,2, затем умножьте на коэффициенты и просуммируйте их, чтобы найти оценочную яркость.
let Ys = Math.pow(sR/255.0,2.2) * 0.2126 +
Math.pow(sG/255.0,2.2) * 0.7152 +
Math.pow(sB/255.0,2.2) * 0.0722; // Andy's Easy Luminance for sRGB. For Rec709 HDTV change the 2.2 to 2.4
Здесь Y - относительная яркость монитора sRGB по шкале от 0,0 до 1,0. Однако это не относится к восприятию, и нам нужны дальнейшие преобразования, чтобы соответствовать нашему человеческому визуальному восприятию относительной легкости, а также воспринимаемого контраста.
40% флип
Но прежде чем мы доберемся до этого , если вы ищете только базовую точку, чтобы перевернуть текст с черного на белый или наоборот, хитрость состоит в том, чтобы использовать только что полученную Y и сделать точку переворота вокруг
Y = 0.40;
. поэтому для цветов выше 0,4 Y сделайте текст черным
#000
а для цветов темнее 0,4 Y сделайте текст белым.
#fff
.
let textColor = (Ys < 0.4) ? "#fff" : "#000"; // Low budget down and dirty text flipper.
Почему 40%, а не 50%? Наше человеческое восприятие света / тьмы и контраста не является линейным. Для дисплея с собственной подсветкой бывает, что 0,4 Y составляет примерно средний контраст в наиболее типичных условиях.
Да, это по-разному, и да, это чрезмерное упрощение. Но если вы переворачиваете текст черным или белым, простой ответ будет полезным.
Перцептивный бонусный раунд
Прогнозирование восприятия данного цвета и яркости по-прежнему является предметом активных исследований, а не полностью устоявшейся наукой. L* (Lstar) CIELAB или LUV использовался для прогнозирования воспринимаемой легкости и даже для прогнозирования воспринимаемого контраста. Однако L* хорошо работает для цветов поверхности в очень определенной / контролируемой среде и не работает так же хорошо для дисплеев с собственной подсветкой.
Хотя это зависит не только от типа и калибровки дисплея, но и от вашей среды и всего содержимого страницы, если вы возьмете Y сверху и увеличите его примерно на ^ 0,685 до ^ 0,75, вы обнаружите, что 0,5 обычно составляет средняя точка, чтобы перевернуть текст с белого на черный.
let textColor = (Math.pow(Ys,0.75) < 0.5) ? "#fff" : "#000"; // perceptually based text flipper.
Использование показателя степени 0,685 приведет к замене цвета текста на более темный цвет, а использование 0,8 сделает замену текста на более светлый цвет.
Двойной бонусный раунд пространственной частоты
Полезно отметить, что контраст - это НЕ просто расстояние между двумя цветами. Пространственная частота, другими словами, вес и размер шрифта также являются КРИТИЧНЫМИ факторами, которые нельзя игнорировать.
Тем не менее, вы можете обнаружить, что когда цвета находятся в среднем диапазоне, вы захотите увеличить размер и / или вес шрифта.
let textSize = "16px";
let textWeight = "normal";
let Ls = Math.pow(Ys,0.7);
if (Ls > 0.33 && Ls < 0.66) {
textSize = "18px";
textWeight = "bold";
} // scale up fonts for the lower contrast mid luminances.
Hue RU
Подробное описание выходит за рамки этого поста, но выше мы игнорируем оттенок и цветность. Оттенок и цветность действительно имеют эффект, например, Гельмгольца Кольрауша, и более простые расчеты яркости, приведенные выше, не всегда предсказывают интенсивность из-за насыщенных оттенков.
Чтобы предсказать эти более тонкие аспекты восприятия, необходима полная модель внешнего вида. Р. Хант, М. Фэршилд, Э. Бернс - вот несколько авторов, на которых стоит обратить внимание, если вы хотите провалиться в кроличью нору человеческого зрительного восприятия ...
Для этой узкой цели мы могли бы немного изменить вес коэффициентов, зная, что зеленый составляет большую часть яркости, а чистый синий и чистый красный всегда должны быть самыми темными из двух цветов. Что обычно происходит при использовании стандартных коэффициентов, так это то, что средние цвета с большим количеством синего или красного могут превращаться в черный при яркости ниже идеальной, а цвета с высоким зеленым компонентом могут делать противоположное.
Тем не менее, я считаю, что лучше всего решить эту проблему, увеличив размер и вес шрифта в средних цветах.
Собираем все вместе
Поэтому мы предполагаем, что вы отправите этой функции шестнадцатеричную строку, а она вернет строку стиля, которую можно отправить конкретному элементу HTML.
function setTextAttributes (hexColor = "#ffffff") {
let textSize = "16px";
let textWeight = "normal";
let rex = /#?(\w\w)(\w\w)(\w\w)/; // regex to parse the hex string
let colorChan = rex.exec(hexColor); // parses string to an array of RGB hex values
let Ys = Math.pow(parseInt(colorChan[1],16)/255.0,2.2) * 0.2126 +
Math.pow(parseInt(colorChan[2],16)/255.0,2.2) * 0.7152 +
Math.pow(parseInt(colorChan[3],16)/255.0,2.2) * 0.0722; // Andy's Easy Luminance Estimate for sRGB. For Rec709 HDTV change the 2.2 to 2.4, and use different coefficients for P3 etc!!
let Ls = Math.pow(Ys,0.75); // Ls is SAPC Screen lightness, similar to L* but for self illuminated monitors & contrast
let textColor = (Ls < 0.5) ? "#fff" : "#000"; // perceptually based text color flipper.
if (Ls > 0.35 && Ls < 0.65) {
textSize = "18px";
textWeight = "bold";
} // scale up fonts for the lower contrast mid luminances. Loosely based on APCA for WCAG 3 beta
return "style='color:" + textColor + "; font-size:" + textSize + "; font-weight:" + textWeight + ";'"
}
А если вы хотите поэкспериментировать с некоторыми из этих концепций, посетите сайт разработки SAPC по адресу https://www.myndex.com/SAPC/, щелкнув «режим исследования», чтобы получить интерактивные эксперименты для демонстрации этих концепций.
Условия просветления
Яркость: Y (относительная) или L (абсолютная кд / м 2) спектрально взвешенная, но в остальном линейная мера света. Не путать со светимостью.
Светимость: свет со временем, полезен в астрономии.
Легкость: легкость восприятия L* (Lstar) согласно определению CIE. Некоторым моделям присуща легкость J * .
Javascript [ES2015]
const hexToLuma = (colour) => {
const hex = colour.replace(/#/, '');
const r = parseInt(hex.substr(0, 2), 16);
const g = parseInt(hex.substr(2, 2), 16);
const b = parseInt(hex.substr(4, 2), 16);
return [
0.299 * r,
0.587 * g,
0.114 * b
].reduce((a, b) => a + b) / 255;
};
Гадкий Питон, если тебе не хочется его писать:)
'''
Input a string without hash sign of RGB hex digits to compute
complementary contrasting color such as for fonts
'''
def contrasting_text_color(hex_str):
(r, g, b) = (hex_str[:2], hex_str[2:4], hex_str[4:])
return '000' if 1 - (int(r, 16) * 0.299 + int(g, 16) * 0.587 + int(b, 16) * 0.114) / 255 < 0.5 else 'fff'
Спасибо за этот пост.
Для тех, кто может быть заинтересован, вот пример этой функции в Delphi:
function GetContrastColor(ABGColor: TColor): TColor;
var
ADouble: Double;
R, G, B: Byte;
begin
if ABGColor <= 0 then
begin
Result := clWhite;
Exit; // *** EXIT RIGHT HERE ***
end;
if ABGColor = clWhite then
begin
Result := clBlack;
Exit; // *** EXIT RIGHT HERE ***
end;
// Get RGB from Color
R := GetRValue(ABGColor);
G := GetGValue(ABGColor);
B := GetBValue(ABGColor);
// Counting the perceptive luminance - human eye favors green color...
ADouble := 1 - (0.299 * R + 0.587 * G + 0.114 * B) / 255;
if (ADouble < 0.5) then
Result := clBlack; // bright colors - black font
else
Result := clWhite; // dark colors - white font
end;
Это такой полезный ответ. Спасибо за это!
Я хотел бы поделиться версией SCSS:
@function is-color-light( $color ) {
// Get the components of the specified color
$red: red( $color );
$green: green( $color );
$blue: blue( $color );
// Compute the perceptive luminance, keeping
// in mind that the human eye favors green.
$l: 1 - ( 0.299 * $red + 0.587 * $green + 0.114 * $blue ) / 255;
@return ( $l < 0.5 );
}
Теперь выясним, как использовать алгоритм для автоматического создания парящих цветов для ссылок меню. Светлые заголовки становятся темнее при наведении, и наоборот.
Реализация флаттера
Color contrastColor(Color color) {
if (color == Colors.transparent || color.alpha < 50) {
return Colors.black;
}
double luminance = (0.299 * color.red + 0.587 * color.green + 0.114 * color.blue) / 255;
return luminance > 0.5 ? Colors.black : Colors.white;
}
У меня была такая же проблема, но я должен был разработать ее на PHP. Я использовал решение @Garek, и я также использовал этот ответ: конвертировать шестнадцатеричный цвет в значения RGB в PHP, чтобы преобразовать код цвета HEX в RGB.
Так что я делюсь этим.
Я хотел использовать эту функцию с заданным цветом фона HEX, но не всегда начиная с '#'.
//So it can be used like this way:
$color = calculateColor('#804040');
echo $color;
//or even this way:
$color = calculateColor('D79C44');
echo '<br/>'.$color;
function calculateColor($bgColor){
//ensure that the color code will not have # in the beginning
$bgColor = str_replace('#','',$bgColor);
//now just add it
$hex = '#'.$bgColor;
list($r, $g, $b) = sscanf($hex, "#%02x%02x%02x");
$color = 1 - ( 0.299 * $r + 0.587 * $g + 0.114 * $b)/255;
if ($color < 0.5)
$color = '#000000'; // bright colors - black font
else
$color = '#ffffff'; // dark colors - white font
return $color;
}
Основываясь на ответе Гачека и после анализа примера @WebSeed с расширением браузера WAVE, я придумал следующую версию, которая выбирает черный или белый текст на основе коэффициента контрастности (как определено в Руководстве по доступности веб-контента W3C (WCAG) 2.1), вместо яркости.
Это код (в javascript):
// As defined in WCAG 2.1
var relativeLuminance = function (R8bit, G8bit, B8bit) {
var RsRGB = R8bit / 255.0;
var GsRGB = G8bit / 255.0;
var BsRGB = B8bit / 255.0;
var R = (RsRGB <= 0.03928) ? RsRGB / 12.92 : Math.pow((RsRGB + 0.055) / 1.055, 2.4);
var G = (GsRGB <= 0.03928) ? GsRGB / 12.92 : Math.pow((GsRGB + 0.055) / 1.055, 2.4);
var B = (BsRGB <= 0.03928) ? BsRGB / 12.92 : Math.pow((BsRGB + 0.055) / 1.055, 2.4);
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
};
var blackContrast = function(r, g, b) {
var L = relativeLuminance(r, g, b);
return (L + 0.05) / 0.05;
};
var whiteContrast = function(r, g, b) {
var L = relativeLuminance(r, g, b);
return 1.05 / (L + 0.05);
};
// If both options satisfy AAA criterion (at least 7:1 contrast), use preference
// else, use higher contrast (white breaks tie)
var chooseFGcolor = function(r, g, b, prefer = 'white') {
var Cb = blackContrast(r, g, b);
var Cw = whiteContrast(r, g, b);
if(Cb >= 7.0 && Cw >= 7.0) return prefer;
else return (Cb > Cw) ? 'black' : 'white';
};
Рабочий пример можно найти в моем ответвлении кода @WebSeed, который дает нулевые ошибки низкой контрастности в WAVE.
Как расширение Kotlin / Android:
fun Int.getContrastColor(): Int {
// Counting the perceptive luminance - human eye favors green color...
val a = 1 - (0.299 * Color.red(this) + 0.587 * Color.green(this) + 0.114 * Color.blue(this)) / 255
return if (a < 0.5) Color.BLACK else Color.WHITE
}
iOS Swift 3.0 (расширение UIColor):
func isLight() -> Bool
{
if let components = self.cgColor.components, let firstComponentValue = components[0], let secondComponentValue = components[1], let thirdComponentValue = components[2] {
let firstComponent = (firstComponentValue * 299)
let secondComponent = (secondComponentValue * 587)
let thirdComponent = (thirdComponentValue * 114)
let brightness = (firstComponent + secondComponent + thirdComponent) / 1000
if brightness < 0.5
{
return false
}else{
return true
}
}
print("Unable to grab components and determine brightness")
return nil
}
Реализация для цели-с
+ (UIColor*) getContrastColor:(UIColor*) color {
CGFloat red, green, blue, alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
double a = ( 0.299 * red + 0.587 * green + 0.114 * blue);
return (a > 0.5) ? [[UIColor alloc]initWithRed:0 green:0 blue:0 alpha:1] : [[UIColor alloc]initWithRed:255 green:255 blue:255 alpha:1];
}
base
R-версия ответа @Gacek, чтобы получить luminance
(вы можете легко применить свой собственный порог)
# vectorized
luminance = function(col) c(c(.299, .587, .114) %*% col2rgb(col)/255)
Применение:
luminance(c('black', 'white', '#236FAB', 'darkred', '#01F11F'))
# [1] 0.0000000 1.0000000 0.3730039 0.1629843 0.5698039
Обратите внимание, что в библиотеке закрытия Google есть алгоритм, который ссылается на рекомендацию w3c: http://www.w3.org/TR/AERT. Однако в этом API вы предоставляете список предлагаемых цветов в качестве отправной точки.
/**
* Find the "best" (highest-contrast) of the suggested colors for the prime
* color. Uses W3C formula for judging readability and visual accessibility:
* http://www.w3.org/TR/AERT#color-contrast
* @param {goog.color.Rgb} prime Color represented as a rgb array.
* @param {Array<goog.color.Rgb>} suggestions Array of colors,
* each representing a rgb array.
* @return {!goog.color.Rgb} Highest-contrast color represented by an array.
*/
goog.color.highContrast = function(prime, suggestions) {
var suggestionsWithDiff = [];
for (var i = 0; i < suggestions.length; i++) {
suggestionsWithDiff.push({
color: suggestions[i],
diff: goog.color.yiqBrightnessDiff_(suggestions[i], prime) +
goog.color.colorDiff_(suggestions[i], prime)
});
}
suggestionsWithDiff.sort(function(a, b) { return b.diff - a.diff; });
return suggestionsWithDiff[0].color;
};
/**
* Calculate brightness of a color according to YIQ formula (brightness is Y).
* More info on YIQ here: http://en.wikipedia.org/wiki/YIQ. Helper method for
* goog.color.highContrast()
* @param {goog.color.Rgb} rgb Color represented by a rgb array.
* @return {number} brightness (Y).
* @private
*/
goog.color.yiqBrightness_ = function(rgb) {
return Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000);
};
/**
* Calculate difference in brightness of two colors. Helper method for
* goog.color.highContrast()
* @param {goog.color.Rgb} rgb1 Color represented by a rgb array.
* @param {goog.color.Rgb} rgb2 Color represented by a rgb array.
* @return {number} Brightness difference.
* @private
*/
goog.color.yiqBrightnessDiff_ = function(rgb1, rgb2) {
return Math.abs(
goog.color.yiqBrightness_(rgb1) - goog.color.yiqBrightness_(rgb2));
};
/**
* Calculate color difference between two colors. Helper method for
* goog.color.highContrast()
* @param {goog.color.Rgb} rgb1 Color represented by a rgb array.
* @param {goog.color.Rgb} rgb2 Color represented by a rgb array.
* @return {number} Color difference.
* @private
*/
goog.color.colorDiff_ = function(rgb1, rgb2) {
return Math.abs(rgb1[0] - rgb2[0]) + Math.abs(rgb1[1] - rgb2[1]) +
Math.abs(rgb1[2] - rgb2[2]);
};
Swift 4 Пример:
extension UIColor {
var isLight: Bool {
let components = cgColor.components
let firstComponent = ((components?[0]) ?? 0) * 299
let secondComponent = ((components?[1]) ?? 0) * 587
let thirdComponent = ((components?[2]) ?? 0) * 114
let brightness = (firstComponent + secondComponent + thirdComponent) / 1000
return !(brightness < 0.6)
}
}
ОБНОВЛЕНИЕ - Найдено, что 0.6
был лучший тестовый стенд для запроса
Вариант Android, который также фиксирует альфу.
(спасибо @ Томас-Вос)
/**
* Returns a colour best suited to contrast with the input colour.
*
* @param colour
* @return
*/
@ColorInt
public static int contrastingColour(@ColorInt int colour) {
// XXX https://stackru.com/questions/1855884/determine-font-color-based-on-background-color
// Counting the perceptive luminance - human eye favors green color...
double a = 1 - (0.299 * Color.red(colour) + 0.587 * Color.green(colour) + 0.114 * Color.blue(colour)) / 255;
int alpha = Color.alpha(colour);
int d = 0; // bright colours - black font;
if (a >= 0.5) {
d = 255; // dark colours - white font
}
return Color.argb(alpha, d, d, d);
}
Если вы манипулируете цветовыми пространствами для визуального эффекта, обычно легче работать в HSL (Hue, Saturation и Lightness), чем в RGB. Перемещение цветов в RGB для получения естественно приятных эффектов, как правило, является довольно концептуально сложным, в то время как преобразование в HSL, манипулирование там, а затем обратное преобразование является более интуитивным по своей концепции и неизменно дает лучшие результаты.
В Википедии есть хорошее введение в HSL и тесно связанный HSV. И есть бесплатный код в сети, чтобы сделать преобразование (например, здесь реализация javascript)
Какое точное преобразование вы используете - дело вкуса, но лично я бы подумал, что изменение компонентов Hue и Lightness наверняка приведет к хорошему высококонтрастному цвету в первом приближении, но вы можете легко перейти к более тонким эффектам.
Вы можете иметь любой текст оттенка на любом фоне оттенка и обеспечить его разборчивость. Я делаю это все время. Для этого в Javascript есть формула для удобочитаемого текста в цвете - STW*. Как сказано в этой ссылке, эта формула представляет собой вариацию в расчете регулировки обратной гаммы, хотя и немного более управляемая IMHO. Меню в правой части этой ссылки и связанных с ней страниц используют произвольно сгенерированные цвета для текста и фона, всегда читаемые. Так что да, ясно, что это можно сделать, нет проблем.
Я бы прокомментировал ответ @MichaelChirico, но у меня недостаточно репутации. Итак, вот пример в R с возвратом цветов:
get_text_colour <- function(
background_colour,
light_text_colour = 'white',
dark_text_colour = 'black',
threshold = 0.5
) {
background_luminance <- c(
c( .299, .587, .114 ) %*% col2rgb( background_colour ) / 255
)
return(
ifelse(
background_luminance < threshold,
light_text_colour,
dark_text_colour
)
)
}
> get_text_colour( background_colour = 'blue' )
[1] "white"
> get_text_colour( background_colour = c( 'blue', 'yellow', 'pink' ) )
[1] "white" "black" "black"
> get_text_colour( background_colour = c('black', 'white', '#236FAB', 'darkred', '#01F11F') )
[1] "white" "black" "white" "white" "black"
В случае, когда вы пытаетесь выбрать между известными цветами переднего плана (например, должен ли текст на этом фоне быть черным или белым?), это было бы идеально: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-contrast Надеюсь, скоро!