Rose Tinted Classes: An SVG Filter Function CSS Trick


In this post, we'll use CSS and SVG filter functions to tint an element's content Rose Quartz, Pantone's 2016 Color of the Year.

The exact hex triplet for Rose Quartz is probably a trade secret, so I'll be using and praying I don't get sued by Big Color.

Here's the content we're trying to rose tint:

Homesteading in Pie Town

Faro and Doris Caudill, homesteaders, Pie Town, New Mexico. Faro and Doris got divorced a couple years after this picture was taken; she ended up homesteading in Alaska. Kodachrome by Russell Lee, 1940.

The Old Solution

Alas, there's no CSS filter function that colorizes content. For many years, the recommended hack was to apply the sepia() filter, then hue-rotate() your way to the target tint color. The sepia() filter did double duty in this approach. It desaturated the content to grayscale, then applied a common tint color to everything.

If traveling back to the 1800s to introduce color seems bonkers, you're not alone. That part was strange, but the hard part was figuring out how to rotate sepia to your target hue, then adjusting brightness and saturation to match the target. People even wrote calculators for this.

Unfortunately, the whole sepia rotation approach is doomed. You can't precisely reach all target colors this way. For some target colors, things will always look a little bit off.

There must be a better way!

The New Solution

Enter <feColorMatrix>. This SVG filter element lets you define an (R,G,B,A) -> (R',G',B',A') color transform in matrix multiplication terms. Armed with this, you can finally do precise colorization. After desaturating the content with a grayscale() filter, the new solution uses <feColorMatrix> to tint it with the target color:

<svg id="tint" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <filter id="colorize" color-interpolation-filters="sRGB">
      <feColorMatrix type="matrix" values="0.969 0 0 0 0
                                           0 0.792 0 0 0
                                           0 0 0.788 0 0
                                           0 0 0 1 0" />
    </filter>
  </defs>
</svg>

Note how our Rose Quartz tint color – #F7CAC9 = (0.969,0.792,0.788) – appears along the diagonal. Change that to whatever tint color you're targeting.

Using these SVG filters from CSS is easy. Just chain them:

.rose {
  filter: grayscale(1) url(#colorize);
}
svg#tint {
  display: none;
}

And here's the result:

Homesteading in Pie Town

Faro and Doris Caudill, homesteaders, Pie Town, New Mexico. Faro and Doris got divorced a couple years after this picture was taken; she ended up homesteading in Alaska. Kodachrome by Russell Lee, 1940.

Notice how only the content is tinted, and the background behind the photograph is unchanged. This approach will work even for image content with transparent and translucent pixels. The final row of the feColorMatrix passes the alpha channel through unchanged.

What doesn't quite work: the resulting brightness falls off more steeply than it should. This is because we're effectively squaring a [0,1] brightness value when grayscale pixels are multiplied by the original color. Ideally, like translucency, luminance would also be conserved. If you have a suggestion here, please drop me a line!


Posted by Alan on Tuesday, August 12, 2025.