1

I have an app where I need to 'highlight' two separate rectangular areas by covering everything else with a half-transparent backdrop.

After some research I though that css clipping/masking could be used here. But seems those are solving the inverse problem (i.e. showing parts covered with mask while hiding the rest). What I need - is to somehow subtract 2 separate regions from the backdrop div element. Kinda clip out.

The following image shows approximately what I'm trying to achieve: enter image description here

p.s.

I guess that can also be achieved by having multiple rectangles within a masking svg that would form that kind of outer backdrop shape. But before this - I'm wondering maybe there's a better way. Cuz this solution would involve some serious thinking :)

enter image description here

Edit:

Right, I tried out the suggested solution (the one that mine was considered a duplicate of). It didn't work for my case where I needed all this to happen dynamically and be cross-browser. As I found, mask-composite has a very limited support. In case someone is interested I found a better solution for my use-case that supports dynamic rects and has a better cross-browser support.

  • I disagree with the decision to close this question. I believe that the solution I found and would like to share is better for that specific scenario. And also has a better browser support. – Daniil Andreyevich Baunov Jul 29 '20 at 17:48

1 Answers1

0

After some more research on masks I found a pretty neat and easy way to implement this. The benefit of this approach is that you can simply manipulate svg properties to change positions of highlighted rects and/or add/remove as many rects as you want. It also has a good browser support since it uses inline svg mask.

So, idea here is that a mask in its default mode basically hides masked object where pixels of the mask are black and reveals where those are white (similar to Photoshop masks). Everything in between is half-transparent.

Here my goal was to show all the backdrop except for 2 (or more) areas. This was achieved by following steps:

  1. Create a rect inside the mask that would cover all the backdrop
  2. Make it white (reveals all the backdrop)
  3. Add 2 (or more) rects under it in the dom (above in display list)
  4. Make them black (those areas are subtracted from backdrop)

.highlighter-backdrop {
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  position: fixed;
  z-index: 10000;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease-in-out;
}

.highlighter-backdrop .backdrop-rect {
    width: 100vw;
    height: 100vh;
    fill: rgba(0, 0, 0, 0.55);
}

.highlighter-backdrop.active {
  opacity: 1;
}
<svg id="backdrop" class="highlighter-backdrop active"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <defs>
        <mask id="highlighterBackdropMask">
            <rect fill="white" height="100%" width="100%" x="0" y="0"></rect>
            <rect x="150" y="150" width="50" height="50" fill="black" />
            <rect x="400" y="250" width="100" height="100" fill="black" />
        </mask>
    </defs>
    <rect class="backdrop-rect" x="0" y="0" mask="url(#highlighterBackdropMask)"></rect>
</svg>