Search code examples
svgsvg-filters

SVG - How to drop an inset shadow on a path that has an rgba fill?


Assuming I have a circle shape (or any shape) in SVG with semi-transparent black fill (or any semi-transparent color):

<circle r="50" fill="rgba(0, 0, 0, 0.2)" />

How can I drop a configurable (color, blur, position) inset shadow whose transparency is independent of the shape fill?

Note: I do not know anything about the background beforehand, the SVG must be really transparent, not faked.

enter image description here


Solution

  • Easiest way to do this is to do an inset-shadow - first resetting the source graphic's color to black/fully opaque.

    <svg width="800px" height="600px" viewBox="0 0 400 300">
      <defs>
        <filter id="inset-shadow">
          <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0 
            0 0 0 0 0 
            0 0 0 0 0 
            0 0 0 100 0" result="opaque-source"/>
          <feGaussianBlur stdDeviation="5"/>
          <feOffset dy="10"/>
          <feComposite operator="xor" in2="opaque-source"/>
          <feComposite operator="in" in2="opaque-source"/>
          <feComposite operator="over" in2="SourceGraphic"/>
        </filter>
      </defs>
      
      <circle filter="url(#inset-shadow)" cx="100" cy="100" r="50" fill="rgba(0, 0, 0, 0.2)" />
      
      <svg>

    Or you can use a lighting effect to do this - more complicated, and performance can be pretty mixed.

    <svg width="800px" height="600px" viewBox="0 0 400 300">
      <defs>
        <filter id="top-light">
          <feColorMatrix type="matrix" values="1 0 0 0 0 
            0 1 0 0 0 
            0 0 1 0 0 
            0 0 0 100 0"/>
          <feGaussianBlur stdDeviation="2"/>
          <feComposite operator="in" in2="SourceGraphic"/>
          <feDiffuseLighting surfaceScale="200" diffuseConstant="1" kernelUnitLength="1" lighting-color="white" result="lightmap">
            <fePointLight x="100" y="0" z="10" />
          </feDiffuseLighting>
          <feGaussianBlur stdDeviation="2"/>
          
        <feColorMatrix type="luminanceToAlpha" />
        
        // Insert another color matrix in here to recolor the shadow
         <feComposite operator="in" in2="SourceGraphic"/>
          <feComposite operator="over" in2="SourceGraphic"/>
    
         
        </filter>
      </defs>
      
      <circle filter="url(#top-light)" cx="100" cy="100" r="50" fill="rgba(0, 0, 0, 0.2)" />
      
      <svg>