Search code examples
htmlcsscss-shapes

Mask an area of an element to see and interact with area beneath


Is it possible to dynamically cut out an area of an HTML div and see and interact with the HTML beneath it?

For example, say I have a div of mixed HTML content of 500x500 centered on top of other HTML content. Now I want to punch a round hole through the top content so I can see and interact with the content beneath it. Is it possible?

I think they call it masking or knock out.


Solution

  • If you need to interact with the portion beneath (through the cut-out area) then using clip-path would be the correct option in my opinion. Masks show the portion beneath but they accomplish it by making the cut-out area of the top element as transparent. So when there is any sort of interaction (even in the cut-out area) it is essentially happening on the top element only. When using clip-path the area that is cut-out is totally blank and the top element has nothing in there. So when that portion is hovered on, the interaction there is directly on the bottom element.

    Clip-path Demo: (when the cut out area is hovered, the background of bottom element changes)

    .example {
      position: relative;
      height: 200px;
      width: 200px;
      margin: 10px;
    }
    .example div {
      position: absolute;
      height: 100%;
      width: 100%;
    }
    .bottom-layer {
      background: beige;
    }
    .bottom-layer:hover {
      background: chocolate;
    }
    .top-layer {
      background: tomato;
    }
    .top-layer:hover {
      background: hotpink;
    }
    #example1 .top-layer {
      clip-path: url(#circle);
    }
    #example2 .top-layer {
      clip-path: url(#pentagon);
    }
    <div class='example' id='example1'>
      <div class='bottom-layer'>Some content</div>
      <div class='top-layer'>Top content</div>
    </div>
    <div class='example' id='example2'>
      <div class='bottom-layer'>Some content</div>
      <div class='top-layer'>Top content</div>
    </div>
    
    <!-- the clip-path definition -->
    
    <svg height="0" width="0">
      <defs>
        <clipPath id='pentagon' clipPathUnits='objectBoundingBox'>
          <path d='M0.25,0.25 0.75,0.25 0.75,0.5 0.5,0.75 0.25,0.5 0.25,0 0,0 0,1 1,1 1,0 0.25,0z' />
        </clipPath>
        <clipPath id='circle' clipPathUnits='objectBoundingBox'>
          <path d='M0.25,0.5 A0.25,0.25 0 1,1 0.75,0.5 L1,0.5 1,0 0,0 0,0.5 0.25,0.5 
                   M0.75,0.5 A0.25,0.25 0 1,1 0.25,0.5 L0,0.5 0,1 1,1 1,0.5 0.75,0.5' />
        </clipPath>
      </defs>
    </svg>

    Sample Mask: (hovering on the cut out area has no impact on the bottom element)

    .example {
      position: relative;
      height: 200px;
      width: 200px;
      margin: 10px;
    }
    .example div {
      position: absolute;
      height: 100%;
      width: 100%;
    }
    .bottom-layer {
      background: beige;
    }
    .bottom-layer:hover {
      background: chocolate;
    }
    .top-layer {
      background: tomato;
    }
    .top-layer:hover {
      background: hotpink;
    }
    #example1 .top-layer {
      -webkit-mask-image: radial-gradient(circle farthest-side at 50% 50%, transparent 50%, white 50%);
    }
    #example2 .top-layer {
      -webkit-mask-image: linear-gradient(to top left, white 50%, transparent 50%);
    }
    <div class='example' id='example1'>
      <div class='bottom-layer'>Some content</div>
      <div class='top-layer'>Top content</div>
    </div>
    <div class='example' id='example2'>
      <div class='bottom-layer'>Some content</div>
      <div class='top-layer'>Top content</div>
    </div>