Sunday, January 12, 2014

SVG Element Transparencies

I solved a really interesting problem the other day that eluded me previously.  I hope this will help someone in the future so they don't make my mistake.

Let's say you have an SVG tag with multiple transparent shapes in it.  The way you set a shape's transparency is by adding fill-opacity style to the element.  

<svg height="50" width="100">
<line x1="0" y1="20" x2="100" y2="20" stroke="black"></line>
<circle cx="50" cy="25" r="10" fill="red" fill-opacity="0.5"></circle>
</svg>

The problem with adding the fill-opacity to multiple overlapping elements is that their fills blend together and sometimes this ruins the purpose of your image. If you draw one element over another, it is hard to say which color is on top of another color.


<svg height="50" width="100">
<line x1="0" y1="20" x2="100" y2="20" stroke="black"></line>
<circle cx="50" cy="25" r="10" fill="red" fill-opacity="0.5"></circle>
<circle cx="55" cy="25" r="10" fill="yellow" fill-opacity="0.5"></circle>
<circle cx="60" cy="25" r="10" fill="blue" fill-opacity="0.5"></circle>
<circle cx="65" cy="25" r="10" fill="green" fill-opacity="0.5"></circle>
</svg>
In the end, what I really wanted was to group all these elements and then apply the opacity to the parent element. This made each individual color stand out, yet the overall shapes were transparent so you could see a background behind it.

<svg height="50" width="100">
<line x1="0" y1="20" x2="100" y2="20" stroke="black"></line>
<g style="opacity: 0.5">
  <circle cx="50" cy="25" r="10" fill="red"></circle>
  <circle cx="55" cy="25" r="10" fill="yellow"></circle>
  <circle cx="60" cy="25" r="10" fill="blue"></circle>
  <circle cx="65" cy="25" r="10" fill="green"></circle>
</g>
</svg>
Why would you want to use one strategy versus the other? If you want the colors to appear distinct but transparent, you group together a bunch of elements and add a transparency to their parent group. But if you want the colors to blend, then you should add the opacities individually.
By the way, this problem isn't really an SVG problem. You see the same results in plain old html. :-D