Масштабирование цвета на основе целевого коэффициента контрастности - PullRequest
0 голосов
/ 17 января 2019

Я пытаюсь создать функцию Sass, которая получает цвет переднего плана и цвет фона и вычисляет коэффициент контрастности. Отсюда (и часть, на которой я застрял) заключается в том, что он просто вернет цвет переднего плана, если он соответствует целевому коэффициенту контрастности, но если этого не произойдет, он осветлит или затемнит цвет переднего плана в соответствии с целевым коэффициентом контрастности.

Например, если заданный фон был #000, а передний - #444 (коэффициент контрастности 2,15), эта функция осветлит передний план до #757575 и вернет этот цвет .

У меня все работает, кроме той части, где мне нужно изменить контрастность. Моя первоначальная мысль состояла в том, чтобы подойти к нему с тем процентом, в котором он находился вдали от цели, и просто осветлить / затемнить (в зависимости от того, какой цвет был изначально темнее) на 100 минус процентная разница. Оглядываясь назад, этот подход был немного наивным, и я боюсь, что в нем будет участвовать более продвинутая математика.

Вот то, что я создал до сих пор (, а вот упрощенная скрипка ):

@function wcag-color($bg, $fg, $size: 16px, $level: "aa"){
    @if ( $level == "aa" ){
        $wcag_contrast_ratio: 4.5; //For text smaller than 18px
        @if ( $size >= 19  ){
            $wcag_contrast_ratio: 3; //For text larger than 19px
        }
    }

    @if ( $level == "aaa" ){
        $wcag_contrast_ratio: 7; //For text smaller than 18px
        @if ( $size >= 19  ){
            $wcag_contrast_ratio: 4.5; //For text larger than 19px
        }
    }

    $actual_contrast_ratio: contrast($bg, $fg); //This function returns the contrast between the two colors.

    @if ( $actual_contrast_ratio > $wcag_contrast_ratio ){
        @return $fg; //Foreground color is acceptable
    }

    //Scale the lightness of the foreground to meet requested WCAG contrast ratio
    $difference: 100 - $actual_contrast_ratio / $wcag_contrast_ratio * 100; //There is more to it than this...

    //Edit: here are a few new lines to ponder. This assumes BG is darker than FG (would need to add a condition to compare luminance of each).
    $acceptable_luminance: luminance($bg)*$wcag_contrast_ratio; //What the luminance of the FG must be to comply
    $difference: ($acceptable_luminance - luminance($fg)); //How far away the FG luminance actually is (not sure if this helps anything...)

    @return scale-color($fg, $lightness: $difference); //Unfortunately luminance is not the same as lightness.
}

Обратите внимание на закомментированную строку «В этом есть нечто большее, чем это ...» - вот где мне нужно обратить вспять мою формулу контрастности, но я бы хотел, чтобы была более простая формула для использования, поскольку я уже знаю, что такое целевой коэффициент контрастности составляет

Я думал об этом несколько дней, и я в тупике. Я бы предпочел избегать метода «угадай и проверь», обходя 1% светлых / затемненных цветов и проверяя каждый в отдельности на их контрастность - это будет работать, но я уверен, что есть более оптимальное решение.

Это был мой справочник по моим начальным функциям (контрастность и яркость), и он мне очень помог: https://medium.com/dev-channel/using-sass-to-automatically-pick-text-colors-4ba7645d2796

Примечание: я не использую Compass или любые другие библиотеки Sass.

Редактировать: вот упрощенная скрипка для справки: https://www.sassmeister.com/gist/445836123feb42885a0cf7f4709261ff

1 Ответ

0 голосов
/ 18 января 2019

Таким образом, учитывая # 000000 и # 444444, вы можете рассчитать коэффициент контрастности (в данном случае 2,15). Математика довольно проста, хотя и немного волосатая. (См. Определение « относительная яркость ».)

Теперь вы хотите вернуться назад? Если у вас # 000000 и вы хотите соотношение 4,5, начиная с # 444444, каким должен быть цвет? Это то, что

Мне нужно изменить формулу контрастности

означает

Это немного сложно, потому что вы решаете для 3 переменных, красного, зеленого и синего компонентов, плюс формула яркости не одинаково обрабатывает красный, зеленый и синий. Он использует 21,25% красного, 71,5% зеленого и 7,25% синего.

Кроме того, формула яркости не является простой линейной формулой, поэтому вы не можете просто взять процент, не соответствующий яркости, и увеличить значение цвета на тот же процент.

Например, в вашем случае соотношение было 2,15, но вам нужно, чтобы оно было 4,5. 2,15 составляет 108% от 4,5, желаемое значение.

Однако, если вы посмотрите на свои исходные значения RGB # 444444 и вычислили, что они должны быть равны # 757575 (для того, чтобы иметь отношение 4,5), то если вы рассматриваете эти значения RGB как простые числа (и преобразуете в десятичное число) тогда # 444444 (4473924) на 72% меньше, чем # 757575 (7697781).

Таким образом, у вас есть разрыв, что ваше соотношение короткое на 108%, а ваши значения RGB короткие на 72%. Таким образом, вы не можете сделать простое линейное уравнение.

( Числа не совсем точны, так как # 757575 дает вам соотношение 4,56, а не точное 4,5. Если вы используете # 747474, вы получите соотношение 4,49, что для WCAG слишком мало. соответствие, но ближе к 4,5, чем к 4,56. Однако # 444444 отстает на 71% от # 747474, так что это не то же самое, что 2,15 с 108% от 4,5, поэтому базовая концепция все еще применима. )

Ради интереса я посмотрел значения от 0x11111 до 0x666666, увеличив их на 0x111111, и рассчитал коэффициент контрастности. На графике было недостаточно точек, поэтому я добавил цвет на полпути между 0x111111 и 0x222222, затем на полпути между 0x222222 и 0x333333 и т. Д.

RGB     contrast  % from 4.5  % from 0x747474
111111    1.11      305.41%       582.35%
191919    1.19      278.15%       364.00%
222222    1.32      240.91%       241.18%
2a2a2a    1.46      208.22%       176.19%
333333    1.66      171.08%       127.45%
3b3b3b    1.87      140.64%        96.61%
444444    2.16      108.33%        70.59%
4c4c4c    2.45       83.67%        52.63%
555555    2.82       59.57%        36.47%
5d5d5d    3.19       41.07%        24.73%
666666    3.66       22.95%        13.73%
6e6e6e    4.12        9.22%         5.45%

graph of contrast ratios

Как видите, линии пересекаются в третьей точке данных, а затем сходятся друг к другу. Я уверен, что здесь есть формула, чтобы вы могли взять процент контрастности, выполнить некоторую (возможно, логарифмическую) функцию и получить процент, необходимый для изменения цвета.

Это была бы увлекательная математическая задача, с которой у меня сейчас нет времени играть.

Обновление 18 января 2019

Я заставил его работать в обратном направлении, но он не обрабатывает крайние случаи, например, когда темный цвет становится темнее, но вы уже достигли максимума (или более светлого цвета, но вы достигли максимума). Но, может быть, вы можете играть с ним.

Контрольный пример

  • #ee0add для светлого цвета (пурпурный)
  • #445566 для темного цвета (темно-серый)
  • коэффициент контрастности 2,09

При вычислении " относительной яркости " цвета он имеет условное выражение.

if X <= 0.03928 then 
  X = X/12.92 
else 
  X = ((X+0.055)/1.055) ^ 2.4

До того, как X будет использоваться в этом условии, он делится на 255, чтобы нормализовать значение между 0 и 1. Так что, если вы возьмете условное значение, 0,03928 и , умножьте на 255 , вы получите 10.0164. Так как значения RGB должны быть целыми числами, это означает, что компонент RGB 10 (0x0A) или меньше будет проходить через «if», а все 11 (0x0B) или больше будут проходить через «else». Поэтому в моих тестовых значениях я хотел, чтобы одна из цветовых частей была 10 (0x0A) (# EE 0A DD).

Относительная яркость для # ee0add составляет 0,23614683378171950172526363525113 (0,236)

Относительная яркость для # 445566 составляет 0,0868525191131797135799815832377 (0,0868)

Коэффициент контрастности (0,236 + 0,05) / (0,0868 + 0,05) = 2,09

(Вы можете проверить это соотношение на https://webaim.org/resources/contrastchecker/?fcolor=EE0ADD&bcolor=445566)

Если мы хотим, чтобы отношение равнялось 4,5, и мы хотим, чтобы # ee0add не менялось, мы должны отрегулировать # 445566. Это означает, что вам нужно решить для:

4.5 = (0.236 + .05) / (XX + .05)

Таким образом, второе значение яркости (XX) должно быть 0,01358818528482655593894747450025 (0,0136)

Исходное второе значение яркости было 0,0868525191131797135799815832377 (0,0868), поэтому для получения 0,01358818528482655593894747450025 (0,0136) нам нужно умножить исходное значение на 0,15645125119651910313960717062698 (0,0136 / 0,86%) = 0,60 * 0,60% = 0,60 * 0,60 = 0,66 * 0,668 = =

Если мы применим эти 15,6% к каждому из значений относительной яркости R, G и B, а затем проработаем условное выражение, приведенное выше, вы можете получить значения RGB.

Исходная яркость для # 445566

r = 0x44 = 68 
g = 0x55 = 85 
b = 0x66 = 102

r1 = 68  / 255 = 0.26666666666666666666666666666667
g1 = 85  / 255 = 0.33333333333333333333333333333333
b1 = 102 / 255 = 0.4

r2 = ((.267 + .055) / 1.055)^^2.4 = 0.05780543019106721120703816752337
g2 = ((.333 + .055) / 1.055)^^2.4 = 0.09084171118340767766490119106965
b2 = ((.400 + .055) / 1.055)^^2.4 = 0.13286832155381791428570549818868

l = 0.2126 * r2 + 0.7152 * g2 + 0.0722 * b2
  = 0.0868525191131797135799815832377

Работая в обратном направлении, взять 15,6% от значений r2, g2 и b2

r2 = 0.05780543019106721120703816752337 * 15.6% = 0.00904373187934550551617004082875
g2 = 0.09084171118340767766490119106965 * 15.6% = 0.01421229937547695322310904970549
b2 = 0.13286832155381791428570549818868 * 15.6% = 0.02078741515147623990363062978804

Теперь отмените этот беспорядок с ^^2.4 и другими вещами

  • чтобы отменить X^^2.4 вы должны сделать обратное, X^^(1/2.4) или X^^(0.4167)
  • затем умножить на 1,055
  • затем вычесть 0,055
  • затем умножить на 255
pow( 0.00904373187934550551617004082875, 1/2.4) = 0.14075965680504652191078668676178
pow( 0.01421229937547695322310904970549, 1/2.4) = 0.16993264267137740728089791717873
pow( 0.02078741515147623990363062978804, 1/2.4) = 0.19910562853770829265100914759565

умножить на 1,055

0.14075965680504652191078668676178 * 1.055 = 0.14850143792932408061587995453368
0.16993264267137740728089791717873 * 1.055 = 0.17927893801830316468134730262356
0.19910562853770829265100914759565 * 1.055 = 0.21005643810728224874681465071341

вычесть 0,055

0.14850143792932408061587995453368 - 0.055 = 0.09350143792932408061587995453368
0.17927893801830316468134730262356 - 0.055 = 0.12427893801830316468134730262356
0.21005643810728224874681465071341 - 0.055 = 0.15505643810728224874681465071341

умножить на 255

0.09350143792932408061587995453368 * 255 = 23.842866671977640557049388406088 = 24 = 0x18
0.12427893801830316468134730262356 * 255 = 31.691129194667306993743562169008 = 32 = 0x20
0.15505643810728224874681465071341 * 255 = 39.53939171735697343043773593192  = 40 = 0x28

Итак, темный цвет - # 182028. Возможно, есть некоторые ошибки округления, но если вы проверите исходный цвет переднего плана, # ee0add с новым цветом, # 182028, вы получите коэффициент контрастности 4,48. Просто стесняюсь 4,5, но, как я уже сказал, возможно, некоторые ошибки округления.

https://webaim.org/resources/contrastchecker/?fcolor=EE0ADD&bcolor=182028

Я пытался сделать то же самое с # ee0add, сохранив то же самое # 445566, но при переходе назад и переходе к последнему шагу, где вы умножаете на 255, я получил числа больше 255, которые не являются действительными компонентами RGB (они может идти только до 0xFF). Если я остановил число на 255, затем взял разницу и добавил ее к наименьшему значению цвета, я получил приличный цвет, но соотношение было 5,04, превышение 4,5. Я тоже могу опубликовать эту математику.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...