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.
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?
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;
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.
Related
I have a button with svg inside like:
<button>
Checkout
<ArrowSvg />
</button>
And ArrowSvg looks like this (line has class: svg-line):
<svg fill="none" stroke="#000">
<defs>
<marker id="m" overflow="visible">
<path d="M-4,-4L0,0 -4,4" />
</marker>
</defs>
<line x1="0" y1="50%" x2="100%" y2="50%"marker-end="url(#m)" class="svg-line" />
</svg>
When button is hovered, I change the stroke color:
btn:hover > .svg-line {
stroke: blue;
}
It's working well - when I hover the button, the arrow (line and arrow head) turns blue.
But when I display the multiple buttons (more than 1), hovering 1 button affects arrows in other buttons. The arrow head part (which is marker/path in svg?) of all the buttons get affected when hovering the first button.
I am also working with the arrow width, so I need line. I can't make everything with path because I won't be able to expand the arrow width.
Am I missing anything? Why am I seeing this issue?
Wrap it in a native JS Web Component, supported in all modern browsers, to create the <svg>
because every SVG requires a unique marker ID
note: the SVG is created for every instance, no need for a marker at all, use the path by itself
customElements.define("svg-button",class extends HTMLElement{
connectedCallback(){
let id = "id" + (Math.floor(Math.random() * 1e10));
let stroke = this.getAttribute("stroke") || "#000";
this.innerHTML = `
<button>
Checkout
<svg fill="none" stroke="${stroke}" viewBox="0 0 10 10">
<defs>
<marker id="${id}" overflow="visible">
<path d="M-4,-4L0,0 -4,4"/>
</marker>
</defs>
<line x1="0" y1="5" x2="9" y2="5" marker-end="url(#${id})"/>
</svg>
</button>`
}
});
<style>
button:hover svg {
stroke:gold;
}
</style>
<svg-button></svg-button>
<svg-button stroke="red"></svg-button>
<svg-button stroke="green"></svg-button>
<svg-button stroke="blue"></svg-button>
What you are writing looks like .JSX syntax, but the question is lacking a react tag. I will assume it for this answer anyway, but other frameworks using the format will probably work comparably.
All you need is a unique id for the <marker> element. This is easily done if you spell out the <ArrowSvg> as a function. Then, wrap it in a factory function to form a closure over a running number:
const ArrowSvg = (() => {
let id = 0;
return function (props) {
return (
const ref = 'arrowMarker' + ++id;
<svg fill="none" stroke="#000">
<defs>
<marker id=(ref) overflow="visible">
<path d="M-4,-4L0,0 -4,4" />
</marker>
</defs>
<line x1="0" y1="50%" x2="100%" y2="50%"
marker-end=(`url(#${ref})`) class="svg-line" />
</svg>
);
}
})();
I created an SVG logo and want to animate it inside a React component.
In my SVG I have 3 different gradients: green, orange, and red.
I noticed that when I'm trying to assign a gradient via className to another element it fills it with just a plain color.
Could you please help me to understand what I'm doing wrong here?
here is the code:
https://codesandbox.io/s/shy-moon-zs1ik5
You have a gradient with cx="1202.5" cy="249.5" and a radius of r="18.5". This falls in the center of the first rectangle but far away from the center of the second one. The fill of this one is the peripheric red from the gradient.
A possible solution would be using the same path with the <use> element for all the identical paths you have. Next you give the use the required class.
Please observe that I've putted the path in the defs. Also the path has an id neded for the xlink:href of the use element.
.red-light{fill: url(#red-gradient);}
<svg viewBox="700 230 200 200">
<defs>
<radialGradient id="red-gradient" cx="1202.5" cy="249.5" r="18.5" gradientUnits="userSpaceOnUse">
<stop offset="0.04" stop-color="#fff"></stop>
<stop offset="0.12" stop-color="#fef4f3"></stop>
<stop offset="0.28" stop-color="#fad8d4"></stop>
<stop offset="0.49" stop-color="#f4aba1"></stop>
<stop offset="0.74" stop-color="#eb6b5b"></stop>
<stop offset="1" stop-color="#e1230a"></stop>
</radialGradient>
<path id="indicator" d="M1216.65,268h-28.3a4.69,4.69,0,0,1-4.35-4.35v-28.3a4.69,4.69,0,0,1,4.35-4.35h28.3a4.69,4.69,0,0,1,4.35,4.35v28.3C1221,268,1218.78,268,1216.65,268Z"></path>
</defs>
<use xlink:href="#indicator" id="indicator-3" data-name="indicator-3" class="red-light" transform="translate(-420)" />
<use xlink:href="#indicator" id="indicator-10" data-name="indicator-10" class="red-light" transform="translate(-460,50)" />
</svg>
I have an svg image injected into a page using vue-svg-inline-loader.
<img
svg-inline
src="#/assets/vectors/silhouettes/body.svg"
:style="silhouetteStyle">
The svg contains a radialGradient that I modified to work with css variables as following
<defs>
<radialGradient
id="gradient"
gradientUnits="userSpaceOnUse"
cx="50%"
cy="27%"
r="var(--radius)">
<stop offset="0%" stop-color="var(--in-color)" />
<stop offset="100%" stop-color="var(--out-color)" />
</radialGradient>
</defs>
In vue I update the css variables to create a dynamic gradient
computed: {
silhouetteStyle() {
/* whatever the calculation of variables */
return `--radius:${radius}; --in-color:${inColor}; --out-color:${outColor}`;
},
},
Gradient colors are updated perfectly, but not the radius. I can't find any response out there about if it is even possible.
-EDIT-
Here is a codesandbox demo to illustrate the thing. As you can see colors are changed but not the radius
in the footer of my site I have social icons as SVGs that fill depending on screen size and hover state.
One example is for instagram:
HTML:
<a href="https://www.instagram.com/pacific_beach_homes/" title="Visit our Instagram page" target="blank" >
<svg class="instagram" alt="Instagram icon" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Instagram</title>
<defs>
<linearGradient id="ig-gradient">
<stop offset="0%" stop-color="#F8ED34" />
<stop offset="50%" stop-color="#EA118D" />
<stop offset="100%" stop-color="#2E368F" />
</linearGradient>
</defs>
<path d="M12 0C8.74 0 8.333.015 7.053.072 5.775.132 4.905.333 4.14.63c-.789.306-1.459.717-2.126 1.384S.935 3.35.63 4.14C.333 4.905.131 5.775.072 7.053.012 8.333 0 8.74 0 12s.015 3.667.072 4.947c.06 1.277.261 2.148.558 2.913.306.788.717 1.459 1.384 2.126.667.666 1.336 1.079 2.126 1.384.766.296 1.636.499 2.913.558C8.333 23.988 8.74 24 12 24s3.667-.015 4.947-.072c1.277-.06 2.148-.262 2.913-.558.788-.306 1.459-.718 2.126-1.384.666-.667 1.079-1.335 1.384-2.126.296-.765.499-1.636.558-2.913.06-1.28.072-1.687.072-4.947s-.015-3.667-.072-4.947c-.06-1.277-.262-2.149-.558-2.913-.306-.789-.718-1.459-1.384-2.126C21.319 1.347 20.651.935 19.86.63c-.765-.297-1.636-.499-2.913-.558C15.667.012 15.26 0 12 0zm0 2.16c3.203 0 3.585.016 4.85.071 1.17.055 1.805.249 2.227.415.562.217.96.477 1.382.896.419.42.679.819.896 1.381.164.422.36 1.057.413 2.227.057 1.266.07 1.646.07 4.85s-.015 3.585-.074 4.85c-.061 1.17-.256 1.805-.421 2.227-.224.562-.479.96-.899 1.382-.419.419-.824.679-1.38.896-.42.164-1.065.36-2.235.413-1.274.057-1.649.07-4.859.07-3.211 0-3.586-.015-4.859-.074-1.171-.061-1.816-.256-2.236-.421-.569-.224-.96-.479-1.379-.899-.421-.419-.69-.824-.9-1.38-.165-.42-.359-1.065-.42-2.235-.045-1.26-.061-1.649-.061-4.844 0-3.196.016-3.586.061-4.861.061-1.17.255-1.814.42-2.234.21-.57.479-.96.9-1.381.419-.419.81-.689 1.379-.898.42-.166 1.051-.361 2.221-.421 1.275-.045 1.65-.06 4.859-.06l.045.03zm0 3.678c-3.405 0-6.162 2.76-6.162 6.162 0 3.405 2.76 6.162 6.162 6.162 3.405 0 6.162-2.76 6.162-6.162 0-3.405-2.76-6.162-6.162-6.162zM12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4zm7.846-10.405c0 .795-.646 1.44-1.44 1.44-.795 0-1.44-.646-1.44-1.44 0-.794.646-1.439 1.44-1.439.793-.001 1.44.645 1.44 1.439z"/></svg>
</a>
CSS:
.instagram {
fill: #fe4164;
fill: url('#ig-gradient');
}
I included a backup color above the fill:url(...) because I thought this might fix it if Safari doesn't accept gradient fills. But that is not the problem. It seems that safari is actually changing the url from what is typed in the css file.
On most browsers, the fill: url(#ig-gradient); is working fine. However Safari for iOS is different. . .
Safari for iOS is changing the fill url to a full url link: url(https://pacificbeachhomes.com/wp-content/themes/pacificbeachhomes/#ig-gradient) which doesnt work, instead of url(#ig-gradient) which works. .. .
Anyone know why safari for iOS is adding the domain? I tried putting the fill url in quotes (shown above) and without quotes and it doesnt seem to change.
active site is: pacificbeachhomes.com
I can't manage to animate a smooth transition between two similar <path />'s
There's this background effect I try to manage in my React app, where you have some blobs floating around that need to deform over time. I've created two blob shapes and tried to animate them via svg <animate /> tag but it only shifts momentarily from one shape to another after set dur property.
I've tried a few libraries like "react-spring" or react-something-svg (there's quite a stack of them out there) but the best I got was to have a path only morph animation with no fill or gradient properties.
Two shapes to shift between:
<svg>
<defs>
<radialGradient id="radialGradient827" cx="105.22" cy="144.2" r="51.989" gradientTransform="matrix(.23275 1.7456 -.93805 .12507 214.81 -67.26)" gradientUnits="userSpaceOnUse">
<stop stop-color="#00f" offset="0"/>
<stop stop-color="#00f3ff" offset="1"/>
</radialGradient>
</defs>
<g transform="translate(-67.756 -51.842)">
<path id="blob" transform="matrix(1.3569 0 0 1.3569 -2.3105 -31.738)" d="m52.019 88.923c1.008-6.2604 4.104-12.132 8.5366-16.666s10.166-7.7395 16.293-9.3701c12.256-3.2613 25.688-0.11296 36.296 6.8373 10.608 6.9503 18.58 17.4 24.228 28.755 5.6488 11.355 9.1245 23.653 12.182 35.961 3.0568 12.306 5.7394 24.802 6.0332 37.479 0.29383 12.677-1.9195 25.642-8.1354 36.694-3.1079 5.5261-7.1991 10.523-12.159 14.473-4.9595 3.9497-10.796 6.8358-17 8.1437s-12.77 1.0114-18.756-1.0776c-5.9861-2.089-11.361-5.9944-15.007-11.181-3.1833-4.5287-5.0021-9.9148-5.8599-15.383-0.85782-5.4687-0.79005-11.042-0.45735-16.567 0.6654-11.051 2.3656-22.3-0.18511-33.073-2.7384-11.566-10.084-21.385-16.303-31.514-3.1096-5.0645-5.9863-10.317-7.8786-15.95-1.8923-5.6336-2.7725-11.692-1.8278-17.56z" fill="url(#radialGradient827)" stroke-width="0"/>
</g>
</svg>
<svg>
<defs>
<radialGradient id="radialGradient827" cx="105.22" cy="144.2" r="51.989" gradientTransform="matrix(.23275 1.7456 -.93805 .12507 214.81 -67.26)" gradientUnits="userSpaceOnUse">
<stop stop-color="#00f" offset="0"/>
<stop stop-color="#00f3ff" offset="1"/>
</radialGradient>
</defs>
<g transform="translate(-60.376 -63.391)">
<path id="blob" transform="matrix(1.3569 0 0 1.3569 -2.3105 -31.738)" d="m52.019 88.923c5.9206-9.9143 16.696-16.529 28.107-18.297 11.411-1.7677 23.305 1.0814 33.237 6.9726 9.9318 5.8912 17.964 14.688 23.862 24.615 5.898 9.9278 9.7369 20.973 12.329 32.226 2.527 10.969 3.9032 22.276 3.0655 33.502-0.83773 11.225-3.9548 22.389-9.9198 31.935-5.965 9.5462-14.884 17.395-25.477 21.204s-22.841 3.3361-32.693-2.1096c-5.4164-2.9941-10.001-7.3752-13.622-12.394-3.6211-5.019-6.3053-10.669-8.3576-16.508-4.1048-11.677-5.7091-24.058-8.4789-36.122-2.4949-10.866-5.9526-21.549-7.3169-32.614-1.3643-11.065-0.45314-22.838 5.2631-32.41z" fill="url(#radialGradient827)" stroke-width="0"/>
</g>
</svg>
Here's a sandbox to play around: click here
I want to understand how to morph between two svg paths with a slow transition and having my gradient applied without using some specialized react animation library and incorporate it into my React app.
All I can do for now is to morph between to unstyled shapes using quite a few libraries and to shift from one shape to another momentarily
You can make the blobs preserve their final shape after the animation by specifying the fill property of the <animation> tag:
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" viewBox="0 0 141 231" xmlns="http://www.w3.org/2000/svg" >
<radialGradient id="radialGradient827" cx="105.22" cy="144.2" r="51.989" gradientTransform="matrix(.23275 1.7456 -.93805 .12507 214.81 -67.26)" gradientUnits="userSpaceOnUse">
<stop stop-color="#00f" offset="0"/>
<stop stop-color="#00f3ff" offset="1"/>
</radialGradient>
<path id="blob" transform="translate(-60.376 -63.391) matrix(1.3569 0 0 1.3569 -2.3105 -31.738)" d="m52.019 88.923c5.9206-9.9143 16.696-16.529 28.107-18.297 11.411-1.7677 23.305 1.0814 33.237 6.9726 9.9318 5.8912 17.964 14.688 23.862 24.615 5.898 9.9278 9.7369 20.973 12.329 32.226 2.527 10.969 3.9032 22.276 3.0655 33.502-0.83773 11.225-3.9548 22.389-9.9198 31.935-5.965 9.5462-14.884 17.395-25.477 21.204s-22.841 3.3361-32.693-2.1096c-5.4164-2.9941-10.001-7.3752-13.622-12.394-3.6211-5.019-6.3053-10.669-8.3576-16.508-4.1048-11.677-5.7091-24.058-8.4789-36.122-2.4949-10.866-5.9526-21.549-7.3169-32.614-1.3643-11.065-0.45314-22.838 5.2631-32.41z" fill="url(#radialGradient827)" stroke-width="0">
<animate
attributeName="path"
to="m52.019 88.923c5.9206-9.9143 16.696-16.529 28.107-18.297 11.411-1.7677 23.305 1.0814 33.237 6.9726 9.9318 5.8912 17.964 14.688 23.862 24.615 5.898 9.9278 9.7369 20.973 12.329 32.226 2.527 10.969 3.9032 22.276 3.0655 33.502-0.83773 11.225-3.9548 22.389-9.9198 31.935-5.965 9.5462-14.884 17.395-25.477 21.204s-22.841 3.3361-32.693-2.1096c-5.4164-2.9941-10.001-7.3752-13.622-12.394-3.6211-5.019-6.3053-10.669-8.3576-16.508-4.1048-11.677-5.7091-24.058-8.4789-36.122-2.4949-10.866-5.9526-21.549-7.3169-32.614-1.3643-11.065-0.45314-22.838 5.2631-32.41z"
dur="1s"
fill="freeze" />
</path>
</svg>
NOTE: For the animation to work you need to ensure that both the initial and the final path have the same number of points, as detailed in here. Here's a great tool to make sure that the animation is possible.
On regards to your gradient, the browser should take care of that. You can simply apply it as you would on any other SVG file.
Avoiding JS libraries to deal with SVG animation is a great move, those tend to be bloated and messy. Stick to the official SVG specs whenever possible.