0

I have a VueJS project in which I use SVGs with a hardcoded color, I try to give these SVGs another color by looping over them using mask and rect tags. This works, but I see that the higher the icon index gets, the lighter the color of the icon becomes. What am i doing wrong?

Here is the codepen example;

https://codepen.io/Kesselfest/pen/xxEZyBb

And the HTML template;

<template>
    <div id="app">
        <div class="flex-container">
            <div v-for="icon in icons" :key="icon.name">
                <div class="iconTile"> <svg viewBox="0 0 36 36">
                        <mask :id="`${icon.name}-mask`">
                            <image :href="icon.location" x="0" y="0" width="100%" height="100%" />
                        </mask>
                        <rect x="0" y="0" width="100%" height="100%" :fill="icon.color"
                            :mask="`url(#${icon.name}-mask)`" />
                    </svg> </div>
            </div>
        </div>
    </div>
</template>

KargWare
  • 1,746
  • 3
  • 22
  • 35
  • Can you use a Prettier tool for sharing the html / css file? So the format is better for human reading? – KargWare Dec 04 '20 at 15:24
  • [`mask`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/mask) works off the alpha channel, so the more black color the svg has, the more faded it will appear. You can check this by changing the order of the icons array (the fading is not based on index). Relevant question/answers [here](https://stackoverflow.com/questions/22252472/how-to-change-the-color-of-an-svg-element) and [here](https://stackoverflow.com/questions/22252472/how-to-change-the-color-of-an-svg-element/53336754#53336754) – chazsolo Dec 04 '20 at 16:10
  • Thank you for the feedback, I have adjusted the html/css file. – Kesselfest Dec 07 '20 at 08:23

1 Answers1

3

As said in the comments, a mask is not the preferable way to change the color of an icon. A filter can do a much better job. This is how I would do it. Excuse me if I abandon the Vue syntax in fvor of showing the result, but I am sure you can port this back easily.

The filter first floods the filter region with the intended color, then clips its aparent area back to the outline of the icon with the Porter-Duff atop operator.

.flex-container {
  justify-content: space-around;
  display: flex;
  padding: 20px;
}

.iconTile {
  margin: 0;
  padding: 10px;
  width: 100px;
  height: 100px;
}
<div class="flex-container">
  <div class="iconTile">
    <svg viewBox="0 0 36 36">
      <filter
           id="checkmark-filter" >
        <feFlood
          flood-color="purple"
          result="color"
        />
        <feComposite
         operator="atop"
         in2="SourceGraphic"
         in="color"
        />
      </filter>
      <image
         href="https://upload.wikimedia.org/wikipedia/commons/thumb/1/13/Icons8_flat_checkmark.svg/768px-Icons8_flat_checkmark.svg.png"
         x="0"
         y="0"
         width="100%"
         height="100%"
         filter="url(#checkmark-filter)"
      />
    </svg>
  </div>
  <div class="iconTile">
    <svg viewBox="0 0 36 36">
      <filter
             id="pencil-filter" >
          <feFlood
            flood-color="green"
            result="color"
          />
          <feComposite
           operator="atop"
           in2="SourceGraphic"
           in="color"
          />
        </filter>
        <image
           href="https://upload.wikimedia.org/wikipedia/commons/5/57/Red_pencil.svg"
           x="0"
           y="0"
           width="100%"
           height="100%"
           filter="url(#pencil-filter)"
        />
      </svg>
  </div>
</div>
ccprog
  • 20,308
  • 4
  • 27
  • 44