W3docs

SVG Drop Shadows

Read and learn about the drop shadows, the <defs> and <filter> elements. See examples of the SVG <feOffset>, <feGaussianBlur>, <feColorMatrix> elements.

A drop shadow makes an SVG shape look like it floats above the page by painting a blurred, offset copy of the shape behind it. In SVG you build that effect from low-level filter primitives — small building blocks like blur and offset that you chain together inside a <filter> element.

When to use SVG filters vs CSS

You have three ways to add a shadow, and they are not interchangeable:

  • box-shadow (CSS) — works on the rectangular box of an HTML/CSS element. It does not follow the shape of SVG paths, so a triangle still gets a rectangular shadow. Best for boxes, cards, and buttons.
  • filter: drop-shadow() (CSS) — follows the actual painted shape (including SVG paths and transparent PNGs). It is the quickest way to drop-shadow an SVG from a stylesheet and is widely supported. Use it when you just need a shadow and don't need fine control.
  • SVG <filter> (this chapter) — the most powerful option. You control each step (offset distance, blur radius, shadow color, blend mode) and can combine several primitives. Use it when you need a colored shadow, an inner shadow, or any effect beyond a plain blur.

This chapter covers the SVG <filter> approach. For other filter effects, see SVG Blur Effects and the SVG Filters intro.

Description of SVG filters

All SVG filters are defined inside a <defs> element. The <defs> element is a short form of definitions. It contains a definition of specific elements like filters. The <filter> element defines an SVG filter. This element has an id attribute (required) identifying the filter, which you then reference from a shape with filter="url(#id)".

Filter primitives and inputs

Every primitive reads an input image and writes an output image. Two special inputs are built in:

  • SourceGraphic — the original shape with all of its colors.
  • SourceAlpha — the same shape but using only its alpha (opacity) channel, so it comes out as a solid black silhouette. This is the usual starting point for a shadow, because a shadow should be a dark copy of the shape, not a recolored copy.

You wire primitives together with two attributes:

  • in — which image this primitive reads (e.g. SourceAlpha, or a result name from an earlier primitive).
  • result — a name you give this primitive's output so a later primitive can read it.

The primitives used in this chapter:

  • <feOffset> — shifts an image by dx (horizontal) and dy (vertical). This positions the shadow away from the shape.
  • <feGaussianBlur> — blurs an image. Its stdDeviation attribute sets the blur radius: larger values give a softer, wider shadow.
  • <feColorMatrix> — transforms each pixel's RGBA values, which is how you tint a shadow a custom color.
  • <feBlend> / <feMerge> — combine two images. <feBlend> stacks two inputs (in and in2) using a mode such as normal; <feMerge> layers any number of inputs in order. Both are used here to paint the original graphic on top of the finished shadow.

To create drop shadows, use the <feOffset> element. You take a copy of the SVG graphic and move it in the xy plane, then blur it, then draw the original on top.

Example of the SVG <feOffset> element:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="150" height="150">
      <defs>
        <filter id="filter" x="0" y="0" width="150%" height="150%">
          <feOffset result="offOut" in="SourceGraphic" dx="30" dy="30" />
          <feBlend in="SourceGraphic" in2="offOut" mode="normal" />
        </filter>
      </defs>
      <rect width="110" height="110" stroke="purple" stroke-width="5" fill="pink" 
            filter="url(#filter)" /> 
      Sorry, your browser doesn't support inline SVG.
    </svg>
  </body>
</html>

In the example above, the <filter> element’s id attribute specifies a unique name for the filter, and the <rect> element’s filter attribute links the rectangle to that filter. <feOffset> copies SourceGraphic and moves it 30px right and 30px down (dx="30" dy="30"), saving the result as offOut. <feBlend> then draws the original SourceGraphic on top of offOut, so you see the shape with a hard-edged offset copy behind it.

Example of the SVG <feGaussianBlur> element:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg width="200" height="200">
      <defs>
        <filter id="filter" x="0" y="0" width="250%" height="250%">
          <feOffset result="offOut" in="SourceGraphic" dx="30" dy="30" />
          <feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
          <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
        </filter>
      </defs>
      <rect width="150" height="150" stroke="coral" stroke-width="5" fill="pink" 
            filter="url(#filter)" /> 
      Sorry, your browser doesn't support inline SVG.
    </svg>
  </body>
</html>

Here the offset copy is blurred with the <feGaussianBlur> element. Its stdDeviation attribute specifies the amount of blur — raise it for a softer shadow, lower it for a crisper one. Because the input is still SourceGraphic, the blurred copy keeps the shape's colors, which is usually not what a real shadow looks like. The next example fixes that.

Example of a black (silhouette) shadow with SourceAlpha:

To make the shadow a dark silhouette instead of a blurred clone of the colored shape, feed <feOffset> the SourceAlpha input instead of SourceGraphic. SourceAlpha carries only opacity, so the offset, blurred copy comes out solid black — exactly what a shadow should be.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg height="200" width="200">
      <defs>
        <filter id="filter" x="0" y="0" width="150%" height="150%">
          <feOffset result="offOut" in="SourceAlpha" dx="15" dy="15" />
          <feGaussianBlur result="blurOut" in="offOut" stdDeviation="8" />
          <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
        </filter>
      </defs>
      <rect width="120" height="120" stroke="purple" stroke-width="5" fill="pink" 
            filter="url(#filter)" /> 
       Sorry, your browser doesn't support inline SVG.
    </svg>
  </body>
</html>

To tint the shadow a custom color, use the <feColorMatrix> element. It multiplies each pixel's red, green, blue, and alpha values by the numbers you supply, so you can darken or recolor the offset copy before blurring it.

Example of coloring the shadow with <feColorMatrix>:

In the matrix below, the red, green, and blue channels are each scaled to 0.2 (the first three diagonal values), which darkens the offset copy toward a dim color, while the alpha channel stays at 1 (the fourth diagonal value) so the shadow keeps the shape's opacity. Change the three 0.2 values to tint the shadow — for example, a higher red value gives a reddish shadow.

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg height="200" width="200">
      <defs>
        <filter id="filter" x="0" y="0" width="150%" height="150%">
          <feOffset result="offOut" in="SourceGraphic" dx="25" dy="25" />
          <feColorMatrix result="matrixOut" in="offOut" type="matrix" 
                         values="0.2 0 0 0 0 0 0.2 0 0 0 0 0 0.2 0 0 0 0 0 1 0" />
          <feGaussianBlur result="blurOut" in="matrixOut" stdDeviation="9" />
          <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
        </filter>
      </defs>
      <rect width="150" height="150" stroke="purple" stroke-width="5" fill="lightblue" 
            filter="url(#filter)" /> 
       Sorry, your browser doesn't support inline SVG.
    </svg>
  </body>
</html>

The <feDropShadow> shorthand

Chaining <feOffset>, <feGaussianBlur>, and <feBlend> is verbose for such a common effect. The <feDropShadow> primitive bundles all three into one element and is supported across modern browsers. You set the offset with dx / dy, the softness with stdDeviation, and the color with flood-color (and optionally flood-opacity).

Example of the SVG <feDropShadow> element:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <svg height="200" width="200">
      <defs>
        <filter id="shadow" x="-20%" y="-20%" width="150%" height="150%">
          <feDropShadow dx="15" dy="15" stdDeviation="8" flood-color="purple" flood-opacity="0.5" />
        </filter>
      </defs>
      <rect width="120" height="120" stroke="purple" stroke-width="5" fill="pink" 
            filter="url(#shadow)" /> 
      Sorry, your browser doesn't support inline SVG.
    </svg>
  </body>
</html>

This produces the same kind of result as the multi-primitive examples above with a single line.

Practice

Practice
Which SVG filter input should you feed into 'feOffset' to make a black silhouette shadow rather than a recolored copy of the shape?
Which SVG filter input should you feed into 'feOffset' to make a black silhouette shadow rather than a recolored copy of the shape?
Was this page helpful?