Search code examples
svgretina-displaysvg-filters

SVG element pixelated on retina only if filters applied


An SVG path element becomes unexpectedly pixelated on retina screens if I apply a filter to it. Without the filter, it looks nice and smooth.

An image showing two curves. The top one, labeled "without filters", is smooth. The bottom one, labeled "with filters", is noticeably pixelated

I'm using a gaussian blur and a color matrix:

<filter id="svg-filter-rounded-corners" x="-50%" y="-50%" width="200%" height="200%">
  <feGaussianBlur stdDeviation="3" />
  <feColorMatrix mode="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 -25" />
</filter>

Here's a reproducible example. The circle on the left has the filter, the circle on the right does not.

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="200" viewBox="0 0 400 200">
  <defs>
    <filter id="filter" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur stdDeviation="3" />
      <feColorMatrix mode="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 -25" />
    </filter>
  </defs>
  <circle filter="url(#filter)" cx="100" cy="100" r="90" fill="none" stroke="#221C35" stroke-width="10" />
  <circle cx="300" cy="100" r="90" fill="none" stroke="#221C35" stroke-width="10" />
</svg>

This is occurring in both Chrome and Firefox, on MacOS.

Is there anything I can do to keep the path smooth even with the filters applied?


Solution

  • This is crispy even on Chrome/Windows. And the issue is that the values you're using for your feColorMatrix are too large. It's nuking the anti-aliasing completely. Try:

    <feColorMatrix mode="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 -4" />
    

    Which gives a more reasonable result. If you don't like that result, you could try a more detailed manipulation of opacity using feComponentTransfer instead of the feColorMatrix.

    <feComponentTransfer>
     <feFuncA type="table" tableValues = "0 0 0 0 0.5 1 1 1 1 1 1 1 1 1 1 1"/>
    </feComponentTransfer>