I have a svg file that does not render gradient in the <use>
tag. Why is it behaving differently, and how can I fix it?
SVG File:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100"
style="stroke:#000000;stroke-width:2"
xml:space="preserve"
id="pb_svg_1">
<rect width="50" height="50" style="fill: url(#lg1)"/>
<defs>
<linearGradient id="lg1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(88,88,88);stop-opacity:1"></stop>
<stop offset="100%" style="stop-color:rgb(255,255,255);stop-opacity:1"></stop>
</linearGradient>
</defs>
</svg>
These are 3 methods I render the svg. 2 work but the one I need does not:
<!-- Does NOT include gradient style -->
<svg width="100" height="100">
<use href="12.svg#pb_svg_1" width="100" height="100"/>
</svg>
<!-- Gradient style works! -->
<div>
<object data="12.svg" width="100" height="100"></object>
</div>
<!-- Gradient style works! -->
<div style="width: 100px;height: 100px">
<embed src="12.svg"/>
</div>
I expect the use element to render the file as it does when the svg is on the same page.
EDIT: It does work in firefox and does not work in chrome and edge
CodePudding user response:
Workaround: define gadients in an inlined svg
Move the gradient <defs>
to an inlined hidden <svg>
.
It's important to hide this svg via zero width and height properties like width:0; height:0;position:absolute;
.
display:none
or visibility:hidden
will remove/disable gradients, clip paths etc.
<!-- HTML svg use instance -->
<svg width="100" height="100" viewBox="0 0 100 100">
<use href="#pb_svg_1" style="fill: url(#lg1); stroke:#000000;stroke-width:2 "/>
</svg>
<!-- Inline svg: hidden gradient definition -->
<svg style="width:0; height:0; position:absolute;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
<defs>
<linearGradient id="lg1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:rgb(88,88,88);stop-opacity:1"/>
<stop offset="100%" style="stop-color:rgb(255,255,255);stop-opacity:1"/>
</linearGradient>
</defs>
</svg>
<!-- External svg: 12.svg -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol id="pb_svg_1" viewBox="0 0 100 100">
<rect x="0" y="0" width="50" height="50" /></symbol>
</svg>
Workaround 2: inline external use references
If refactoring all svg assets isn't feasible – change your embedding method.
2.1 via fetch
HTML
<!-- HTML svg use instance -->
<svg width="100" height="100" viewBox="0 0 100 100">
<use href="12.svg#pb_svg_1" />
</svg>
Js
inlineExternalUse();
function inlineExternalUse(){
let extSvgs = document.querySelectorAll('use');
if(extSvgs.length){
extSvgs.forEach(function(item, i){
let href = item.getAttribute('href') ? item.getAttribute('href') : item.getAttribute('xlink:href');
// change href to inline reference
let hrefNew = '#' href.split('#')[1];
item.setAttribute('href', hrefNew);
fetch(href)
.then(response => response.text() )
.then(data => {
//inline ext svg
let parser = new DOMParser();
let svgInline = parser.parseFromString(data, "application/xml").querySelector('svg');
svgInline.setAttribute('aria-hidden', 'true')
svgInline.style.width=0;
svgInline.style.height=0;
svgInline.style.position='absolute';
document.body.appendChild(svgInline);
});
});
}
}
2.2: via native web component
See @Danny '365CSI' Engelman's article "〈load-file〉Web Component, add external content to the DOM" or this answer "How to change the color of an svg element?"