automated-a11y-sass icon indicating copy to clipboard operation
automated-a11y-sass copied to clipboard

Grey foreground skews to color of background.

Open Merovex opened this issue 4 years ago • 3 comments

Context: I was looking for an alternative to adjusting the foreground color to ensure it was accessible when I happened upon your article and this repo. When I substituted the old routine for yours, I noticed that the foreground color was shifted

a11y-color(#333333, #161315, 'AAA') yields #CE9292. That is, the foreground's color was shifted to conform to the background color.

Forgive me, but I'm not familiar enough with Sassmeister to give the example. But, I did a debug dump of the gray range. My "normal" approach would be to use something in the middle grey, then let the contrast routine force it in the correct direction. I do this because I have both a light & dark mode and prefer to set the background and have the text adjust accordingly.

The hex on the left is the FG going in. The hex on the right is the output. I stopped after #999 since #AAAAAA is an AAA compliant foreground to #161315

DEBUG: #111111 #d28f8f
DEBUG: #222222 #d09090
DEBUG: #333333 #ce9292
DEBUG: #444444 #cb9393
DEBUG: #555555 #c69494
DEBUG: #666666 #c19696
DEBUG: #777777 #bb9898
DEBUG: #888888 #b39b9b
DEBUG: #999999 #a79e9e

I focused down on the part of your code that steps through the luminance. scale-color() is the culprit, with the first step being #333333 to #383737 finally to #ce9292. However, when I use a different color, it seems to not make the same mistake, #338833 steps to #348d34 finally to #3db93d. So, color me curious why grey can skew pink when saturation rises, but not other colors.

$fg: scale-color($fg, $lightness: $step, $saturation: $step/2);

It appears you're tweaking HSL, so I decided to set $saturation:0 instead; or rather remove it. That fixed it.

The saturation value ($step/2) was %1 for 38 iterations, changing the saturation +38%;

I think I fixed this ultimately by limiting the saturation step if the saturation was already in the gray area:

      $sat-step: 0;
      @if saturation($fg) > 10 {
        $sat-step: $step/2
      }
      $fg: scale-color($fg, $lightness: $step, $saturation:$sat-step);

Merovex avatar Sep 07 '20 15:09 Merovex

Wow, thanks for this! Very good insights, I'll see what I can do to make the corrections.

jhogue avatar Sep 08 '20 14:09 jhogue

No worries. I'm disappointed the Sass team won't build something like this in. It looks like the last attempt was 2014 and the said "no" because it used HSL. :shrug:

However, I just ran into another random problem. Using the color #456ca1 put me into a continuous loop. True of my version of that step-through or yours. I "fixed" it by putting a counter that stopped if exceeds 288, which is the number of lines in your lookup. While loops should always have an escape valve.

Digging a bit more, #63573e is the base color, which is something I'm auto-calculating internally off of #456ca1. Either way, it appears there are some cases where colors will create a continuous loop absent a stop. It appears to be when the color contrast can never get to the correct ratio (7 in this case, the ratio of #456ca1 to #FFFFFF is 5.36, and to #000000 is 3.9. Good to know the color is not acceptable in my use case (WebAIM to the rescue). I went a little darker.

Merovex avatar Sep 08 '20 21:09 Merovex

Sending more than one comment since I'm digging into your code. You are using the lookup because SASS has no pow() function. The "other" accessibility tool I had been using used one. The following code shows how they detected luminance:


@function pow($base, $exponents) {
  $raised: 1;
  @for $i from 1 through $exponents {
    $raised: $raised * $base;
  }
  @return $raised;
}

@function luma($color){
  // Thanks voxpelli for a very concise implementation of luminance measure in sass
  // Adapted from: https://gist.github.com/voxpelli/6304812
  $rgba: red($color), green($color), blue($color);
  $rgba2: ();
  @for $i from 1 through 3 {
    $rgb: nth($rgba, $i);
    $rgb: $rgb / 255;
    $rgb: if($rgb < .03928, $rgb / 12.92, pow(($rgb + .055) / 1.055, 2));
    $rgba2: append($rgba2, $rgb);
  }
  @return (.2126 * nth($rgba2, 1) + .7152 * nth($rgba2, 2) + 0.0722 * nth($rgba2, 3))*100;
}

Ultimately, I'm going back to the solution I found earlier. I did bring into it the innovation of stepping through @while instead of its prior @for iteration through iterations of 7 multiples.

https://gist.github.com/Merovex/ffdab61ea070e8aa45816c8e6138408f

Merovex avatar Sep 08 '20 22:09 Merovex