Search code examples
htmlcsssvgmaskrect

Why does the colored SVG I recolor using a mask turns the color lighter than the chosen color?


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>


Solution

  • 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>