SVE
SVE

Reputation: 1655

svg border corners with inner border

I have a some block, with some design:

enter image description here

And I have some svg code:

.box {
	position: relative;
	margin: .75em auto 0;
	max-width: 255px;
	min-height: 56px;
}

svg {
	position: absolute;
	width: 100%; height: 100%;
}
<div class='box'>
	<svg>
		<mask id='m' fill='#fff'>
			<rect id='r' width='256' height='56'/>
			<circle id='c' r='10' fill='#000'/>
			<use xlink:href='#c' x='100%'/>
			<use xlink:href='#c' y='100%'/>
			<use xlink:href='#c' x='100%' y='100%'/>
		</mask>
		
		<mask id='m2' fill='#fff'>
			<rect id='r2' width='248' height='50' x="4" y="4" />
			<circle id='c2' r='14' fill='#000' stroke='#000'/>
			<use xlink:href='#c2' x='100%' />
			<use xlink:href='#c2' y='100%'/>
			<use xlink:href='#c2' x='100%' y='100%'/>
		</mask>
		
		<use xlink:href='#r' fill='red' mask='url(#m)'/>
		<use xlink:href='#r2' fill='none' stroke="#000" mask='url(#m2)'/>
	</svg>
</div>

Question: how to make inside a block with the same rounded cut corners, but not with a solid fill and stroke?

P.S: it should remain the ability to edit the radius of the rounding corners, indents vn. blocks. Perhaps there is a simple implementation on css (maximum cross-browser), would also be suitable.

Upvotes: 3

Views: 792

Answers (3)

Temani Afif
Temani Afif

Reputation: 272752

I would go with a pure CSS solution using multiple background. It's a bit trick to manipulate but using some CSS variable you can make it easy to adjust:

.box {
  --th:2px; /*thickness of the transparent part*/
  --l:4px; /*height of border*/
  --r:25px; /*radius*/
  
  
  --rad:transparent calc(103% - var(--th) - var(--l) - 1px), 
         #000 calc(103% - var(--th) - var(--l))  
              calc(103% - var(--th) - 1px),
         transparent calc(103% - var(--th)) 103%,
         #000 103%;
  --rad-s:var(--r) var(--r);
  --border:#000 calc(var(--l)),transparent calc(var(--l)),transparent calc(var(--l) + var(--th));
  --w:calc(100% - 2*var(--r) + 2*var(--th));
  --h:calc(var(--l) + var(--th));
  margin:10px;
  display:inline-block;
  padding:40px 20px;
  background:
    /*The 4 borders*/
    linear-gradient(to bottom,var(--border)) top   /var(--w) var(--h),
    linear-gradient(to top   ,var(--border)) bottom/var(--w) var(--h),
    linear-gradient(to right ,var(--border)) left  /var(--h) var(--w),
    linear-gradient(to left  ,var(--border)) right /var(--h) var(--w),
    /*The 4 corners */
    radial-gradient(farthest-side at top    right,var(--rad)) top    right/var(--rad-s),
    radial-gradient(farthest-side at top    left ,var(--rad)) top    left /var(--rad-s),
    radial-gradient(farthest-side at bottom right,var(--rad)) bottom right/var(--rad-s),
    radial-gradient(farthest-side at bottom left ,var(--rad)) bottom left /var(--rad-s),
    /*The main background*/
    linear-gradient(#000,#000) center/calc(100% - 2*var(--r)) calc(100% - 2*var(--h)),
    linear-gradient(#000,#000) center/calc(100% - 2*var(--h)) calc(100% - 2*var(--r));
    
 background-repeat:no-repeat;
 
 color:#fff;
 text-align:center;
}

body {
 background:pink;
}
<div class="box">
  Some text inside
</div>

<div class="box" style="--th:3px;--r:20px">
  Some text inside
</div>

<div class="box" style="--th:4px;--r:40px;--l:8px">
  Some text inside
</div>

<div class="box" style="--th:5px;--r:30px">
  Some text inside
</div>

<div class="box" style="--th:1px;--r:15px;--l:3px">
  Some text inside
</div>

CSS transparent inner border

Upvotes: 5

enxaneta
enxaneta

Reputation: 33034

This is my answer: I'm using the size of the bounding box of the text so you can change the text as you like. For the cut out corners I'm using arcs. Also you can change the "padding" i.e. the distance between the text and the border.

let bb = txt.getBBox();


function drawShape(path, padding){
let d = `M${bb.x},${bb.y - padding}
         L${bb.x + bb.width},${bb.y - padding}
A${padding}, ${padding} 0 0 0 ${bb.x + bb.width + padding},${bb.y}
         L${bb.x + bb.width + padding},${bb.y + bb.height}
A${padding}, ${padding} 0 0 0 ${bb.x + bb.width},${bb.y + bb.height + padding}
         L${bb.x},${bb.y + bb.height + padding}
A${padding}, ${padding} 0 0 0 ${bb.x  - padding},${bb.y + bb.height}
         L${bb.x  - padding},${bb.y}
A${padding}, ${padding} 0 0 0 ${bb.x},${bb.y - padding}z
`
path.setAttributeNS(null,"d",d)
}
drawShape(pth, 10);
drawShape(pth1, 10);
<svg viewBox="0 0 200 100">
  <path id="pth" fill="black" stroke="black" stroke-width="4" d="" />
  <path id="pth1" stroke="white" stroke-width="2" d="" />
  <text id="txt" fill="white" dominant-baseline="central" text-anchor="middle" x="100" y="50">
    some text inside
  </text>
  </svg>

Upvotes: 2

Paul LeBeau
Paul LeBeau

Reputation: 101800

How about this? It should work for any size by just changing the dimensions of <div class="box">.

.box {
	position: relative;
	margin: .75em auto 0;
	width: 255px;
	height: 56px;
}

.box svg {
	position: absolute;
	width: 100%;
  height: 100%;
}

.size2 {
	width: 455px;
	height: 256px;
}
<div class="box">
  <svg width="100%" height="100%">
    <mask id="m" fill="#fff">
      <rect width="100%" height="100%"/>

      <rect width="100%" height="100%" fill="none" stroke="#000" stroke-width="12"/>
      <circle r="16" fill="#000"/>
      <circle cx="100%" r="16" fill="#000"/>
      <circle cy="100%" r="16" fill="#000"/>
      <circle cx="100%" cy="100%" r="16" fill="#000"/>

      <rect width="100%" height="100%" fill="none" stroke="#fff" stroke-width="8"/>
      <circle r="14" fill="#fff"/>
      <circle cx="100%" r="14" fill="#fff"/>
      <circle cy="100%" r="14" fill="#fff"/>
      <circle cx="100%" cy="100%" r="14" fill="#fff"/>

      <circle r="10" fill="#000"/>
      <circle cx="100%" r="10" fill="#000"/>
      <circle cy="100%" r="10" fill="#000"/>
      <circle cx="100%" cy="100%" r="10" fill="#000"/>
    </mask>
		
    <rect width="100%" height="100%" mask="url(#m)"/>
  </svg>
</div>

Upvotes: 5

Related Questions