How to create rounded borders with gap?

Viewed 66

I'm trying to create blocks and elements with rounded corners and a gap between the corner and the straight line. Turns out its a little bit difficult :)

screenshot of block element with rounded corners

I also have to create "button" like this,

button1

and

button2

If I can not create them in pure CSS I will use svg for this, but I have to solve the above problem first.

Anyone have some idea?

3 Answers

mask can help you:

.box {
  --r:40px; /* radius*/
  --g:5px; /* gap */
  
  width:200px;
  height:100px;
  display:inline-block;
  border:5px solid red;
  box-sizing:border-box;
  margin:10px;
  border-radius:var(--r);
  --m:#0000 90deg,#000 0; 
  -webkit-mask:
    conic-gradient(from -180deg at calc(100% - var(--g)) var(--g)            ,var(--m))
        0    100%/var(--r) var(--r),
    conic-gradient(from  90deg at var(--g)              var(--g)             ,var(--m))
        100% 100%/var(--r) var(--r),
    conic-gradient(from   0deg at var(--g)              calc(100% - var(--g)),var(--m))
        100% 0   /var(--r) var(--r),
    conic-gradient(from -90deg at calc(100% - var(--g)) calc(100% - var(--g)),var(--m))
        0    0   /var(--r) var(--r),
    linear-gradient(#000 0 0);
   -webkit-mask-repeat:no-repeat;
   -webkit-mask-composite:xor;
   mask-composite:exclude;
}
<div class="box"></div>
<div class="box" style="width:100px;--r:50px"></div>
<div class="box" style="width:150px;--r:50px"></div>

To have content, use it as pseudo element:

.box {
  --r:30px; /* radius*/
  --g:5px; /* gap */
  
  width:200px;
  height:100px;
  display:inline-block;
  box-sizing:border-box;
  padding:20px;
  position:relative;
  margin:10px;
}
 
.box:before {
  content:"";
  position:absolute;
  inset:0;
  border:5px solid red;
  border-radius:var(--r);
  --m:#0000 90deg,#000 0; 
  -webkit-mask:
    conic-gradient(from -180deg at calc(100% - var(--g)) var(--g)            ,var(--m))
        0    100%/var(--r) var(--r),
    conic-gradient(from  90deg at var(--g)              var(--g)             ,var(--m))
        100% 100%/var(--r) var(--r),
    conic-gradient(from   0deg at var(--g)              calc(100% - var(--g)),var(--m))
        100% 0   /var(--r) var(--r),
    conic-gradient(from -90deg at calc(100% - var(--g)) calc(100% - var(--g)),var(--m))
        0    0   /var(--r) var(--r),
    linear-gradient(#000 0 0);
   -webkit-mask-repeat:no-repeat;
   -webkit-mask-composite:xor;
   mask-composite:exclude;
}
<div class="box"> content </div>
<div class="box" style="width:100px;--r:50px">content </div>
<div class="box" style="width:150px;--r:50px">content </div>

Looks like a job for a border-image.

const grab = document.getElementById('grab');
console.log("url('data:image/svg+xml;base64,"+btoa(grab.innerHTML.replace(/\r?\n */g,''))+"')");
.border-gap {
  border: 16px solid;
  border-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OCA0OCI+PHBhdGggc3Ryb2tlPSJibGFjayIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGZpbGw9Im5vbmUiIGQ9Ik0xLDEzIEExMiwxMiAwIDAgMSAxMywxTTE5LDEgSDI5TTM1LDEgQTEyLDEyIDAgMCAxIDQ3LDEzTTQ3LDE5IFYyOU00NywzNSBBMTIsMTIgMCAwIDEgMzUsNDdNMjksNDcgSDE5TTEzLDQ3IEExMiwxMiAwIDAgMSAxLDM1TTEsMjkgVjE5Ij48L3BhdGg+PC9zdmc+') calc(100% * 19 / 48);
  padding: 8px;
}
<div class="border-gap">Text</div>

<template id="grab">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
    <path stroke="black" stroke-width="2" stroke-linecap="round" fill="none" d="
      M1,13 A12,12 0 0 1 13,1
      M19,1 H29
      M35,1 A12,12 0 0 1 47,13
      M47,19 V29
      M47,35 A12,12 0 0 1 35,47
      M29,47 H19
      M13,47 A12,12 0 0 1 1,35
      M1,29 V19
    " />
  </svg>
</template>

I've included the SVG I used as well as the method for getting a data: URL for it, which can then be put in the border-image.

The hard way...

body {
  background: #232323;
}

.btn {
  border: 3px solid #fafafa;
  padding: 2px 12px;
  border-radius: 50%;
  background: transparent;
  position: relative;
}

.btn::before,
.btn::after {
  position: absolute;
  content: '';
  width: 3px;
  height: 5px;
  background: #232323;
  top: 40%
}

.btn::before {
  left: -10%;
}

.btn::after {
  right: -8%;
}

.btn:hover {
  border-color: #ff3844
}

.btn:hover .icon {
  color: #ff3844
}

.icon {
  color: #fafafa;
  font-size: 1.5rem;
  font-weight: bold
}

span {
  position: relative
}

span::before,
span::after {
  position: absolute;
  content: '';
  width: 5px;
  height: 4px;
  background: #232323;
  left: -2px;
}

span::before {
  top: -22px
}

span::after {
  bottom: -2px
}
<button class="btn">
  <div class='icon'>+</div>
  <span></span>
</button>

Related