3

I have this card layout Codepen card layout <div></div> in which I would like to create a "hole punch effect". Where the card is missing semi-circle bits from either side, and the blurred background shows through in the background.

hole punched effect

I have tried using pseudo elements on the card element itself and making it inherit the background to give the illusion of negative space. As well as using clip-path, but that seems to do the inverse operation of what I want. I want to keep most of the card, and just erase a portion of it. Not sure what to call this or how to search for it, any and all suggestions are much appreciated!

Akin Hwan
  • 607
  • 1
  • 9
  • 26
  • Possible duplicate of [Clip path inset circle?](https://stackoverflow.com/questions/37000558/clip-path-inset-circle) – Temani Afif Jan 15 '18 at 18:49

4 Answers4

4

you can use clip-path for custom paths if it fits your needs.

here is an example:

.clip {
  width: 300px;
  height: 160px;
  background-color: red;
  clip-path: polygon(0% 0%, 100% 0%, 100% 40%, 99% 41%, 98% 42%, 97% 44%, 96% 48%, 96% 50%, 96% 52%, 97% 56%, 98% 58%, 99% 59%, 100% 60%, 100% 100%, 0% 100%, 0% 60%, 1% 59%, 2% 58%, 3% 56%, 4% 52%, 4% 50%, 4% 48%, 3% 44%, 2% 42%, 1% 41%, 0% 40%);
}
<div class="clip"></div>

look at this polygon for your responsive question:

.clip {
  width: 300px;
  height: 160px;
  background-color: red;
  clip-path: polygon(0% 0%, 100% 0%, 100% calc(50% - 18px), calc(100% - 5px) calc(50% - 15px), calc(100% - 8px) calc(50% - 12px), calc(100% - 9px) calc(50% - 9px), calc(100% - 10px) calc(50% - 7px), calc(100% - 11px) 50%, calc(100% - 10px) calc(50% + 7px), calc(100% - 9px) calc(50% + 9px), calc(100% - 8px) calc(50% + 12px), calc(100% - 5px) calc(50% + 15px), 100% calc(50% + 18px), 100% 100%, 0% 100%, 0% calc(50% + 18px), 5px calc(50% + 15px), 8px calc(50% + 12px), 9px calc(50% + 9px), 10px calc(50% + 7px), 11px 50%, 10px calc(50% - 7px), 9px calc(50% - 9px), 8px calc(50% - 12px), 5px calc(50% - 15px), 0% calc(50% - 18px));
}
<div class="clip"></div>
Joel Stüdle
  • 337
  • 2
  • 11
  • oh wow, this is great thank you. But I am disappointed that there isn't a way to define what you want to "erase" from a div, and overlay that somehow. seems like there should be a subtractive method of doing clips/masks in CSS, oh well! – Akin Hwan Jan 15 '18 at 18:12
  • @AkinHwan glad to help. Unfortunately, I also don't know how to invert the clip-path. – Joel Stüdle Jan 15 '18 at 18:22
  • did you code this polygon by hand or use some tool to help you in visualizing the different points? The only problem with this is it is not so responsive/flexible. – Akin Hwan Jan 15 '18 at 20:31
  • I did it by hand. I tried to find a tool to do this, but I was not successful. It should be responsive because every point is based on a percentual value. if you change the dimension of `.clip` the polygon will fit this dimensions. – Joel Stüdle Jan 15 '18 at 23:40
2
.target {
  clip-path: url(resources.svg#c1);
}

I think you are on the right track, try using a SVG to define the clipping region. https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path

Steven Tang
  • 954
  • 1
  • 7
  • 21
2

it's a little late, but i'd like to share this solution with you:

.shape {
  width: 275px;
  height: 300px;
  position: relative;
  background-color: transparent;
}

.shape-left, .shape-right {
  width: 50%;
  height: 100%;
  position: absolute;
  overflow: hidden;
}

.circle {
    position: absolute;
    box-sizing: content-box;
    width: 50px;
    height: 50px;
    border-radius: 100%;
    border: 100vh solid white;
    top: 50%;
}

.shape-left {
  left: 0;
}

.shape-left .circle {
  left: 0;
  transform: translate(-50%, -50%);
}
  
.shape-right {
  right: 0;
}

.shape-right .circle {
  right: 0;
  transform: translate(50%, -50%);
}

body {
  background-image: url(https://images.pexels.com/photos/2318554/pexels-photo-2318554.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940);
  background-size: cover;
  background-position: 50% 50%;
}
<div class="shape">
  <div class="shape-left"><div class="circle"></div></div>
  <div class="shape-right"><div class="circle"></div></div>
</div>

so basically what i did is the following:

  1. create the rectangle without background
  2. create a 'left' and a 'right' child element without background and hidden overflow both filling one half of your rectangle
  3. give both children an element without background
  4. style the element as a circle
  5. align the circles inside the 'left' and 'right' element to the position you like the rectangle being 'clipped'
  6. give the circles an oversized border (so it fills out the whole parent element) and a border color of your choice

tada ** if it is hard to understand, change the size of the border on the .circle element. this will help to understand.

Joel Stüdle
  • 337
  • 2
  • 11
0

I have figured out something that works closer to what I desired. I adapted the example from this link html5rocks mask tutorial

-webkit-mask-box-image: url("stamp.svg") stretch; 
mask-border: url("stamp.svg") stretch;

My stamp looks different, and note how I use stretch so that it doesn't repeat. Just keep in mind that the area you want to be see-through must be a "None" Path and the part of your original html element you want visible can just be black.

My custom stamp made with Illustrator

Akin Hwan
  • 607
  • 1
  • 9
  • 26