Getting the “Belle & Sebastian effect” with CSS filters

There are a lot of arti­cles out there regard­ing using SVG’s feColorMatrix with CSS fil­ters to get a “duo­tone” or “Insta­gram” effect on pho­tos, but frankly most of the exam­ples looked too weird to me, and the matrix mul­ti­pli­ca­tion that’s going on is pret­ty hard to wrap my brain around.

Usu­al­ly what I want is a sim­ple mono­chrome duo­tone effect; in oth­er words, the Belle & Sebas­t­ian effect:

Most of these are a “dark” duo­tone effect, where the blacks remain black and the whites become the desired col­or.

There’s also a “light” duo­tone effect, which does the reverse:

Here the whites remain white and the blacks turn into the desired col­or.

How do we do that with feColorMatrix? The best expla­na­tion that I’ve seen of how the fil­ter works is prob­a­bly from A List Apart, but I think it gets the grayscale stuff wrong. For instance, in all its grayscale exam­ples, it only main­tains the bright­ness of a sin­gle col­or chan­nel, rather than aver­ag­ing them out.

Instead, what we need to start with is a “true” grayscale, where all col­or chan­nels are mul­ti­plied by the bright­ness val­ue of all oth­er col­or chan­nels equal­ly, and in such a way that no chan­nel has a val­ue greater than 1. What this means is start­ing with some­thing like this:

<filter id="grayscale">
  <feColorMatrix
    type="matrix"
    values="0.33 0.33 0.33 0 0
            0.33 0.33 0.33 0 0
            0.33 0.33 0.33 0 0
            0    0    0    1 0 "/>
</filter>

Then, to “col­orize” the whites — for a “dark”/If You’re Feel­ing Sin­is­ter duo­tone effect — we need to sub­tract the col­or chan­nels we don’t want. So, for instance, if we want our whites to turn red, we remove the green and blue chan­nels by chang­ing their “mul­ti­pli­er” val­ue to -1:

<filter id="grayscale">
  <feColorMatrix
    type="matrix"
    values="0.33 0.33 0.33 0  0
            0.33 0.33 0.33 0 -1
            0.33 0.33 0.33 0 -1
            0    0    0    1  0 "/>
</filter>

If instead we want a “light” duo­tone, where whites remain whites and blacks change to our desired col­or, we increase the mul­ti­pli­er of the col­or we want, rather than decreas­ing the mul­ti­pli­er for the col­ors we don’t. So, for green:

<filter id="grayscale">
  <feColorMatrix
    type="matrix"
    values="0.33 0.33 0.33 0 0
            0.33 0.33 0.33 0 1
            0.33 0.33 0.33 0 0
            0    0    0    1 0 "/>
</filter>

If you need a col­or that isn’t pure red, green, or blue, use val­ues that are the ratio of your desired col­or’s R, G, and B val­ues to 255. So, for rebeccapurple, which is RGB(102, 51, 153), we would do:

<filter id="grayscale">
  <feColorMatrix
    type="matrix"
    values="0.33 0.33 0.33 0 0.4
            0.33 0.33 0.33 0 0.2
            0.33 0.33 0.33 0 0.6
            0    0    0    1 0 "/>
</filter>

Below is a Code­Pen you can play around with to see how I’m doing this. In order to affect con­trast, I find it’s best to play with the “main” alpha mul­ti­pli­er — that 1 in the bot­tom-right — and to increase or decrease the 0.33 val­ues (though they should all remain equal), but I admit that I’m most­ly flail­ing here.

There’s also a great tool to play with these val­ues live on a GitHub Page by @kazzkiq.

See the Pen Belle & Sebas­t­ian CSS feCol­or­Ma­trix fil­ters by Jay (@jsit) on Code­Pen.default