Search code examples
htmlcssfont-awesome-5

How can I transition this font awesome (v5.0) color from white to my custom color?


I am just working on a beginner project, and when I hover over the Instagram Icon, I would like it to slowly transition to the gradient of colors from some svg code I copied off of StackOverflow. I understand how the SVG code works (generally), but cannot figure out how to make the transitions work.

Here's a snippet of necessary code, along with the css that I've tried so far.

I believe the end transition value for fill is what is causing the issue. If I change it to a different value, like "blue", or "red", the transition works fine.

.social-container {
	position: absolute;
	bottom: 0;
	color: white;
	border: 1px solid white;
	display: flex;
	width: 150px;
	height: 35px;
	justify-content: space-between;
	align-items: center;
}


svg {
	transition: fill 3s ease;
}

.instagram-logo svg * {
  transition: all 2s ease;
	fill: black;
}

.instagram-logo:hover svg * {
	fill: url(#rg);
}

/* So I noticed the issue is the .instagram-logo:hover svg * {}. When I use a solid color like "blue" for the fill value, the transition works flawlessly. But when using the url, it doesn't work at all */
<script src="https://use.fontawesome.com/releases/v5.0.8/js/all.js"></script>

<div class="instagram-logo">
  <svg width="0" height="0">
    <radialGradient id="rg" r="150%" cx="30%" cy="107%">
      <stop stop-color="#fdf497" offset="0" />
      <stop stop-color="#fdf497" offset="0.05" />
      <stop stop-color="#fd5949" offset="0.45" />
      <stop stop-color="#d6249f" offset="0.6" />
      <stop stop-color="#285AEB" offset="0.9" />
    </radialGradient>
  </svg>
  <i class="fab fa-instagram fa-2x"></i>
</div>


Solution

  • Browsers started to support CSS transition of <color> values, so they do accept to make the transition between your CSS fill: <color> to an other fill: <color>.

    But, when you are setting this CSS fill value to the gradient, for the engine, it's now an <urlFunc> value, which eventually resolves to an <image> value*. So transitioning from a <color> to this new value is not possible.

    *Though I'm not sure about this assertion...


    One solution though would be to animate a CSS <filter> value:

    .instagram-logo{
      padding: 2px 8px;
    }
    .instagram-logo svg.fa-instagram path{
      fill: url(#rg);
    }
    
    /* from black to color */
    .instagram-logo svg.fa-instagram{
      filter: brightness(0%) grayscale(100%);
      transition: filter 2s ease, -webkit-filter 2s ease;
    }
    .instagram-logo svg.fa-instagram:hover{
      filter: brightness(100%) grayscale(0%);
    }
    
    /* from white to color */
    .instagram-logo.white{
      background: black;
    }
    .instagram-logo.white svg.fa-instagram{
      filter: brightness(0%) grayscale(100%) invert(1);
    }
    .instagram-logo.white svg.fa-instagram:hover{
      /*
        we need to make a new declaration
        because transitions can only be done on func values 
        so we need the same <filterFunc> at both hands of the transition
     */
      filter: brightness(100%) grayscale(0%) invert(0);
    }
    <script src="https://use.fontawesome.com/releases/v5.0.8/js/all.js"></script>
    
    <div class="instagram-logo">
      <svg class="hidden" width="0" height="0" style="position:absolute; z-index:-1">
        <radialGradient id="rg" r="150%" cx="30%" cy="107%">
          <stop stop-color="#fdf497" offset="0" />
          <stop stop-color="#fdf497" offset="0.05" />
          <stop stop-color="#fd5949" offset="0.45" />
          <stop stop-color="#d6249f" offset="0.6" />
          <stop stop-color="#285AEB" offset="0.9" />
        </radialGradient>
      </svg>
      <i class="fab fa-instagram fa-2x"></i>
    
    </div>
    <div class="instagram-logo white">
      <i class="fab fa-instagram fa-2x"></i>
    </div>

    Note that in given example, I set the filter on the parent <svg> node, because chrome doesn't seem to support CSS filtering on inner SVG nodes without prefix yet.