SVG Linear gradient doesn't work in Safari - html

I've got an SVG object that contains a linear gradient embedded directly in a document. It works fine in Chrome and Firefox, but in Safari nothing is rendered. If I create the SVG as a file and embed it using the Object tag, it works fine in Safari. Other shapes and fills work, it's just linear gradient that doesn't work. I guess I could use the object, but I'd prefer to embed the SVG directly.
I've create a demo here (works in Chrome, not Safari): http://jsfiddle.net/sjKbN/
I came across this answer which suggests setting the content type to application/xhtml+xml, but this in itself seems to cause other problems.
Just wondering if anyone had come across any other fixes or ideas to get this working.

Your gradient will work in Safari if you wrap a defs tag around it:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve">
<defs>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="5.6665" y1="149.5" x2="293.333" y2="149.5">
<stop offset="0" style="stop-color:#FFF33B"/>
<stop offset="0.0595" style="stop-color:#FFE029"/>
<stop offset="0.1303" style="stop-color:#FFD218"/>
<stop offset="0.2032" style="stop-color:#FEC90F"/>
<stop offset="0.2809" style="stop-color:#FDC70C"/>
<stop offset="0.6685" style="stop-color:#F3903F"/>
<stop offset="0.8876" style="stop-color:#ED683C"/>
<stop offset="1" style="stop-color:#E93E3A"/>
</linearGradient>
</defs>
<rect x="5.667" y="5.333" fill="url(#SVGID_1_)" width="287.667" height="288.333"/>
</svg>
​It seems that wrapping your references in defs is encouraged but not obligatory according to spec. So this is a bug in Safari.

About Alpha : It seems that Safari (7 at this moment) does not cover SVG color alpha channel, use stop opacity attribute. it works fine!
<stop stop-color="rgba(x,y,z,0.5)"> //safari does not work
<stop stop-color="rgb(x,y,z)" stop-opacity="0.5"> //ok

The accepted answer was not the solution for me.
My problem was the presence of a <base href="/" /> tag in my index file. Simply removing it solved the problem for me.
If you cannot remove it, probably some workaround already exist: found this gist but I did not tested it.
Update
Simply removing the href broke the child routing of my angular app, the proper workaround is to prepend to the linearGradient id with the page relative location. I wrapped the logic in a method like this:
get svgFill(): string {
return `url(${this.location.path()}#${this.gradientId}) white`;
}

The answer is simple, all id's (not only <linear gradient>) need to be UNIQUE for all SVG files.

I had some troubles too making an inline SVG with a linear gradient work. The designer had put a - in the id of the <linearGradient. The solution was as simple as removing it.
<linearGradient id="linear-gradient">
...
<path fill="url(#linear-gradient)" d="..."/>
with
<linearGradient id="lineargradient">
...
<path fill="url(#lineargradient)" d="..."/>

Related

SVG <linearGradient> code keeps breaking when rendered in any browser

I've scoured all corners of the web looking for a solution to this but it seems no one else has had this issue.
Here is my current code:
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="mygradient">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="yellow"/>
</linearGradient>
</defs>
<path id="myID" d="M 0 78.37136556477951 C 207.875 51.32892778872315 207.875 51.32892778872315 415.75 64.85014667675132 C 623.625 78.37136556477951 623.625 78.37136556477951 831.5 60.035876993171016 C 1039.375 41.70038842156255 1039.375 41.70038842156255 1247.25 64.68862384088634 C 1455.125 87.67685926021014 1455.125 87.67685926021014 1663 60.035876993171016 L 1663 3756 L 0 3756 Z" fill="url(#mygradient)"/>
</svg>
Whenever any browser tries to render this, the <linearGradient> breaks completely. This is how it renders in browsers:
<lineargradient id="mygradient"><stop offset="0%" stop-color="red"></stop offset="0%" stop-color="red"><stop offset="100%" stop-color="yellow"></stop offset="100%"></lineargradient id="mygradient">
As you can see, all spaces in the <linearGradient> become and <linearGradient> becomes <lineargradient>.
Any help with this will be appreciated.
Sorted this one out, pasted my <linearGradient> code snippet into a minifier which seemed to fix the issue. Don't know why but it just did.

SVG animation waits for DOMLoad event, timelineBegin="onStart" is not working?

As explained in this page svg animation timeline starts with DOMLoad event has been triggered. But u can change it to svg's load by timelineBegin="onStart".
I want to use svg as a preloaded and it should start animation immidately.
Why my animation still waits for DOMLoad event:
<svg id="map" version="1.2" width="100%" viewbox="-2 -2 506.3302 339.85639" xmlns:svg="http://www.w3.org/2000/svg" timelineBegin="onStart">
<defs>
<radialgradient id="grad1" cx="0.65" cy="0.78" r="0.08" rx="0.5" ry="1">
<stop offset="0.8" style="stop-color: #1a1a1a; stop-opacity:1"></stop>
<stop offset="100%" style="stop-color:rgb(255,255,255);stop-opacity:1"></stop>
<animate id="map-animation" attributeName="r" dur="2500ms" from="0.08" to="1.2" fill="freeze"/>
</radialgradient>
</defs>
<path id="map" fill="url(#grad1)" d="m733.83-66.9...>
</svg>
As Robert Longson commented, timelineBegin="onStart" is an attribute only defined for SVG 1.2 Tiny, and SVG 1.2 Tiny never got browser support. (SVG 1.1 Tiny SVGs should show up fine in all modern, full web browsers, but that's to be expected, because aside from the required version="1.1" baseProfile="tiny" attributes, those are the same as any other version 1.1 SVGs, except certain elements, attributes, and style properties are disallowed.)
However, if you want an alternative, it occurred to me that wrapping an SVG in an iframe could achieve a similar result. See https://jsfiddle.net/potsq649/
(There may be downsides to this depending on how you intended to use the SVG; e.g. this complicates script interaction with the SVG a bit, but that can still be done. If you use a data URI as I did in the example, URL-encode characters as needed, including any "#" characters, which need to be URL-encoded to %23 to avoid Firefox treating the text after that as a fragment identifier.)

SVG Linked from same svg file causes one to disappear

Strange one this.
I've got the following:
<svg aria-hidden="true">
<use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#down"></use>
</svg>
<table>
<tr>
<td>
<svg aria-hidden="true">
<use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#close"></use>
</svg>
</td>
</tr>
</table>
The first icon doesn't show up. However if I change the svg file of the first to:
<svg aria-hidden="true">
<use xlink:href="/assets/icons/standard-sprite/svg/symbols.svg#down"></use>
</svg>
Then both show, is there something I'm missing with SVG from the same file?
It's definitely not a URL thing, because if both <svg> tags use the same URL, then only the second is displayed.
Many Thanks
HOPE THIS HELPS TO ALL NEW PEOPLE
After all this years I stumbled upon the same problem and I solved it...
What happened for me was that the fill attributes of my paths shared the same url(#paint0_linear) and the viewbox of these "fill" where set on the position of the first SVG in the DOM, to solve this just change the name of the fills (and their corresponding id's) of the subsequent SVGS.
English is not my native language so let me show you what I did in code in case I didn't make myself clear:
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="hamb1">
<path id="hambBottom1" fillRule="evenodd" clipRule="evenodd" d="M0 22" fill="url(#paint0_linear)"/>
<path id="hambTop1" d="M13.8599" fill="url(#paint1_linear)"/>
</g>
<defs>
<linearGradient id="paint0_linear" x1="-6.5" y1="30" x2="18.9429" y2="34.8415" gradientUnits="userSpaceOnUse">
<stop stopColor="#134F82"/>
<stop offset="1" stopColor="#2BA665"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="-6.50012" y1="30" x2="18.9428" y2="34.8414" gradientUnits="userSpaceOnUse">
<stop stopColor="#134F82"/>
<stop offset="1" stopColor="#2BA665"/>
</linearGradient>
</defs>
</svg>
Check that the fill attribute on the paths NEVER share the same id.
I can't be completely sure since I guess you should explain question properly, But it may be the case that first file path may not be correct (ie with link "/assets/icons/utility-sprite/svg/symbols.svg#down") (ie may be some spell error) so the file is not loading. Try loading file manually with url.

Referring to local ID in the context of a <BASE> tag (SVG on Firefox)

My problem happens on a current Firefox on Win7 using SVG (this might not be too relevant to the actual problem):
`
<head>
<!-- base href="http://127.0.0.1/package/index.php" /-->
</head>
<body>
<svg height="150px" width="400px">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:rgb(120,120,120);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(40,40,40);stop-opacity:1" />
</linearGradient>
</defs>
<rect x="225" y="30" width="80" height="28" fill="url(#grad1)"/>
</svg>
</body>
</html>
`
The gradient is identified by the ID (grad1) and referred to by the rect-tag. This works fine as long as the base-tag is commented out as above. As soon as the base-tag is set free, my pretty rectangle disappears; presumably because the ID is appended to the URL defined in the base tag. When that happens, Firefox appears to make an extra round trip to the server.
My problem is, this page in kept in a package that sometimes includes the base-tag and sometimes does not. I appear not to have much control over that without modifying that other software (which I do not want to do) So my question is: how can I "anchor" the references to the ID's in the local file, so that they become independent of the presence of the base-tag ?
If your <base> element refers to an other page, then FF behavior is the correct one.
Relative <funcIRI> should be read as url(<currentURI>#element).
The <base> element does change the currentURI of the document to the one set in its href attribute.
So a possible solution, if you have access to the svg markup, is to use an absolute path in the <funcIRI> : url(://path/to/your/page.php#element).
This way, the base element won't have any influence on the <funcIRI> you do use.
Also, you may have an issue if the cache-control header of the php response is set to no-cache, this may make the browser to always send a new request to the server.

SVG Rounding Bug

Chrome's way of rounding sub-pixel values in SVGs creates a problem for me.
Is there any way to fix this problem? Because I use opacity I'm not able to simply add a dark background to remove the white glimps.
Here's the example:
http://dabblet.com/gist/766f6a238d00bcbb41d4
You can create a filter to add "grout" into the gap :) But it's a hack that works by increasing the opacity of those pixels. It will also roughen up the anti-aliasing of our other edges. Also if you're using opacity in these gradients then you will need to adjust those tableValues below to the range that you want (aka if your fill is 0.4 opacity, then your tableValues would look like "0 .1 .4 .4 .4"). If you have variable opacity in your gradients, then you can play around with other types of component transfers that will preserve the opacity gradients better.
<svg id="background-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 150 75" >
<defs>
<linearGradient y2="1" x2="1" y1="0" x1="0" id="triangleGradient">
<stop stop-color="black" offset="0"/>
<stop stop-color="blue" offset="1"/>
</linearGradient>
<filter id="mynameisgrout">
<feComponentTransfer>
<feFuncA type="table" tableValues="0 .25 1 1 1"/>
</feComponentTransfer>
</filter>
</defs>
<g filter="url(#mynameisgrout)">
<polygon points="0,75 100,75 50,0" fill="url(#triangleGradient)"></polygon>
<polygon points="50,0 150,0 100,75" fill="url(#triangleGradient)"></polygon>
</g>
</svg>
The SVG shape rendering option allows to configure what's important for rendering.
In this case shape-rendering="crispEdges" solves the problem.
See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering