2

I am new to using the css property clip-path and have created a shape that almost fits the requirement I have.

I am looking to create the following shape however struggling to convert the squares I have to circles.

enter image description here

.ticket {
  background-color: blue;
  height: 100px;
  width: 200px;
  border-radius: 10px;
  box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%);
  clip-path: polygon(
  0 0,
  0% 42%,
  5% 42%,
  5% 58%,
  0 58%,
  0 100%,
  100% 100%,
  100% 58%,
  95% 58%,
  95% 42%,
  100% 42%,
  100% 0
  );
}
<div class="ticket"></div>

Is this possible using this property? If not, how could I achieve this using a SVG instead? Is it also possible to add a drop shadow to this clipped mask? As you can see in the snippet the shadow doesn't really work.

Charklewis
  • 4,427
  • 4
  • 31
  • 69
  • Don't you want to do the normal CSS way of adding circles through pseudo elements? – m4n0 May 04 '21 at 01:53
  • Is there a way to do that and have them make like a hole punch so that the background can be seen through the hole? – Charklewis May 04 '21 at 01:54
  • Suggestion would be that you create a SVG of the structure you want to clip and then use `clip-path: url(#id)` with the `svg` id. – m4n0 May 04 '21 at 02:04

3 Answers3

5

If it's only a solid coloration, background can do it:

.ticket {
  background:
    radial-gradient(20px at right, #0000 97%,blue) right,
    radial-gradient(20px at left , #0000 97%,blue) left;
  background-size: 51% 100%;
  background-repeat: no-repeat;
  height: 100px;
  width: 200px;
  border-radius: 10px;
  filter: drop-shadow(0 0.5rem 0.2rem rgb(0 0 0 / 50%));
}
<div class="ticket"></div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
3

It is possible to 'cut holes' using the mask-image property and radial-gradients.

This snippet uses your code but replacing the clip-path with circle radial-gradient masks. Obviously you can change the percentages depending on hole-size required.

body {
  background: cyan;
}

.ticket {
  background-color: blue;
  height: 100px;
  width: 200px;
  border-radius: 10px;
  box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%);
  --mask1: radial-gradient(circle at 0 50%, transparent 0, transparent 5%, black 5%, black 90%, transparent 90%, transparent);
  --mask2: radial-gradient(circle at 100% 50%, transparent 0, transparent 5%, black 5%, black 90%, transparent 90%, transparent);
  /* webkit needed for Chrome */
  -webkit-mask-image: var(--mask1), var(--mask2);
  mask-image: var(--mask1), var(--mask2);
}
<div class="ticket"></div>

(body has been given a background just to prove that holes have been cut rather than white circles drawn which is what would have happened with pseudo elements).

The box shadow is more problematic as it gets masked (or clipped as in the question's code). Box-shadow on element with -webkit-mask-image has ideas on putting a shadow on a containing element which has the mask image(s) as background images(s) but putting a shadow into the holes is still a problem. Perhaps just putting a slightly bigger container with gradient gray/transparent backgrounds would do enough, with the 'holes' varying transparent grays rather than just transparent. Seems hacky though.

A Haworth
  • 30,908
  • 4
  • 11
  • 14
  • This is exactly what I was looking for! I will keep experimenting with the shadow to see if I can get it to render correctly. Do you mind if I ask why you have the colour black in the mask? – Charklewis May 04 '21 at 04:36
  • I think any color in the mask would be OK, but I'm not an expert at this. It's just when you see SVg masks and the like they tend to be black and transparent. – A Haworth May 04 '21 at 04:57
  • On the shadow bit, you could put a drop shadow on the actual element and the mask/background on a before pseudo element - needs some playing around with the parameters though and I'm not sure it can ever be perfect. See also [link]https://codepen.io/thebabydino/pen/rbmeBY referenced by [link]https://css-tricks.com/using-box-shadows-and-clip-path-together/ – A Haworth May 04 '21 at 05:00
  • 1
    @Charklewis the default mask-mode is alpha so only the alpha channel of the color is relevant, it can be any kind of coloration (related: https://stackoverflow.com/a/62387441/8620333) – Temani Afif May 04 '21 at 11:04
0

Here is my solution for both contained and outlined coupons with mask-image and radial-gradient .

In order to draw an outlined coupon, I use two backgrounds and masks, each of which is only a half part to avoid overlapping of radial-gradient.

.wrapper {
  display: flex;
  gap: 30px;
  --coupon-side-radius: 6px;
  --coupon-background-color: #c39f76;
  --coupon-border-color: #c39f76;
  --coupon-border-width: 1px;
}

.coupon {
  width: 100px;
  height: 100px;
  border: var(--coupon-border-width, 1px) solid var(--coupon-border-color);
  border-radius: 6px;
  box-sizing: border-box;
  background: radial-gradient(
        circle at center left,
        transparent 0px var(--coupon-side-radius),
        var(--coupon-border-color) var(--coupon-side-radius)
          calc(var(--coupon-side-radius) + var(--coupon-border-width, 0.5px)),
        var(--coupon-background-color) calc(var(--coupon-side-radius) + var(--coupon-border-width) + 0.5px)
      )
      border-box,
    radial-gradient(
        circle at center right,
        transparent 0px var(--coupon-side-radius),
        var(--coupon-border-color) var(--coupon-side-radius)
          calc(var(--coupon-side-radius) + var(--coupon-border-width, 0.5px)),
        var(--coupon-background-color) calc(var(--coupon-side-radius) + var(--coupon-border-width, 0.5px) + 0.5px)
      )
      border-box;
  background-size: 50% 100%, 50% 100%;
  background-position: 0% 100%, 100% 100%;
  background-repeat: no-repeat, no-repeat;

  -webkit-mask-image: radial-gradient(
      circle at center left,
      transparent 0,
      transparent var(--coupon-side-radius),
      #000 calc(var(--coupon-side-radius) + 0.5px)
    ),
    radial-gradient(
      circle at center right,
      transparent 0,
      transparent var(--coupon-side-radius),
      #000 calc(var(--coupon-side-radius) + 0.5px)
    );
  -webkit-mask-size: 50% 100%, 50% 100%;
  -webkit-mask-position: 0% 100%, 100% 100%;
  -webkit-mask-repeat: no-repeat, no-repeat;
}

.coupon1 {
  --coupon-side-radius: 6px;
  --coupon-background-color: #c39f76;
  --coupon-border-color: #c39f76;
  --coupon-border-width: 1px;
}

.coupon2 {
  --coupon-side-radius: 6px;
  --coupon-border-color: red;
  --coupon-border-width: 1px;
  
  --coupon-background-color: #c39f76;

}

.coupon3 {
  --coupon-side-radius: 6px;
  --coupon-background-color: transparent;
  --coupon-border-color: red;
  --coupon-border-width: 1px;
}

.coupon4 {
  --coupon-side-radius: 6px;
  --coupon-background-color: transparent;
  --coupon-border-color: red;
  --coupon-border-width: 2px;
}

.coupon5 {
  --coupon-side-radius: 6px;
  --coupon-background-color: transparent;
  --coupon-border-color: red;
  --coupon-border-width: 0.5px;
  border: none !important;
  position: relative;
}
.coupon5::before{
    content: "";
    position: absolute;
    top: 0px;
    left: 0px;
    box-sizing: border-box;
    width: 200%;
    height: 200%;
    transform: scale(0.5);
    transform-origin: left top;
    border: 1px solid red;
    border-radius: 16px;
    opacity: 0.7;
}

.coupon-demo {
  width: 100px;
  height: 100px;
  border: 2px solid red;
  border-radius: 15px;
  background: radial-gradient(
        circle at center left,
        transparent 0px 6px,
        red 6px 8px,
        #fff 9px
      )
      border-box,
    radial-gradient(
        circle at center right,
        transparent 0px 6px,
        red 6px 8px,
        #c39f76 9px
      )
      border-box;
  background-size: 51% 100%, 50% 100%;
  background-position: 0% 100%, 100% 100%;
  background-repeat: no-repeat, no-repeat;

  -webkit-mask-image: radial-gradient(
      circle at center left,
      transparent 0,
      transparent 6px,
      red 7px
    ),
    radial-gradient(
      circle at center right,
      transparent 0,
      transparent 6px,
      red 7px
    );
  -webkit-mask-size: 50% 100%, 50% 100%;
  -webkit-mask-position: 0% 100%, 100% 100%;
  -webkit-mask-repeat: no-repeat, no-repeat;
}
<div class="wrapper">
  <div class="coupon coupon1">1. Contained</div>
  <div class="coupon coupon2">2. Contained + Outlined</div>
  <div class="coupon coupon3">3. Outlined</div>
  <div class="coupon coupon4">4. Border 2px</div>
  <div class="coupon coupon5">5. Border 0.5px </div>
  <div class="coupon-demo">6. For debug purpose </div>
<div>
Zhuang Niu
  • 31
  • 1
  • 5