Open jebarjonet opened 6 years ago
Hi,
I'm not sto much into SVG icons and javascript.
I've found this workaround on SO: https://jsfiddle.net/tagliala/f019sa7v/2/
Ref: #https://stackoverflow.com/questions/10894377/dynamically-adding-a-svg-gradient
Maybe it is possible to add a feature to use icons as clippath or add extra properties to the generated svg
@tagliala the jsfiddle example is not working on my end (MacOS / Chrome v63) but I believe that SVG gradients definitions with Javascript are a real pain. Even if I could pass a <LinearGradient>
inside the <svg>
and reference it in the <path>
I would still have to generate it with React which I prefer to avoid :)
The cleanest -and pure CSS- way would be that I could use FA web font instead of SVG icons
I just spelled out a static solution on SO: https://stackoverflow.com/a/47801536/4996779
@ccprog Thanks, your solution works like a charm. Still, it would have been awesome if this was a part of FA's API.
Note that this is not running with React in this demo 🙂
My solution was to use the Font version of FA 5 (instead of the SVG version) so I could use CSS gradients on it instead of using react-fontawesome
@jebarjonet maybe I got you wrong(?!), but I'm using @ccprog's solution in react
@CanRau yep, but I really wanted to generate gradients on the fly as simply as a css line
@jebarjonet would definitely be preferable 👍
Having a hard time with @ccprog's solution using Vue and with webpack. I managed to get webpack to inline the svg in the url()
but the gradient never displayed. Not sure what I'm doing wrong.
@r-tanner-f have you tried to preserve the reference instead of inlining it in the css like in ccprog's answer? i don't know but it might not work like this.. so you have the svg in you html, hidden with css and the css just references the id of the svg gradient
For anyone still trying to achieve this effect with Font Awesome (5.0.13 as of this comment) working with JS and SVG, @ccprog 's solution above worked for me.
I had several icons that I wanted to apply a gradient to; I didn't care about hover, I just wanted it on there.
Here are the steps I followed to achieve this effect:
<svg width="0" height="0">
<linearGradient id="lgrad" x1="100%" y1="100%" x2="0%" y2="0%" >
<stop offset="0%" style="stop-color:rgb(252,207,49);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(245,85,85);stop-opacity:1" />
</linearGradient>
</svg>
<i>
tags are replaced with inline-svg.
.parent-div svg * {
fill: url(#lgrad);
}
Done!
See this JSFiddle for an example.
Thanks, @stavvie34 .This will get you into troubles inside of a loop because you can't use the same id for multiple elements. You can't use v-bind:style here because we need to have the same id in both CSS and SVG. Here an example of what I could do hoping it will help someone. Source
<template>
<!-- ... -->
<Fa :icon="[ 'fab', child.icon ]" />
<svg width="0" height="0">
<linearGradient :id="'lgrad' + child.id" x1="100%" y1="100%" x2="0%" y2="0%">
<stop ... />
<stop ... />
</linearGradient>
</svg>
<!-- ... -->
</template>
<script>
export default {
// Our prop
// child: {
// id: 4,
// icon: 'js',
// },
mounted() {
let style = document.createElement('style');
style.type = "text/css";
style.appendChild(document.createTextNode(''));
this.styleNode = style.childNodes[0];
document.head.appendChild(style);
// The magic
let css = '.fa-' + this.lang.icon + ' * {fill: url(#lgrad' + this.child.id + ');}';
this.styleNode.textContent = css;
},
props: {
child: Object,
},
}
</script>
I guess it can also be done using CSS variable but I could't find a way to get the prop inside the style
scope.
@stavvie34 Amazing thanks! You saved me <3
Have you considered using a mask to accomplish this? Here's a quick codepen demoing what I;m thinking.
Have you considered using a mask to accomplish this? Here's a quick codepen demoing what I;m thinking.
Thank You!
Have you considered using a mask to accomplish this? Here's a quick codepen demoing what I;m thinking.
In case it helps anyone (it took me a while to find) to get this working in angular-fontawesome you need to add a custom class: https://github.com/FortAwesome/angular-fontawesome/issues/173#issuecomment-529375797
I don't like these solutions because I am working with <FontAwesomeIcon />
React component and I don't want to work with custom svg tags and components...
I found a workaround for MY problem :
To achieve that, I am using FontAwesome layers & mask :
<span className="fa-layers fa-fw">
<FontAwesomeIcon
className="gradient"
icon="circle"
mask="square-full"
color="white"
/>
<FontAwesomeIcon
icon="check"
inverse
transform="shrink-6"
/>
</span>
.gradient {
background: linear-gradient(
180deg,
rgba(94, 189, 62, 1) 34%,
rgba(255, 185, 0, 1),
rgba(247, 130, 0, 1),
rgba(226, 56, 56, 1),
rgba(151, 57, 153, 1),
rgba(0, 156, 223, 1) 91%
);
}
Here is a live demo : https://codepen.io/SylvainDNS/pen/ZEpXEEZ
Hi guys, when using vh
or vw
units, the solution described above often leads to display errors in the browser. After hours of despair I solved it ugly with the following code:
const iconRef = useRef < HTMLDivElement | null > (null);
useEffect(() => {
const svg = iconRef.current!.querySelector('svg');
if (svg) {
const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
const linearGradient = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient');
linearGradient.setAttribute('id', 'pride');
linearGradient.setAttribute('x1', '0%');
linearGradient.setAttribute('y1', '0%');
linearGradient.setAttribute('x2', '0%');
linearGradient.setAttribute('y2', '100%');
const stops = [
{
offset: '0%',
color: '#ff0018'
},
{
offset: '16.7%',
color: '#ff0018'
},
{
offset: '16.7%',
color: '#ff8c00'
},
{
offset: '33.3%',
color: '#ff8c00'
},
{
offset: '33.3%',
color: '#ffed00'
},
{
offset: '50%',
color: '#ffed00'
},
{
offset: '50%',
color: '#008026'
},
{
offset: '66.7%',
color: '#008026'
},
{
offset: '66.7%',
color: '#0000f9'
},
{
offset: '83.3%',
color: '#0000f9'
},
{
offset: '83.3%',
color: '#a700ff'
},
{
offset: '100%',
color: '#a700ff'
}
];
stops.forEach(({
offset,
color
}) => {
const stop = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
stop.setAttribute('offset', offset);
stop.setAttribute('stop-color', color);
linearGradient.appendChild(stop);
});
defs.appendChild(linearGradient);
svg.prepend(defs);
const path = svg.querySelector('path');
if (path) {
path.setAttribute('fill', 'url(#pride)');
}
}
}, []);
return (
<span ref={ iconRef } >
<FontAwesomeIcon icon={ faHeart } />
</span>
);
Result:
I liked the fact that FA < v4 was a font so that I could apply a CSS gradient on it (ex: http://jsfiddle.net/HGxMu/220/)
I am currently using
react-fontawesome
which outputs SVG icons, on which I can not apply CSS gradients. Is there a way to either: