Nick Budden
Nick Budden

Reputation: 641

SVG: Multiple Effects in One Filter

I'm trying to implement multiple drop shadows into a single SVG filter, but I believe my question is more generic than that: how can I add multiple effects into a single SVG filter? In my case, here's specifically what I'm trying to do.

I've got an SVG document that currently contains a single path element, and I've applied a single drop shadow effect to this path element.

My SVG Document

 <svg xmlns:xlink="http://www.w3.org/1999/xlink" width="1440" height="1750">
      <defs>
        <filter id="dropshadow">
          <feGaussianBlur in="SourceAlpha" stdDeviation="2.2"></feGaussianBlur>
          <feOffset dx="12" dy="12" result="offsetblur"></feOffset>
          <feFlood flood-color="rgba(0,0,0,0.5)"></feFlood>
          <feComposite in2="offsetblur" operator="in"></feComposite>
          <feMerge>
            <feMergeNode></feMergeNode>
            <feMergeNode in="SourceGraphic"></feMergeNode>
          </feMerge>
        </filter>
      </defs>

      <path xmlns:xlink="http://www.w3.org/1999/xlink" d="M 100 100 L 300 100 L 200 300 z z" fill="#2DA9D6" filter="url(#dropshadow)"></path>
    </svg>

Which gives me an SVG that looks like this:

enter image description here

Now, I want to add a second (completely different) drop shadow to this same path element. For example, let's say a drop shadow that goes up and to the left of the element. In CSS my whole dropshadow might look like:

box-shadow: 5px 5px 5px rgba(0,0,0,0.5), -5px -5px 5px rgba(0,0,0,0.5);

How can I do these multiple shadows with SVG filters? I've had a look at this question which suggests putting multiple effects into one filter, but I'm not sure how to merge multiple effects into one filter.

Thanks for any help!

Upvotes: 8

Views: 5537

Answers (3)

bluenote10
bluenote10

Reputation: 26570

Note that according to this answer it seems possible to combine filters simply by chaining them with the syntax filter="url(#dropshadow1) url(#dropshadow2)".

```
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="1440" height="1750">
  <defs>
<filter id="dropshadow1" color-interpolation-filters="sRGB">
  <feGaussianBlur in="SourceAlpha" stdDeviation="2.2"></feGaussianBlur>
  <feOffset dx="12" dy="12" result="offsetblur"></feOffset>
  <feFlood flood-color="rgba(0,0,0,0.5)"></feFlood>
  <feComposite in2="offsetblur" operator="in"></feComposite>
  <feMerge>
    <feMergeNode></feMergeNode>
    <feMergeNode in="SourceGraphic"></feMergeNode>
  </feMerge>
</filter>
<filter id="dropshadow2" color-interpolation-filters="sRGB">
  <feGaussianBlur in="SourceAlpha" stdDeviation="2.2"></feGaussianBlur>
  <feOffset dx="-12" dy="-12" result="offsetblur"></feOffset>
  <feFlood flood-color="rgba(0,0,0,0.5)"></feFlood>
  <feComposite in2="offsetblur" operator="in"></feComposite>
  <feMerge>
    <feMergeNode></feMergeNode>
    <feMergeNode in="SourceGraphic"></feMergeNode>
  </feMerge>
</filter>
  </defs>

  <path
xmlns:xlink="http://www.w3.org/1999/xlink"
d="M 100 100 L 300 100 L 200 300 z z"
fill="#2DA9D6"
filter="url(#dropshadow1) url(#dropshadow2)">
  </path>
</svg>
```

enter image description here

It seems crucial though to use color-interpolation-filters="sRGB" in this case, and even then there seems to be a slight order dependence, i.e., filter="url(#dropshadow1) url(#dropshadow2)" seems to look slightly different than filter="url(#dropshadow2) url(#dropshadow1)". I'm not sure if this is an artifact in the renderers I tried, or an expected effect though...

Upvotes: 0

karly
karly

Reputation: 404

You can do multiple filters using just CSS! Use a function for each filter separated by a space:

.multiple-different-filters {
  filter: blur(20px) grayscale(20%);
}


.double-dropshadow {
  filter: drop-shadow(5px 5px 5px rgba(0,0,0,0.5)) drop-shadow(-5px -5px 5px rgba(0,0,0,0.5));

}

You need to call the drop-shadow() function for each shadow separately.

From: https://css-tricks.com/almanac/properties/f/filter/

Upvotes: 2

Erik Dahlstr&#246;m
Erik Dahlstr&#246;m

Reputation: 60976

You can use the result attributes to give a name to a filter primitive element's output, think of it as a sort of filter-local id attribute. You can then use that name as filter input with the in or in2 attributes.

<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="1440" height="1750">
  <defs>
    <filter id="dropshadow">
     <feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur"/> 
      <feOffset dx="12" dy="12" result="offsetblur"/>
      <feOffset dx="-20" dy="-12" result="offsetblur2" in="blur"/>
      <feComponentTransfer result="shadow1" in="offsetblur">
        <feFuncA type="linear" slope="0.5"/>
      </feComponentTransfer>
      <feComponentTransfer result="shadow2" in="offsetblur2">
        <feFuncA type="linear" slope="0.2"/>
      </feComponentTransfer>
      <feMerge> 
        <feMergeNode in="shadow1"/>
        <feMergeNode in="shadow2"/>
        <feMergeNode in="SourceGraphic"/> 
      </feMerge>
    </filter>
  </defs>

  <path xmlns:xlink="http://www.w3.org/1999/xlink" d="M 100 100 L 300 100 L 200 300 z z" fill="#2DA9D6" filter="url(#dropshadow)"></path>
</svg>

See fiddle.

Upvotes: 14

Related Questions