How to use blend mode in svg for vector shapes?

bukowski picture bukowski · Jul 12, 2012 · Viewed 9.7k times · Source

Here is my simple svg:

<!DOCTYPE html>
<html>
<head>
</head>
<body>

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <defs>
    <filter id="f1" x="0" y="0">
      <feBlend mode="multiply" in="SourceGraphic" in2="SourceGraphic" />
    </filter>
    </defs>
    <path d='M100 100 L200 100 L200 200 L100 200 Z' fill='#00FFFF'/>
    <path d='M150 150 L250 150 L250 250 L150 250 Z' fill='#CC3300'/>
    <path d='M175 175 L275 175 L275 275 L175 275 Z' fill='#FFFF00'/>
</svg>

</body>
</html>

Its just simple 3 rectangle shapes. Is it possible to apply blend mode MULTIPLY to all three rectangles?

Answer

Erik Dahlstr&#246;m picture Erik Dahlström · Jul 20, 2012

Yes, it's possible, but it's not as nice as it should be. Here are two options, the first using feImage and the second using BackgroundImage filter input. As you can see they both have drawbacks. Support is not universal for feImage that references svg content nor the BackgroundImage filter input, but you can try in e.g Opera or Chrome to see some results.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
    <defs>
        <filter id="f1" x="0" y="0" width="1" height="1">
          <feImage xlink:href="#p1" result="p1"/>
          <feImage xlink:href="#p2" result="p2"/>
          <feImage xlink:href="#p3" result="p3"/>
          <feBlend mode="multiply" in="p1" in2="p2" />
          <feBlend mode="multiply" in2="p3" />
        </filter>

        <filter id="f2" x="0" y="0" width="1" height="1">
          <feBlend mode="multiply" in="BackgroundImage" in2="SourceGraphic" />
        </filter>

        <path id="p1" d='M100 100 L200 100 L200 200 L100 200 Z' fill='#00FFFF'/>
        <path id="p2" d='M150 150 L250 150 L250 250 L150 250 Z' fill='#CC3300'/>
        <path id="p3" d='M175 175 L275 175 L275 275 L175 275 Z' fill='#FFFF00'/>
    </defs>
    <rect width="100%" height="100%" filter="url(#f1)"/>

    <g transform="translate(300 0)">
        <g enable-background="new">
            <g enable-background="new">
                <path d='M100 100 L200 100 L200 200 L100 200 Z' fill='#00FFFF'/>
                <path d='M150 150 L250 150 L250 250 L150 250 Z' fill='#CC3300' filter="url(#f2)"/>
            </g>
            <path d='M175 175 L275 175 L275 275 L175 275 Z' fill='#FFFF00' filter="url(#f2)"/>
        </g>
    </g>
</svg>

Hopefully we'll soon have support for CSS Compositing and Blending in all browsers. If that is supported you can write something like this instead:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <style>
       path { mix-blend-mode: multiply; }
    </style>
    <path d='M100 100 L200 100 L200 200 L100 200 Z' fill='#00FFFF'/>
    <path d='M150 150 L250 150 L250 250 L150 250 Z' fill='#CC3300'/>
    <path d='M175 175 L275 175 L275 275 L175 275 Z' fill='#FFFF00'/>
</svg>

Here's a live example.