Solved With CSS! Colorizing SVG Backgrounds

CSS is getting increasingly powerful, and with features like CSS grid and custom properties (also known as CSS variables), we’re seeing some really creative solutions emerging. The possibilities are still being explored on what CSS can do to make writing UI’s simpler, and that’s exciting!

One of those is now one of my favorite CSS features: filters. Let’s look at how we can use filters to solve a problem you may have encountered when working with SVG as a background image on an element.

CSS Filters

First, let’s start by with an overview of filters. They include the following functions:

  • blur()
  • brightness()
  • contrast()
  • drop-shadow()
  • grayscale()
  • hue-rotate()
  • invert()
  • opacity()
  • saturate()
  • sepia()

These effects can also be achieved with SVG filters or WebGL shaders, but CSS filters are the easiest way to implement basic transformations in the most browser-efficient manner. Because they are shortcuts of SVG filter effects, you can also use filter: url() and specify a filter effect ID onto any element. If you want to play around with custom filters, I recommend checking out cssfilters.co.

The Problem: Editing SVG Backgrounds

I love using the SVG (scalable vector graphics) format for web design. SVG is a great image format for the web, and since it’s based on code, it allows for high-quality responsive and interactive content. When you inject SVG onto the page, you have access to each of its internal elements and their properties, allowing you to animate them, update values (such as color), and dynamically inject additional information. SVG is also a great icon format, especially instead of icon fonts, and in smaller UI elements due to its high quality (think: retina screens) and small image size (think: performance).

I find that often, when SVG is used for these smaller elements, or as a large area of illustration, it’s included as a background image for simplicity. The drawback to this is that the SVG is no longer under your control as a developer. You can’t adjust individual properties, like fill color, of an SVG background because it is treated just like any image. This color conundrum can be solved with CSS! Filters to the rescue!

Adjusting Brightness

The first time I discovered the SVG background challenge was when I was working on a website that had white SVG icons for social share icons that lived on a background determined to match that application. When these icons were moved onto a white background, they were no longer visible. Instead of creating a new icon, or changing the markup to inject inline SVG, you can use filter: brightness().

With the brightness filter, any value greater than 1 makes the element brighter, and any value less than 1 makes it darker. So, we can make those light SVG’s dark, and vice versa!

What I did above was create a dark class with filter: brightness(0.1). You can also do the opposite for darker icons. You can lighten icons by creating a light class with something like filter: brightness(100) or whatever is suitable to your needs.

Icons with a fill color of #000, or rgb(0,0,0) will not brighten. You need to have a value greater than 0 in any of the rgb channels. fill: rgb(1,1,1) works great with a high brightness value such as brightness(1000), but even brightness(1000) will not work on pure black. This is not an issue with light colors and white.

Adjusting Color

We’ve now seen how to adjust light and dark values with a brightness() filter, but that doesn’t always get us the desired effect. What if we want to inject some color into those icons? With CSS filters, we can do that. One little hack is to use the sepia filter along with hue-rotate, brightness, and saturation to create any color we want.

From white, you can use the following mixtures to get the navy, blue, and pink colors above:

.colorize-pink {
  filter: brightness(0.5) sepia(1) hue-rotate(-70deg) saturate(5);
}

.colorize-navy {
  filter: brightness(0.2) sepia(1) hue-rotate(180deg) saturate(5);
}

.colorize-blue {
  filter: brightness(0.5) sepia(1) hue-rotate(140deg) saturate(6);
}

The world is your oyster here. SVG is just one use case for multiple filters. You can apply this to any media type—images, gifs, video, iframes, etc., and support is pretty good, too:

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeOperaFirefoxIEEdgeSafari
18*15*35No186*

Mobile / Tablet

iOS SafariOpera MobileOpera MiniAndroidAndroid ChromeAndroid Firefox
6.0-6.1*37*No4.4*6457

One final note here is to remember your user! Filters will not work in Internet Explorer, so please send a visible image to all of your users (i.e. don’t use a white SVG with an applied filter on a white background, because your IE users will not see anything). Also, remember to use alternative text for icon accessibility, and you’ll be golden to use this technique in your own applications!