Making CSS Gradients smooth

By Matt,

August 2017

Web Dev
Ever used CSS gradients and thought “Urghh!”. We have. Here's a quick post about making them smooth as peanut butter.

We've had a couple of sites lately that use CSS gradients behind some text. This let us have a background image of any (or a mix of) colours, and still keep the text nicely readable.

The issue is, in the default state, CSS gradients can look a bit... gross. I'm sure some of you have written gradients like this:

.my-thing {
  background: linear-gradient(to-bottom, black, transparent);
}

Which works and you get a gradient that goes from solid black to transparent. Unfortunately you probably also get a nasty looking hard edge line going across the element. Check out this example screen shot:

Example gradient as above with visible line across the page
Ewwww!

In looking for a fix for this, I stumbled across this post on CSS Tricks by the clever and talented Andreas Larsen, which explains how to make them much nicer using physics, maths and diagrams of motorway intersections. Don't let that description put you off though, is an interesting read. The trick is to create a curve to ease your gradients on and then add the appropriate stops in your CSS. More like this:

.my-thing {
  background: linear-gradient(to bottom, black 0%, rgba(0, 0, 0, 0.738) 19%, rgba(0, 0, 0, 0.541) 34%, rgba(0, 0, 0, 0.382) 47%, rgba(0, 0, 0, 0.278) 56.5%, rgba(0, 0, 0, 0.194) 65%, rgba(0, 0, 0, 0.126) 73%, rgba(0, 0, 0, 0.075) 80.2%, rgba(0, 0, 0, 0.042) 86.1%, rgba(0, 0, 0, 0.021) 91%, rgba(0, 0, 0, 0.008) 95.2%, rgba(0, 0, 0, 0.002) 98.2%, transparent 100%);
}

This creates a gradient more like this:

A revised gradient which is much smoother
Mmmm. Velvety.

It's called a Scrim. I know what your thinking, that looks complicated. How do I use that? Well Andreas created a Post CSS plugin to smooth all your gradient troubles. Pretty sweet. Inspired by this I created a SCSS mixin to achieve the same thing.

/*
A simple little SCSS mixin for creating scrim gradients
Inspired by Andreas Larson - https://github.com/larsenwork
https://css-tricks.com/easing-linear-gradients/
*/

@mixin scrimGradient($startColor: $color-black, $direction: 'to bottom') {

  $scrimCoordinates: (
    0: 1,
    19: 0.738,
    34: 0.541,
    47: 0.382,
    56.5: 0.278,
    65: 0.194,
    73: 0.126,
    80.2: 0.075,
    86.1: 0.042,
    91: 0.021,
    95.2: 0.008,
    98.2: 0.002,
    100: 0
  );

  $hue: hue($startColor);
  $saturation: saturation($startColor);
  $lightness: lightness($startColor);
  $stops: ();

  @each $colorStop, $alphaValue in $scrimCoordinates {
    $stop: hsla($hue, $saturation, $lightness, $alphaValue) percentage($colorStop/100);
    $stops: append($stops, $stop, comma);
  }

  background: linear-gradient(unquote($direction), $stops);

}

I hear you like syntax highlighting? I've got your back over here in this Gist.

Here's a comparison of the two techniques, which shows makes the difference more obvious:

A comparison shot of both techniques, with the scrim technique visibly better

Best enjoyed with some smooth jazz. Nice.