23

I have the following SVG graphic:

<svg width='36' height='30'>
  <defs>
    <linearGradient id="normal-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" style="stop-color:rgb(81,82,84); stop-opacity:.4"/>
      <stop offset="100%" style="stop-color:rgb(81,82,84); stop-opacity:1"/>
    </linearGradient>
    <linearGradient id="rollover-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" style="stop-color:rgb(0,105,23); stop-opacity:.5"/>
      <stop offset="100%" style="stop-color:rgb(0,105,23); stop-opacity:1"/>
    </linearGradient>
    <linearGradient id="active-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" style="stop-color:rgb(0,0,0); stop-opacity:.4"/>
      <stop offset="100%" style="stop-color:rgb(0,0,0); stop-opacity:1"/>
    </linearGradient>
  </defs>

  <text x="8" y="25" style="font-size: 29px;" font-family="Arial">hello world</text>
</svg>'

I set the fill attribute of the text element through CSS and switch between the various gradients depending on the hover state. This works great in Chrome & Safari, but in Firefox, the text doesn't show up. Upon inspecting the element, I discovered that Firefox is appending none to the end of my fill: url(#...) CSS attribute. I tried deleting the none keyword with Firebug, but Firebug just deletes the entire attribute. Why is this happening?

EDIT: I should note that if I remove the CSS that sets the fill property, and hardcode the fill attribute into the text element (not through an inline style attribute), the text displays properly in all browsers.

Nathan Friend
  • 12,155
  • 10
  • 75
  • 125
  • 1
    What does your actual CSS look like, to go with that SVG? As for the "none" thing, "fill: url(whatever) none" is the same thing as "fill: url(whatever)"; both say that if the thing at the url is not available there is no fallback and nothing should be painted. – Boris Zbarsky Feb 28 '13 at 06:35
  • @BorisZbarsky Thanks, I didn't realize that the 'none' specified what happens when the first resource isn't found. – Nathan Friend Feb 28 '13 at 14:45

3 Answers3

41

Figured it out. In my CSS, I was referring to the gradients in the same way I was originally referencing the fill inline:

#myselector {
    fill: url('#gradient-id');
}

To get it working in Firefox, I had to change it to this:

#myselector {
    fill: url('/#gradient-id');
}

Not sure why this is. Maybe it has something to do with the directory structure containing my stylesheet?

Nathan Friend
  • 12,155
  • 10
  • 75
  • 125
  • 4
    A relative `url()` in a stylesheet is resolved relative to the stylesheet. So if your stylesheet and SVG are in different directories, chances are you weren't linking to the SVG at all. – Boris Zbarsky Feb 28 '13 at 17:00
  • 1
    Webkit doesn't do this right and I'm pretty sure Boris reported that to their bugtracker some time ago. – Robert Longson Feb 28 '13 at 18:32
  • Hi Boris, I'm also having this problem, I've seen you commenting frequently on the Firefox bug reports, can you explain why fill: url("#gradient-id") doesn't find that gradient id in the dom when specified in css, but does inline? I'm not loading svgs external to my page... Is Chrome's implementation of this incorrect? This seems like it should be the expected behavior. – Daniel Apr 05 '13 at 17:55
  • 5
    the fact that the url is resolved as expected when placed inline like style="fill: url(#gradient-id)" but NOT when placed in a stylesheet seems to indicate it is a bug, unless there is a nuance of spec implementation that I am missing – Daniel Apr 05 '13 at 18:02
  • @Daniel, you should post this as an answer. It seems to be a general solution to this problem. – Frederik Wordenskjold Apr 16 '13 at 13:55
  • 8
    You saved me an amazing amount of time with this answer. Was pulling my hair out when the gradients just would not show up on firefox! – bantic Oct 22 '13 at 02:37
  • @Daniel When placed inline, the hash is relative to the page's current URL. In a stylesheet, it's relative to the stylesheet's URL. – Curtis Blackwell Oct 10 '14 at 04:40
  • Yeah it has to be relative. This worked for me fill: url(./#gradient-id); – Miguel Mota Nov 06 '14 at 21:25
  • This does not work if the current url is not root. Adding attribute ``` fill="url(#gradient-id)" ``` directly on the tag did the trick for me. – benomite Dec 13 '16 at 11:18
8

SVG “fill: url(#…)” behave strangely in Firefox when we assigning the below code with css(both external and internal css.)

#myselector {
fill: url('#gradient-id');
}

Solution

give inline styling, this can be done in both the ways. Static or dynamic way

Dynamic way

.attr('fill', 'url(#gradient-id)')

Static way

fill="url(#gradient-id)" 

In static you have to put this in the SVG Html;

1

I had same problem with linearGradient in SVG – still in 2017. I guess, the problem is that Firefox treat url('#gradient-id') like normal URL and applied rules of <base href=""/> metatag. Comment it out and check then.

phk
  • 2,002
  • 1
  • 29
  • 54
lukdur
  • 129
  • 4
  • There's no base tag in the question. This question is about resolving a url in a CSS stylesheet. Does it resolve against the stylesheet itself (as the CSS spec says) or the document using that stylesheet (as Chrome does). – Robert Longson Apr 20 '17 at 08:50
  • 4
    Sure, it is not - I only think that this could be a reason why it is not working properly. It is a reason in my case. It is not about stylesheet, but where the **id** tag (here **gradient-id**) is placed. For some reasons using relative path **#gradient-id** with **base** metatag broke something and FF cannot find **gradient-id** tag anywhere. In my case it is not working in html (in svg circle) and in css or js with relative path. It's working when I remove **base** tag or set absolute path in js like **.attr('stroke', "url("+window.location.href+"#gradient-id)"** – lukdur Apr 20 '17 at 09:22
  • meta tag also affects Safari @lukdur. So, what's your solution to this problem? Setting the absolute path? – Alexander Burakevych May 31 '17 at 06:23
  • @AlexanderBurakevych yes. I know that this is not perfect solution, but working very well. Here you have jQuery example: `$(someCircle).attr('stroke', "url(" + window.location.href + "#gradientId)");` – lukdur Jun 01 '17 at 08:34