11

I've been playing around with SVGs in websites, and I've been trying to get filters to work, but I can't seem to get it right.

The problem is that the svg disappears completely once I apply a defined filter. I've tried to apply the filter inline, just to see if it worked, like this:

<symbol id="circle" viewBox="0 0 400 209.603" filter="url('#blur-filter')">
...
</symbol>

but with no success.

Ultimately, my goal is that I would be able to apply the filters via CSS, but I can't seem to get it to work, and this is the first time I've really played around with SVGs, so I don't know if I'm making some obvious mistake.

Code:

.svg-circle:hover {
  filter: url("#blur-filter");
}
.svg-grey {
  fill: #333;
}
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
  <defs>
    <filter id="blur-filter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="2" />
    </filter>
    <symbol id="circle" viewBox="0 0 400 209.603">
      <circle cx="100" cy="100" r="100" />
    </symbol>
  </defs>
</svg>

<svg>
  <use xlink:href="#circle" class="svg-circle svg-grey"/>
</svg>

I want the filter to be applied when I hover over the element. My other question is how I can incorporate this with CSS transitions, so that the blur gets applied gradually, like other css3 transitions.

I also want the filters to be global, so they can be reused across multiple svg images whenever I want, so define once, and reuse.

I've also created a Codepen to demonstrate my problem.

dippas
  • 58,591
  • 15
  • 114
  • 126
Pavlin
  • 5,390
  • 6
  • 38
  • 51

3 Answers3

4

Remove your style="display:none" and add width:0 to your first svg

.svg-circle:hover {
  filter: url("#blur-filter");
}
.svg-grey {
  fill: #333;
}
svg:first-of-type {
  width:0
}
<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <filter id="blur-filter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="2" />
    </filter>
    <symbol id="circle" viewBox="0 0 400 209.603">
      <circle cx="100" cy="100" r="100" />
    </symbol>
  </defs>
</svg>
<svg>
  <use xlink:href="#circle" class="svg-circle svg-grey"/>
</svg>
dippas
  • 58,591
  • 15
  • 114
  • 126
  • This seems like a good train of thought, but the `display: none`is there for a reason. As you can see on your example, the svg tag takes up some space, which is not what I want. I want definitions at the top of my html, and they should take up no space. Do you have any idea on how to get around this? – Pavlin Feb 16 '16 at 16:07
  • @Pavlin, but they do not take space by default. – Qwertiy Feb 16 '16 at 16:09
  • @Qwertiy but it does take up space, if you look at his first snippet. – Pavlin Feb 16 '16 at 16:11
  • @Pavlin I updated my first snippet, to remove the space, take a look – dippas Feb 16 '16 at 16:12
  • 1
    @Pavlin, because you aren't specifiing the sizes. See my answer. – Qwertiy Feb 16 '16 at 16:17
  • You still have the space between svg tags. Classic problem with inline-blocks. – Qwertiy Feb 16 '16 at 16:20
  • Yes, I can fix the existing spacing easily now. This seems to be a very strange "feature" of svgs... I've got it to work now. – Pavlin Feb 16 '16 at 16:21
2

Remove the display: none; on the definitions SVG and give it 0 dimensions. This should do it. Somehow the filter may be inheriting that display: none.

.svg-circle:hover {
  filter: url("#blur-filter");
}
.svg-grey {
  fill: #333;
}
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
  <defs>
    <filter id="blur-filter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="2" />
    </filter>
    <symbol id="circle" viewBox="0 0 400 209.603">
      <circle cx="100" cy="100" r="100" />
    </symbol>
  </defs>
</svg>

<svg>
  <use xlink:href="#circle" class="svg-circle svg-grey"/>
</svg>

As for the transition, I don't think you can do that by using referenced filters.

Alin Purcaru
  • 43,655
  • 12
  • 77
  • 90
  • As I remember, you can, if they both are inlined into same html and ids are unique or if you specify the path (not just an anchor) to other svg. – Qwertiy Feb 16 '16 at 16:08
  • Your example does work, but it does the opposite of what I want to achieve. I want svg definitions at the top, so that I can reuse them multiple times across the page. If I did it the way you've done it, I'd need to copy the paths several times throughout the page. – Pavlin Feb 16 '16 at 16:09
  • @Pavlin I was wrong with my first assumption. I updated the answer. – Alin Purcaru Feb 16 '16 at 16:12
2

html, body {
  margin: 0;
  padding: 0;
}

.svg-circle:hover {
  filter: url("#blur-filter");
}

.svg-grey {
  fill: #333;
}
<svg width="0" height="0">
  <defs>
    <filter id="blur-filter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="2" />
    </filter>
    <symbol id="circle" viewBox="0 0 400 209.603">
      <circle cx="100" cy="100" r="100" />
    </symbol>
  </defs>
</svg><svg width="400" height="210">
  <use xlink:href="#circle" class="svg-circle svg-grey"/>
</svg>
Qwertiy
  • 19,681
  • 15
  • 61
  • 128