QR Code contains TinyURL of this article.How To: Maintain Foreground Contrast on Variable Background Colours with Sass

When I designed the Perpetual βeta’s home-page, I created “tiles” to promote the latest weblog posts. Starting with a base background-color of rgb(61, 104, 144), I use a Sass loop to lighten each tile’s background-color by 5%:

$tile-blue: rgb(61, 104, 144);
.cardinal.home {
  .weblog-article-index {
    .entry {
      @for $i from 1 through 6 {
        $percentage: $i * 5%;
        &:nth-child(#{$i}) {
          $background: lighten($tile-blue, $percentage);
          background-color: $background;
        }
      }
    }
  }
}

Which results in this:

The Perpetual βeta home-page tiles

What you might not immediately notice is that the last two tiles in the sequence have dark text on light(ish) backgrounds as opposed to the first four tiles, where the opposite is true. If I had continued to use light text on those last two tiles, there would be too little contrast between that foreground text and the tile background.

I wrote a Sass function that takes a background-color value and returns a foreground colour that should contrast reasonably well against it:1

@function get-foreground-color($background-color) {
  $threshold: 62;
  $adjust: 40%;
  @if (lightness($background-color) >= $threshold) {
    // Lighter background, return dark colour
    @return darken($background-color, $adjust);
  } @else {
    // Darker background, return light colour
    @return lighten($background-color, $adjust);
  }
}

I then modify the tile background-color loop to call this function, passing in the current background-color on each iteration, like so:

$tile-blue: rgb(61, 104, 144);
.cardinal.home {
  .weblog-article-index {
    .entry {
      @for $i from 1 through 6 {
        $percentage: $i * 5%;
        &:nth-child(#{$i}) {
          $background: lighten($tile-blue, $percentage);
          background-color: $background;
          color: get-foreground-color($background);
          a {
            color: get-foreground-color($background);
          }
        }
      }
    }
  }
}

Job done!

  1. The W3C has published guidelines pertaining to colour contrast. The code I have presented here does not (yet) comply with those guidelines. I might further tweak this in an attempt to make it compliant. I’ll update this post if I do. ↩︎