Search code examples
svgfilterglow

Apply glow to SVG element with a gradient


I have an SVG element that's based on a circle and a mask to create a ring.

The code is as follows:

<svg width="100%" height="100%" viewBox="0 0 300 300" version="1.1">
  <defs>
    <linearGradient x1="97.3756325%" y1="100%" x2="0%" y2="100%" id="gradient">
      <stop stop-color="#FF00AC" offset="0%"></stop>
      <stop stop-color="#5D00C4" offset="100%"></stop>
    </linearGradient>
    
    <mask id="circle-mask">
      <circle cx="150" cy="150" r="145" fill="white"/>
      <circle cx="150" cy="150" r="140" fill="black"/>
    </mask>
  </defs>
  
  <circle cx="150" cy="150" r="145" mask="url(#circle-mask)" fill="url(#gradient)"/>
</svg>

The ring got a gradient as fill color. Now I want to apply a glow effect on the ring that uses the colors of the gradient. Any ideas on how to do that?


Solution

  • What is a "glow"? I don't think there is a canonical definition, so I'm going with one that I have seen used before: a backdrop shadow that is colored and whose opacity values are exagerated. To define those effects, refer to the SVG <filter> spec, its support is pretty good across browsers.

    I understand you need the mask for more complex situations than this one. The important thing here is the order in which different effects are applied: clip paths and masks are processed after filter effects:

    First the element is styled under absence of filter effects, masking, clipping and opacity. Then the element and its descendants are drawn on a temporary canvas. In a last step the following effects are applied to the element in order: filter effects, clipping, masking and opacity.

    Therefore you need to wrap the masked element in a <g> and apply the glow filter there.

    Vary stdDeviation to stretch or shrink the shadow, and vary slope to change its opacity. If you set the slope to a value > 2, you will no longer get a clear border between the ring and its shadow.

    <svg width="100%" height="100%" viewBox="0 0 300 300" version="1.1">
      <defs>
        <linearGradient x1="97.3756325%" y1="100%" x2="0%" y2="100%" id="gradient">
          <stop stop-color="#FF00AC" offset="0%"></stop>
          <stop stop-color="#5D00C4" offset="100%"></stop>
        </linearGradient>
        <mask id="circle-mask">
          <circle cx="150" cy="150" r="145" fill="white"/>
          <circle cx="150" cy="150" r="140" fill="black"/>
        </mask>
        <filter id="glow">
          <feGaussianBlur stdDeviation="5"/>
          <feComponentTransfer>
            <feFuncA type="linear" slope="2" />
          </feComponentTransfer>
          <feBlend in2="SourceGraphic" />
        </filter>
      </defs>
      
      <g filter="url(#glow)">      
        <circle cx="150" cy="150" r="145" mask="url(#circle-mask)" fill="url(#gradient)"/>
      </g>
    </svg>