2

This is different from Using SVG for additive color mixing (additive blending), which is talking specifically about additive blending. For that it's as easy as setting mix-blend-mode: screen. As far as I'm aware, there is no mix-blend-mode to average colors. The answer to this probably does involve using Filters, as mentioned in an answer there; but how is the question?

I'm making an app where you view some SVG data. The SVG has layers that are different colors which contain various shapes/paths. The colors of the layers and the shapes/paths are input and vary.

An example SVG might look like:

<svg>
  <g fill="#ff0000" id="layer1">
    <path d="M0,50 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <g fill="#00ff00" id="layer2">
    <path d="M25,50 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <g fill="#0000ff" id="layer3">
    <path d="M12.5,75 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <!-- more layers... -->
</svg>

Which would look like the first set of circles in the picture below (Normal).

What I want is to be able to toggle a 'transparent mode', so you can see the shapes that are hidden underneath other shapes. So if two shapes overlap in an area, the color of that area should be the average of the two layer colors. And if there is just one shape not overlapping anything, the color should be just the color of the layer. By average I mean if there is a color "#ff0000" on top of color "#00ff00", the resulting color should be "#7f7f00".

I can get a weak transparency effect (middle picture) by drawing everything twice: draw everything once at full opacity, then draw it again on top at half opacity. But the effect is very weak and not really showing the true 'mix' of the colors.

This picture hopefully explains the effect I want (the set on the right):

Example

I don't mind using something hacky to achieve this as long as the end result looks right.

user3044553
  • 147
  • 2
  • 8

2 Answers2

4

If you are up to hacky things you can pair two mix-blend-mode exclusion & multiply

path {
  mix-blend-mode: exclusion;
}

.multiply path {
  opacity: 0.5;
  mix-blend-mode: multiply;
}
<svg>
  <g fill="#ff0000" id="layer1">
    <path d="M0,50 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <g fill="#00ff00" id="layer2">
    <path d="M25,50 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <g fill="#0000ff" id="layer3">
    <path d="M12.5,75 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
<g class="multiply">
  <g fill="#ff0000">
    <path d="M0,50 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <g fill="#00ff00">
    <path d="M25,50 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <g fill="#0000ff">
    <path d="M12.5,75 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
</g>
</svg>
Charles Lavalard
  • 2,061
  • 6
  • 26
  • Thank you Charles! This snippet works in my browser and looks like it should! I'm having some trouble getting this solution to work though. When I copy the SVG and CSS you posted into an HTML document, it appears miscolored. This jsfiddle, with the same code, also looks miscolored: https://jsfiddle.net/hwuke2mc/ I'm not sure why it's working in the snippet but not elsewhere? Also, would you mind explaining a little about why this works? – user3044553 May 18 '21 at 19:43
  • Interestingly, it does work on codepen: https://codepen.io/joesalerno/pen/ExWNaOm . However I still can't get it to work with files on my computer. I've tried putting the CSS in an external file, as well as inlining it, but it seems to want to look like it does in that jsfiddle link I posted. I'm not sure what's going on. – user3044553 May 18 '21 at 20:29
  • Actually it works in all cases in Firefox. But in Edge, it only works in the snippet and in codepen. Any ideas how to get it working for Edge? And what is going on here in general? Thank you for the help! For reference, this is what this solution looks like in Edge for me: https://imgur.com/RYsYyCI – user3044553 May 18 '21 at 20:45
  • The snippet seems to work fine for me in Edge. Version 90.0.818.62 (Official build) (64-bit) on Win 10. – Paul LeBeau May 19 '21 at 11:01
  • I can confirm it works for me too on newer edge versions. It seems on older ones, mix-blend-mode:exclusion works differently with blank backgrounds. There may be some other differences between versions. I'm still curious why it works in codepen and on stackoverflow snippets in all cases, though. This solution seems like magic to me. It would be nice to understand how it works! But it does work. – user3044553 May 20 '21 at 14:25
0

It is not the perfect result. But you could have a progressive opacity.

#layer1 {
 opacity: 1
}

#layer2 {
 opacity: .7
}

#layer3 {
 opacity: .5
}
<svg>
  <g fill="#ff0000" id="layer1">
    <path d="M0,50 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <g fill="#00ff00" id="layer2">
    <path d="M25,50 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <g fill="#0000ff" id="layer3">
    <path d="M12.5,75 a50 50 0 1 1 100,0 a50 50 0 1 1 -100,0"/>
  </g>
  <!-- more layers... -->
</svg>
crg
  • 4,284
  • 2
  • 29
  • 57