skip to Main Content

I’m trying to create a block with a smooth, curved cut-out in the top-right corner, similar to the image below:

enter image description here

Currently, my implementation looks like this:

enter image description here

As you can see, the current curve is not as smooth as I’d like it to be – It’s essentially not a curve, but a square with straight angles. Here’s my current code:

body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
  background-color: #f0f0f0;
  font-family: Arial, sans-serif;
}

.curved-block {
  width: 300px;
  background-color: white;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  position: relative;
  overflow: hidden;
  padding: 5px;
}

.curved-block::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  width: 40px;
  height: 40px;
  background-color: #f0f0f0;
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cpath d='M0 0 h25 c5 0, 10 0, 13 3 s2 7, 2 12 v25 h-40 z' fill='%23000000'/%3E%3C/svg%3E");
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cpath d='M0 0 h25 c5 0, 10 0, 13 3 s2 7, 2 12 v25 h-40 z' fill='%23000000'/%3E%3C/svg%3E");
  mask-size: cover;
  -webkit-mask-size: cover;
}

.icon {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 23px;
  height: 23px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 16px;
  font-weight: bold;
  background-color: #0056b3;
  border-radius: 50%;
  color: white;
  z-index: 2;
}
<div class="curved-block">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <span class="icon">+</span>
</div>

I’m struggling to achieve a smoother, more natural-looking curve in the SVG mask. How can I modify the SVG path to create a curve that looks more like the one in the desired result image? Thank you in advance for your suggestions.

2

Answers


  1. I did it here: https://css-shape.com/inverted-radius/

    You can easily copy the code and adjust the variables:

    .inverted-radius {
      --r: 15px; /* the radius */
      --s: 30px; /* the size of the corner*/
      
      height: 150px;
      margin: 10px;
      background: #3FB8AF;
      border-radius: var(--r);
      --_m:/calc(2*var(--r)) calc(2*var(--r))
        radial-gradient(#000 70%,#0000 72%) no-repeat;
      mask:
        right calc(var(--s) + var(--r)) top var(--_m),
        right calc(var(--s) + var(--r)) var(--_m),
        radial-gradient(var(--s) at 100% 0,#0000 99%,#000 101%) 
         calc(-1*var(--r)) var(--r) no-repeat,
        conic-gradient(at calc(100% - var(--s) - 2*var(--r)) calc(var(--s) + 2*var(--r)),
         #0000 25%,#000 0);
    }
    <div class="inverted-radius"></div>
    Login or Signup to reply.
  2. Since you’re using uniformly rounded corners you may also combine a CSS clip-path with a SVG "goo" filter.

    body {
      font-family: Arial, sans-serif;
      margin: 0;
      background-color: #f0f0f0;
      padding: 3em;
    }
    
    :root{
      --icon-space: 2em;
      --drop-shadow: drop-shadow(2px 2px 2px rgba(0, 0, 0, 0.75))
    }
    
    .curved-block-outer {
      position: relative;
    }
    
    .curved-block {
      background-color: #fff;
      padding: 0.5em 2.5em 0.5em 0.5em;
      clip-path: polygon( 0% 0%, calc(100% - var(--icon-space)) 0%, calc(100% - var(--icon-space)) var(--icon-space), 100% var(--icon-space), 100% 100%, 0% 100%);
    }
    
    /* round corners via SVG filter; add drop shadow */
    .curved-block-filter {
      filter: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><filter id='goo'><feGaussianBlur in='SourceGraphic' stdDeviation='7.5' result='blur'/><feColorMatrix in='blur' mode='matrix' values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9' result='goo'/><feComposite in='SourceGraphic' in2='goo' operator='atop'/></filter></svg>#goo") var(--drop-shadow);
    }
    
    .icon {
      position: absolute;
      right: 0;
      top: 0;
      z-index: 10;
      width: 1.5em;
      height: 1.5em;
      display: block;
      text-align: center;
      font-size: 1em;
      line-height: 1.6em;
      font-weight: bold;
      background-color: #0056b3;
      border-radius: 50%;
      color: #fff;
      filter: var(--drop-shadow);
    }
    <div class="curved-block-outer ">
      <span class="icon">+</span>
      <div class="curved-block-filter">
        <div class="curved-block">
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        </div>
      </div>
    </div>

    We’re basically

    • drawing a polygon with 6 vertices with relative units
    • apply a SVG filter to round the rendering of this polygon

    Unfortunately we need some additional wrapping elements otherwise we can’t apply a drop shadow or the plus-button is also affected by the filters.

    Goo filter

    You can either reference the filter by inlining a SVG in your HTML

    <svg class="flt_svg">
        <filter id="goo">
          <feGaussianBlur in="SourceGraphic" stdDeviation="7.5" result="blur" />
          <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
          <feComposite in="SourceGraphic" in2="goo" operator="atop" />
        </filter>
    </svg>
    

    and apply it in CSS like so:

    filter: url("#goo")
    

    or you can encode the SVG to a dataURL and embed it directly in CSS

    filter: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><filter id='goo'><feGaussianBlur in='SourceGraphic' stdDeviation='7.5' result='blur'/><feColorMatrix in='blur' mode='matrix' values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9' result='goo'/><feComposite in='SourceGraphic' in2='goo' operator='atop'/></filter></svg>#goo")
    

    The stdDeviation='7.5' value specifies the border/rounding radius.

    See also

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search