HTML & CSS
Article

A Dynamic Gradient Text Function in Sass

By Cathy Dutton

In this post a common text color function will be extended to work with gradient backgrounds. The effect is achieved by first creating a gradient background from a list of values. The function then appends corresponding color values to a new list to create a text gradient.

A little background…

The ability to change the color of text depending on its background is a common request, one way to do this is to test for the lightness of the background and then modify the text accordingly. A popular and well documented function exists to do just that…

@function set-notification-text-color($color) {
  @if (lightness($color) > 50) {
    @return #000000; // Lighter background, return dark color
  } 
  @else {
    @return #ffffff; // Darker background, return light color
  }
}

The above function is applied like this:

.notification-confirm {
  background: $notification-confirm;
  color: set-notification-text-color($notification-confirm);
}

Step 1 – The background gradient mixin

Before we look at the text gradient function we need to create a list to hold the values for our background gradient and create the mixin…

$list: $orange, $white, $orange, $white;

This list above and a direction are used as the arguments for the background mixin. Using a list has two main advantages, firstly it has an open ended number of arguments allowing for any combination of colors and/or percentages. Secondly, and importantly for this function we can iterate through the list to create the same number of new values for the text gradient. More information on mixin arguments and when to use them can be found in this post.

The gradient mixin looks like this:

@mixin gradient($direction, $list) {
  background: -webkit-linear-gradient($direction, $list);
}

and is applied like this:

.text {
  @include gradient(left, $list);
}

Step 2 – The text gradient function

In webkit/blink based browsers it is possible to display text gradients using the text clip property along with text-fill-color as shown below:

.text {
  background: -webkit-linear-gradient(left, #000, #fff); // We will need to generate gradient colors to complement the background.
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

Firstly we need to create a function with the same $list value as the argument. The function will create a new empty list to store our new values and then return them:

@function text-color($list){
  $text-list:();
  @return $text-list;
}

Then we run through each value in $list:

@function text-color($list){
  $text-list:();
  @each $color in $list {
    // Do something...
  }
  @return $text-list;
}

Inside our for each loop we can run the same check as the solid color function mentioned at the beginning of this post:

@function text-color($list){
  $text-list:();
  @each $color in $list {
    @if lightness($color) > 50% {
      // Create a dark text color
    } 
    @else {
      // Create a light text color
    }
  }
  @return $text-list;
}

To create the dark or light text color we need to add the value to $text-list. This is done using the append function:

$text-list:append($text-list, $black, comma);  // Adds $black to $text-list
$text-list:append($text-list, $white, comma); // Adds $white to $text-list

The final function would therefore be:

@function text-color($list){
  $text-list:();
  @each $color in $list {
    @if lightness($color) > 50% {
      $text-list:append($text-list, $black, comma);
    } 
    @else {
      $text-list:append($text-list, $white, comma);
    }
  }
  @return $text-list;
}

The function is applied to the $list gradient argument on the text element:

.text-block {
  @include gradient(left, $list);
  p {
    @include gradient(left, text-color($list));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}

Sass color functions:

This function is fine in most cases but is a little restrictive in that the text can only be black or white. By using some of the built in Sass color manipulations the function can generate a text color dynamically based on input, removing the need for the if statement. A few examples of this would be:

@function text-color($list){
  $text-list:();
  @each $color in $list {
    $text-list:append($text-list, invert($color), comma);
  }
  @return $text-list;
}

@function text-color($list){
  $text-list:();
  @each $color in $list {
    $text-list:append($text-list, complement($color), comma);
  }
  @return $text-list;
}

@function text-color($list){
  $text-list:();
  @each $color in $list {
    $text-list:append($text-list, adjust-hue($color, 40deg), comma);
  }
  @return $text-list;
}

Taking things a little further:

As I mentioned earlier a key reason for using a list as the gradient parameter is the ability to use it as a multidimensional list. The example below adds percentages to give a little more control over the gradient…

$list: ($orange 0%),
       ($orange 50%),
       ($white 50%),
       ($white 100%);

This percentage value also needs to be added to the function:

@function text-color($list){
  $text-list:();
  @each $color, $percentage in $list {
    $text-list:append($text-list, invert($color), $percentage, comma);
  }
  @return $text-list;
}

Using CSS Keyframes we can animate a gradient to create some interesting effects for progress bars or loading animations. Demonstrations of some of the effects discussed can be found in this CodePen.

Limitations and fallbacks

As I mentioned previously text gradients work in blink/webkit browsers only, we can however ensure they degrade gracefully in other browsers. To do this simply use the webkit prefix only for your gradient, fill-color and background clip properties for this technique. You could also add a fallback color and background to the mixin…

@mixin gradient($direction, $list) {
  background: $white; // Fallback solid background color for unsupported browsers
  background: -webkit-linear-gradient($direction, $list);
}

p {
  color: $orange; // Fallback solid text color for unsupported browsers
  @include gradient(left, text-color($list));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}
Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in Front-end, once a week, for free.