SVG use and gradients as fill - html

I've been trying to externalize my SVG icons to a file and referencing them with markup like <svg><use xlink:href="file.svg#icon" /></svg>. In theory this works really nicely, but different browsers have issues with rendering. All the browsers are able to render the svg correctly when referencing the symbol with <use> inside the file and opening the svg file's url directly.
In short, is there a cross-browser way to get SVG linearGradients working as fills for elements when referencing the symbols with <svg><use/></svg> in the markup?
I set up a plunker demonstrating the problem:
http://plnkr.co/edit/feKvZ7?p=preview
Simplified, the markup is like the following:
<!DOCTYPE html>
<html>
<body>
<h1>SVG sprite test</h1>
<svg width="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<use xlink:href="icon.svg#icon" />
</svg>
</body>
</html>
And the SVG file looks like this:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="gradient">
<stop offset="0" stop-color="black" />
<stop offset="1" stop-color="white" />
</linearGradient>
</defs>
<symbol id="icon" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" stroke="black" fill="url(#gradient)" />
</symbol>
<use id="iconuse" xlink:href="#icon" width="100" height="100" />
</svg>
This is what it looks like in the different browsers:

The symbol tag is used to hide the elements that are inside it. Elements inside the symbol are called using the <use> command by their unique indicator.
Therefore, it is better to use this method of calling individual elements rather than calling the whole symbol
In addition, elements when using <use> fall into the shadow DOM and using CSS in some cases becomes impossible
Therefore, it is better to delete all internal styles inside symbol and assign them directly to the use command
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="gradient">
<stop offset="0" stop-color="black" />
<stop offset="1" stop-color="white" />
</linearGradient>
</defs>
<symbol id="icon" viewBox="0 0 100 100">
<circle id="circle" cx="50" cy="50" r="40" />
<rect id="rect" x="100" y="10" width="100" height="100" />
</symbol>
<use class="iconuse" xlink:href="#circle" width="100" height="100" fill="url(#gradient)" stroke="black" />
<use class="iconuse" xlink:href="#rect" width="100" height="100" fill="url(#gradient)" />
</svg>

Try next one (it's how Inkscape provide implementation of gradients):
<linearGradient id="gradient">
<stop
style="stop-color:black;"
offset="0"/>
<stop
style="stop-color:white;"
offset="1" />
</linearGradient>
...
<path
style="fill:url(#gradient); ...

Related

How can I use gradients from SVG symbols in other files?

I have found that when I have a source SVG with a symbol and a destination SVG that access the source SVG with <use>, the symbol is imported and is able to access the gradient (perhaps because it is simply already on the page). However, when the source SVG is in a different file, the objects in the <symbol> are imported but not the gradient. How can I import the gradient as well?
Here is some MCVE code:
index.html:
<style>
html,body,svg { width: 100% }
</style>
<!-- inline SVG with gradient -->
<svg viewBox="0 0 80 20" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
  <symbol id="myDot" width="10" height="10" viewBox="0 0 2 2">
<linearGradient id="linear-gradient" x1="0.133" y1="0.008" x2="0.949" y2="1.101" gradientUnits="objectBoundingBox">
<stop offset="0.042" stop-color="#21dbaa"/>
<stop offset="0.358" stop-color="#00b4ef"/>
<stop offset="0.433" stop-color="#01a7ec"/>
<stop offset="0.568" stop-color="#0487e4"/>
<stop offset="0.68" stop-color="#0768dd"/>
<stop offset="0.965" stop-color="#5f1ae5"/>
</linearGradient>
    <circle cx="1" cy="1" r="1" fill="url(#linear-gradient)"/>
  </symbol>
</svg>
<svg viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
 
  <!-- All instances of our symbol -->
  <use xlink:href="#myDot" x="5"  y="5" style="opacity:1.0" />
  <use xlink:href="#myDot" x="20" y="5" style="opacity:0.8" />
  <use xlink:href="symbol.svg#myDot" x="35" y="5" style="opacity:0.6" stroke="black" stroke-width=".1" />
  <use xlink:href="symbol.svg#myDot" x="50" y="5" style="opacity:0.4" stroke="black" stroke-width=".1" />
  <use xlink:href="symbol.svg#myDot" x="65" y="5" style="opacity:0.2" stroke="black" stroke-width=".1" />
</svg>
symbol.svg:
<!-- external SVG with gradient -->
<svg viewBox="0 0 80 20" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
  <symbol id="myDot" width="10" height="10" viewBox="0 0 2 2">
<linearGradient id="linear-gradient" x1="0.133" y1="0.008" x2="0.949" y2="1.101" gradientUnits="objectBoundingBox">
<stop offset="0.042" stop-color="#21dbaa"/>
<stop offset="0.358" stop-color="#00b4ef"/>
<stop offset="0.433" stop-color="#01a7ec"/>
<stop offset="0.568" stop-color="#0487e4"/>
<stop offset="0.68" stop-color="#0768dd"/>
<stop offset="0.965" stop-color="#5f1ae5"/>
</linearGradient>
    <circle cx="1" cy="1" r="1" fill="url(#linear-gradient)"/>
  </symbol>
</svg>
Here is a working Codepen demo that illustrates the problem, using the same code as shown above. Notice how the two circles importing the symbol from the inline SVG in index.html are correctly displaying the gradient, but the three circles importing the symbol from symbol.svg are not displaying the gradient.
Edit: This may be a duplicate of another question asking about referencing gradients in external files.
Looks like browser support for this feature is still somewhat low (source). The example given in the question should in theory work in a couple years.
One workaround is to include the gradient definitions on every page where external SVGs are referenced and point to that instead.
index.html:
<svg style="height: 0; width: 0;" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="linear-gradient" x1="0.133" y1="0.008" x2="0.949" y2="1.101" gradientUnits="objectBoundingBox">
<stop offset="0.042" stop-color="#21dbaa"/>
<stop offset="0.358" stop-color="#00b4ef"/>
<stop offset="0.433" stop-color="#01a7ec"/>
<stop offset="0.568" stop-color="#0487e4"/>
<stop offset="0.68" stop-color="#0768dd"/>
<stop offset="0.965" stop-color="#5f1ae5"/>
</linearGradient>
</defs>
</svg>
<svg>
<use xlink:href="#myDot" fill="url(#linear-gradient)" />
</svg>
symbol.svg:
<svg viewBox="0 0 80 20" xmlns="http://www.w3.org/2000/svg">
<symbol id="myDot" width="10" height="10" viewBox="0 0 2 2">
<circle cx="1" cy="1" r="1" fill="url(#linear-gradient)"/>
</symbol>
</svg>

Cannot display linear gradient as a background image on a html page

<svg version="1.1" xmlns="http://w3.org/2000/svg">
<title> Background </title>
<text>
<LinearGradient id="g" x1="200%" x2="0%" y1="50%" y2="0%">
<stop style = "stop-color: green;" offset="0"/>
<stop style = "stop-color: white;" offset="1"/>
</LinearGradient>
</text>
<rect style = "fill: url(#g);" width = "100%" height = "100%"/>
</svg>
The output of this code is either broken image, or the Title "Background" and I do not see what's wrong with it.
You've two issues which affect standalone SVG only
the SVG namespace is incorrect so the file is not recognised as an SVG file. You're missing www from the namespace.
standalone SVG files are case sensitive so we need to write linearGradient
And this one is a bug even when you embed SVG in html.
you can't make a linearGradient the child of a <text> tag. We can use <defs> instead. In theory we could omit the <defs> tag, although I think Safari isn't keen on that.
which leaves us with this...
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<title> Background </title>
<defs>
<linearGradient id="g" x1="200%" x2="0%" y1="50%" y2="0%">
<stop style = "stop-color: green;" offset="0"/>
<stop style = "stop-color: white;" offset="1"/>
</linearGradient>
</defs>
<rect style = "fill: url(#g);" width = "100%" height = "100%"/>
</svg>
You should use defs for the gradient. You may also consider viewbox and width/height:
<svg version="1.1" xmlns="http://w3.org/2000/svg" viewBox="0 0 200 100" width="200">
<title> Background </title>
<defs>
<LinearGradient id="g" x1="200%" x2="0%" y1="50%" y2="0%">
<stop style = "stop-color: green;" offset="0"/>
<stop style = "stop-color: white;" offset="1"/>
</LinearGradient>
</defs>
<rect fill="url(#g)" x="0" y="0" width="200" height="100" />
</svg>

SVG Symbol animate not working with Safari

I'm currently struggling with a SVG.
Right now, I'm trying to display an animated SVG in my webpage. In order to do it, I just put the svg code at the end of the body, and used the html tag "use" to embed my SVG (which contains a symbol).
Here is my SVG code :
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient x1="100%" y1="0%" x2="0%" y2="100%" id="linearGradient">
<stop offset="0%" stop-color="#7A5FFF">
<animate attributeName="stop-color" values="#05FFA3; #45CAFC; #7873F5; #FC6262; #05FFA3;" dur="10s" repeatCount="indefinite"></animate>
</stop>
<stop offset="100%" stop-color="#01FF89">
<animate attributeName="stop-color" values="#2096FF; #303F9F; #FF6EC4; #FFD86F; #2096FF;" dur="10s" repeatCount="indefinite"></animate>
</stop>
</linearGradient>
</defs>
<symbol x="0px" y="0px" width="308px" height="308px" viewBox="0 0 308 308" id="svg-logo">
<circle cx="150" cy="150" r="150" fill="url(#linearGradient)" />
</symbol>
</svg>
And here is the way I embed it in my page :
<svg class="star">
<use xlink:href="#svg-logo">
</svg>
It works fine, except on safari. The linear gradient animation is completely broken, and looks like this :

SVG <use> with xlink.href not working with the fill url() attribute in Chrome and Mozilla

I'm trying to apply styles to <use> element. I have an attribute xlink.href for shape and attribute fill with the linearGradient
The problem is that in Google Chrome this gradient is not displayed with the <use> tag, although in Microsoft Edge everything is fine, so we have a gradient filling for <rect> and <use> elements
Google Chrome:
<svg width="100" height="100">
<use
class="tooth-crown-main"
xlink:href="/assets/teeth/teeth.svg#b1-crown"
x="0" y="0"
fill="url(#ToothBackground)"
stroke="#a7a9ac" stroke-alignment="inner" stroke-width="0.3">
</use>
<rect x="10" y="10" width="50" height="50" fill="url(#ToothBackground)" />
</svg>
<svg width="100" height="1" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="ToothBackground" gradientTransform="rotate(90)">
<stop offset="0%" stop-color="#e3f3ef" />
<stop offset="30%" stop-color="#ffffff" />
<stop offset="70%" stop-color="#ffffff" />
<stop offset="100%" stop-color="#e3f3ef" />
</linearGradient>
</defs>
</svg>
Microsoft Edge:
In Google Chrome earlier this worked fine, the same as in Microsoft Edge. Is it possible that the problem is related to the Chrome updates?
Any ideas how to fix that?
Thanks!

Firefox doesn't adhere to preserveAspectRatio

I have the following graphic embedded into markup:
<div id="svgContainer" >
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
preserveAspectRatio="xMaxYMin meet"
viewBox="0 0 1800 1111">
<defs>
<linearGradient id="gradient" x1="0" y1="00%" x2 ="0" y2="100%">
<stop stop-color="black" offset="0"/>
<stop stop-color="white" offset="1"/>
</linearGradient>
<mask id="masking" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
<rect y="0.3" width="1" height=".7" fill="url(#gradient)" />
<circle cx=".5" cy=".5" r=".5" fill="white" />
</mask>
</defs>
<foreignObject width="100%" height="100%"
id="coverImageContainer" mask="url(#masking)">
<img id="coverImage" src="/images/v3/eminem-cover.jpg" />
</foreignObject>
</svg>
</div>
On Safari and Chrome, the graphic resizes appropriately using the center of the graphic as the appropriate anchor point. On Firefox, however, the image resizes as thought I had set preserveAspectRatio on the svg element to xMinYMax meet. Any ideas what's causing this discrepency in behavior?