7

Is it possible to round a rectangle in SVG while ensuring the stroke obeys the roundedness of corners? The code below isn't working.

No Stroke:

stroke-width="0px"

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="0px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

With Stroke:

stroke-width="10px"

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

The stroke seems to follow the original sharp corners instead of the rounded corners.

Alexandr_TT
  • 13,635
  • 3
  • 27
  • 54
Crashalot
  • 33,605
  • 61
  • 269
  • 439

3 Answers3

9

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

A wide string extends beyond the svg border of the canvas SVG. Therefore, the string is partially cropped.

enter image description here

You must reduce the size of the rectangle so that the line is visible and shift the upper left corner of the rectangle right and down x="5" and y="5"

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <rect x="5" y="5" width="90" height="90" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

Update

ViewBox added. The coordinates of the rectangle x andy of the are increased, SVG wrapped in a container and can be embedded in an HTML page as a separate block. Adaptive application

.container {
width:30%;
height:30%
}
<div class="container">
<svg  viewBox="0 0 110 110" xmlns="http://www.w3.org/2000/svg">
    <rect x="10" y="10" width="90" height="90" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>
</div>

enter image description here

As you can see from the picture, a square with a wide stroke is completely inside the SVG canvas

Alexandr_TT
  • 13,635
  • 3
  • 27
  • 54
  • This would work, except it seems the stroke is not consistently rendered across browsers. In some browsers, it seems rendered in the center of the element border and some browsers it's fully inside? Details https://stackoverflow.com/questions/7241393/can-you-control-how-an-svgs-stroke-width-is-drawn – Crashalot Nov 19 '19 at 05:22
  • @Crashalot Stroke svg elements are always displayed symmetrically relative to the border of the elements. With a stroke width of 10 pixels - 5px outside the element 5px inside the element. In the snippet, my example works in Chrome Firefox. If the stroke is incorrect in other browsers, then try to enlarge the viewport and increase the initial coordinates of the rectangle ` x` and `y` – Alexandr_TT Nov 19 '19 at 06:21
  • 1
    I think the challenge here is to have an adaptative rectangle inside the SVG. In both of your examples you are either fixing the width/height of the rect or the ratio so yes it's adaptative but always remain a square. We cannot have something like this: https://jsfiddle.net/9cd62hy5/1/ where the rect is always 100% in width/height of the SVG. I found a solution using calc() here: https://stackoverflow.com/a/51496341/8620333 but it works find only on Chrome. (PS: the use of height in the second case is useless since the parent has no defined height) – Temani Afif Nov 19 '19 at 08:07
  • @Temani Afif I answered the question OP `Is it possible to round a rectangle in SVG while ensuring the stroke obeys the roundedness of corners?` And I explained in the first example why the round stroke is not visible, since it did not fit completely on the SVG canvas. The second example is given as a bonus on how to make a rectangle or any other shape adaptive in SVG. Namely: add the `viewBox` and remove the fixed width / height in the header of the SVG file. I always carefully study your creative answers to questions from the participants of this site. I really like many of your answers. – Alexandr_TT Nov 19 '19 at 13:56
  • 2
    You are entirely answering the question but I think the OP missed some details because I am pretty sure this one is asked due to the issue faced in his old one here: https://stackoverflow.com/q/58784579/8620333 where I suggested to him to turn out to SVG since the CSS solution is a bit hacky that's why I think the responsive part (not clearly asked here) is important and that's why he's using 100% in height/width. I added an answer as I noticed firefox fixed the issue with calc() so it should be a good solution (don't know about the other browser)[thanks for the compliment btw] – Temani Afif Nov 19 '19 at 14:08
4

The first trivial solution is to make the overflow visible and add some margin to rectify this

svg {
  overflow:visible;
  margin:5px; /*half the stroke*/
}
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

<svg width="150" height="80" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

<svg width="100" height="200" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

Or you use calc() like below:

svg rect{
  height:calc(100% - 10px);
  width:calc(100% - 10px);
  x:5px;
  y:5px;
}
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

<svg width="150" height="80" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

<svg width="100" height="200" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" stroke="red" stroke-width="10px" rx="10px" ry="10px" stroke-linejoin="round" />
</svg>

That can be used as background too:

.box {
    background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"  ><rect x="5" y="5" width="100%" height="100%" style="height:calc(100% - 10px);width:calc(100% - 10px)" stroke="red" stroke-width="10" rx="10" ry="10" stroke-linejoin="round" /></svg>');
    color: #fff;
    padding:25px;
    display:inline-block;
    margin: 75px 0;
}
<div class="box"> Some text here</div>

<div class="box"> text very loooooooooooong here</div>


<div class="box"> a text <br> two line here</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • why do you define the width/height in the svg markup, but also use css style rules to define the size? won't the inline size overrule the css size? – Crashalot Nov 27 '19 at 17:12
  • @Crashalot no, the CSS one will override because it's width/height attribute and not inline width/height so the CSS is more specific than it and you can simply remove the attribute one. You don't have to define them, I simply kept the same SVG from the first to the second snippet – Temani Afif Nov 27 '19 at 18:54
  • @Crashalot related question to understand why the CSS override the attribute: https://stackoverflow.com/a/56727105/8620333 – Temani Afif Nov 27 '19 at 18:58
0

<svg width="400" height="180">
    <rect x="50" y="20" rx="20" ry="20" width="150" height="150"
          style="fill:red;stroke:black;stroke-width:5;opacity:0.5" />
</svg>
Wang Liang
  • 4,244
  • 6
  • 22
  • 45