Tinting or lightening with CSS

The problem

Consider the requirement that, on hover, an element’s background becomes lighter. The background could be an image or a colour. The ideal solution should allow a .tint-lighter (or .tint-darker, .tint-red, etc) class to be applied to any element.

Possible solutions

There are a number of use-cases for tinting with CSS and a number of ways to achieve the effect (Like this one). Most of the techniques I have seen before fall into three categories:

  • Using opacity
  • By layering background images
  • With an overlay

Each of those solutions has a drawback.

If you are using opacity then you cannot have anything behind the element (as we wanted a lighter colour not a see-through element). Also, if you have content in the element that will become translucent too.

The layered background images works well: you overlay the desired background with a translucent white background (say a uniform gradient). The main issue with this is that you need to know the properties of the original background in your declaration. That is, if an element has two classes, .red and .tint-lighten, there needs to be a specific selector for that combination, as it will override the background set by just .red. Say there are 50 classes with different colours (for example, to represent countries) and you have three tint types, plain, lighten on hover and darken to show some functionality is disabled. In that case you need to define 150 css selectors and backgrounds for each combination. Probably not too difficult with a pre-processor but pretty bloaty.

Using an overlay can work but again it will affect the content of the element and if the element is animated or an interesting shape there can be some complexity.

Throwing my hat into the ring

I had to tackle this issue the other day. I tried all of the above techniques but wasn’t happy. The best solution was the layered background images but we were using 10 different tints and 12 different colours (for a data visualization) and 120 perturbations for such a simple case was unsatisfying.

I tried to think about other ways to layer colours and came to box-shadows. The solution is based upon applying a very large inset box shadow with a translucent colour, then, the background is overlaid but not the content and the original background is still in place. Here’s an example:

See the Pen Esfch by chrismichaelscott (@chrismichaelscott) on CodePen.

Leave a Reply

Your email address will not be published. Required fields are marked *