Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gradients on FA v5 icons #11925

Open
jebarjonet opened this issue Dec 13, 2017 · 18 comments
Open

Gradients on FA v5 icons #11925

jebarjonet opened this issue Dec 13, 2017 · 18 comments

Comments

@jebarjonet
Copy link

jebarjonet commented Dec 13, 2017

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/)

screen shot 2017-12-13 at 09 49 36

.icon {
    font-size: 50px;
    background: -webkit-gradient(linear, left top, left bottom, from(#0c8), to(#333));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}

I am currently using react-fontawesome which outputs SVG icons, on which I can not apply CSS gradients. Is there a way to either:

  • Apply a CSS gradient on SVG icons? (using the React repo referenced above)
  • Force web font usage instead of SVG icons? (preferably using the React repo referenced above)
@tagliala
Copy link
Member

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

@jebarjonet
Copy link
Author

@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

@ccprog
Copy link

ccprog commented Dec 13, 2017

I just spelled out a static solution on SO: https://stackoverflow.com/a/47801536/4996779

@galtalmor
Copy link

@ccprog Thanks, your solution works like a charm.
Still, it would have been awesome if this was a part of FA's API.

@jebarjonet
Copy link
Author

jebarjonet commented Jan 18, 2018

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

@CanRau
Copy link

CanRau commented Mar 22, 2018

@jebarjonet maybe I got you wrong(?!), but I'm using @ccprog's solution in react

@jebarjonet
Copy link
Author

@CanRau yep, but I really wanted to generate gradients on the fly as simply as a css line

@CanRau
Copy link

CanRau commented Mar 22, 2018

@jebarjonet would definitely be preferable 👍

@r-tanner-f
Copy link

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.

@CanRau
Copy link

CanRau commented May 5, 2018

@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

@stavvie34
Copy link

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:

  1. I used Angry Tools's gradient generator to give me an svg I can define.
  2. Define an svg element in your html.
<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>
  1. In your stylesheet, reference the svg icons you would like to apply the gradient to. With Font Awesome 5.0.13, using js, your <i> tags are replaced with inline-svg.
.parent-div svg * {
  fill: url(#lgrad);
}

Done!

See this JSFiddle for an example.

@the94air
Copy link

the94air commented Jan 17, 2019

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.

@stychu
Copy link

stychu commented Apr 25, 2019

@stavvie34 Amazing thanks! You saved me <3

@seanreiser
Copy link

Have you considered using a mask to accomplish this? Here's a quick codepen demoing what I;m thinking.

https://codepen.io/seanreiser/pen/QWLaZZp

@NastyDogBreath
Copy link

Have you considered using a mask to accomplish this? Here's a quick codepen demoing what I;m thinking.

https://codepen.io/seanreiser/pen/QWLaZZp

Thank You!

@ghost
Copy link

ghost commented Aug 11, 2020

Have you considered using a mask to accomplish this? Here's a quick codepen demoing what I;m thinking.

https://codepen.io/seanreiser/pen/QWLaZZp

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:
FortAwesome/angular-fontawesome#173 (comment)

@sylvainDNS
Copy link

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 :
image

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

@temmiland
Copy link

temmiland commented Jun 22, 2024

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:
result

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests