Dynamically Changing Font Color Based on Background, Using CSS

The day I discovered the ability to change font color based on the lightness or darkness of the background was the day I realized how magical CSS can be. Up until then, I thought that could only be handled using JS. Boy was I wrong, and boy was my heart happy!

In my previous post, we discussed how to write an @each loop that combed through a list of colors and applied different background colors to every flash message variant.

Today we’re going to spice things up a little and learn how you can dynamically change your font color based on the background of each flash message.

We’ll start with using all of the same code from my previous post.

I’m not going to go into detail about that code here, but basically this loop is going through each type of flash message and assigning a background based on the instance. The next thing we want to do is change the text color based on the background color for each flash message.

Show me the lightness!

Step 1

First, we need to write a function that will calculate a color’s lightness. lightness( ) does just that! This is a built-in SASS function that calculates the lightness of a color’s RGB value. The value returned by the function is between 0 and 100; 0 being the darkest and 100 being the lightest. Therefore, if the value of the background color returns on the lower end of the spectrum, meaning the background is dark, we would want to set a lighter text color.

@function set-flash-text-color($color: nth($status, 1)) {
  @if (lightness($color) > 60) {
    @return $body-font-color; // Lighter background, return dark color
  } @else {
    @return $white; // Darker background, return light color
  }
}

For this example, I used 60% as the threshold for setting my greater than/less than values. (Note: Most people will start at 50% since it’s halfway between 0 and 100. I used 60 to get my desired color combinations). This was because I wanted the text in Flash--info to be dark, but still wanted the text in Flash--success and Flash--alert to be white (changing the percentage to 50% would affect the success and alert messages).

Step 2

In the @each function we created in my last post, you can now declare the font color by adding color: set-flash-text-color(nth($status, 2)); after where the background color is set.

@each $status in $flashes {
  .Flash--#{nth($status, 1)} {
    background: nth($status, 2);
    color: set-flash-text-color(nth($status, 2));
  }
}

Step 3

Marvel in the magic! That’s just it. Your text colors will now change depending on the color of the background!

Step 4

The last thing we need to style is the close button. We want to set the close button to dynamically change both when it is static and when it is hovered. To do this, duplicate the function above twice.

But, we’ll want to make a few changes to the duplicated code:

@function set-flash-close-button($color: nth($status, 1)) {
  @if (lightness($color) > 50) {
    @return $black-30; // Lighter background, return dark color
  } @else {
    @return $white-65; // Darker background, return light color
  }
}

@function set-flash-close-button-hover($color: nth($status, 1)) {
  @if (lightness($color) > 50) {
    @return $black-45; // Lighter background, return dark color
  } @else {
    @return $white-45; // Darker background, return light color
  }
}

First, rename both of the new functions. We’ll call them set-flash-close-button and set-flash-close-button-hover.

Next, I changed the lightness percentage to 50% for both of the close button functions. Again, this is totally subjective to get the desired color combinations.

Lastly, I adjusted the return values for both close button functions. You can use whichever 2 colors you wish, as long as one is on the darker spectrum and the other is on the lighter spectrum.

Step 5

Now that we have the two functions created for close buttons, we can add 2 variables inside of the @each loop.

@each $status in $flashes {
  $flash-close-btn: set-flash-close-button(nth($status, 2));
  $flash-close-btn-hover: set-flash-close-button-hover(nth($status, 2));

Step 6

The last step we have to take is to declare the font colors for the close button: both for the default state as well as on hover. To do this, we will use the vars we declared in Step 5 and add the styles inside of the @each loop.

@each $status in $flashes {
  $flash-close-btn: set-flash-close-button(nth($status, 2));
  $flash-close-btn-hover: set-flash-close-button-hover(nth($status, 2));

  .Flash--#{nth($status, 1)} {
    background: nth($status, 2);
    color: set-flash-text-color(nth($status, 2));
    .Close {
      @include global-transition;
      color: $flash-close-btn;
      &:hover,
      &:active,
      &:focus {
        color: $flash-close-btn-hover;
      }
    }
  }
}

The whole shebang:

Hopefully this little unicorn-sprinkle of CSS magic opens your mind into how great the world of SCSS functions can be! Again, keep that code DRY, ya’ll!

At Revelry, our team is focused on shipping great software every day.

Read more notes from Blaze!
We’re transparent about how we work. For a look at how we build digital products, check out
Lean Agile Processes and Tools.

Keep in touch by subscribing to CODING CREATIVITY and follow us on LinkedIn!