I am trying to create a rectangle in svg with a border / stroke at the top and bottom and with rounded corners by using a radius (rx, ry). By using the css property "dasharray: width, height" it is possible to style only the top and the bottom with a border/stroke. Without a radius this works as expected.
However, when the radius is added, the top border no longer starts in the top left corner of the rectangle. I tried to correct this behavior by using the css property dash-offset, but this seems to make the top border disappear partly (althought it seems to work for the bottom border).
Any help on how to create a rectangle with a radius and only a top and bottom border is much appreciated, as is some insight into what is happening.
see the fiddle at: https://jsfiddle.net/Lus8ku7p/
<svg>
<rect x =10 y=10 id=a ></rect>
<rect x = 10 y=170 id=b class=round></rect>
<rect x=170 y=10 id=c ></rect>
<rect x=170 y=170 id=d class=round></rect>
</svg>
svg{
width:400px;
height:400px
}
rect {
width: 150px;
height: 150px;
stroke-width:4px;
stroke:black;
fill:red;
stroke-dasharray: 150 150;
}
.round{
rx:20px;
ry:20px;
}
#c, #d{
stroke-dashoffset: 40px;
}
The <rect> element is a basic SVG shape that draws rectangles, defined by their position, width, and height. The rectangles may have their corners rounded.
The stroke-dasharray attribute is a presentation attribute defining the pattern of dashes and gaps used to paint the outline of the shape; Note: As a presentation attribute, stroke-dasharray can be used as a CSS property. You can use this attribute with the following SVG elements: <altGlyph>
The stroke-dashoffset attribute is a presentation attribute defining an offset on the rendering of the associated dash array. Note: As a presentation attribute stroke-dashoffset can be used as a CSS property.
In order for dash patterns to render the same in all SVG renderers, the SVG specification defines where the dash pattern should begin for all shapes. Including rectangles.
For a rectangle, the start point is at the left end of the horizontal section of the top side of the rectangle. So if there is a rounded corner, it is at the point where the curve meets the straight. The dash pattern then proceeds around the rectangle in a clockwise direction.
That start point is effectively a tunnel or portal through which the dash pattern emerges and disappears into. You can't change its location, you just have to construct your dash pattern carefully with that start point in mind.
You don't say where exactly how much of the rounded corner you want included in the top stroke, but I am going to assume you want to include the whole of the curve.
In your example the rectangle is 150x150 with a corner radius of 20. Let's call those w, h, and r.
To calculate the dash pattern correctly we need to work out the lengths of all the sides and rounded corners accurately.
The top and bottom will each be length (w - 2 * r) = 110
. Lets call this xlen
.
The left and right sides will be length (w - 2 * r) = 110
. Let's call this ylen
.
Each of the rounded corners will be length (PI * 2 * r) / 4 = 31.416
. Let's call this rlen
Dash pattern version 1
We could just make our dash pattern up from the different lengths of pattern that we need to complete the circumference of the rectangle. Ie.
xlen + rlen = 141.416
.ylen = 110
.rlen + xlen + rlen = 172.832
.ylen = 110
.rlen = 31.416
.So the dash pattern would be "141.416 110 172.832 110 31.416"
.
rect {
stroke-width: 4px;
stroke: black;
fill:red;
stroke-dasharray: 141.416 110 172.832 110 31.416;
}
<svg width="400" height="400">
<rect x="10" y="10" width="150" height="150" rx="20"/>
</svg>
Dash pattern version 2
The other, simpler, but less obvious solution perhaps is to take advantage of the fact that dash patterns repeat. Combine this with a dash offset and we can make the dash pattern a lot simpler.
rlen + xlen + rlen = 172.832
.ylen = 110
.So the dash pattern would be "172.832 110"
.
"But wait" you might say, That won't wwork because the pattern will be shifted clockwise by the length of a rounded corner. You are right.
rect {
stroke-width: 4px;
stroke: black;
fill:red;
stroke-dasharray: 172.832 110;
}
<svg width="400" height="400">
<rect x="10" y="10" width="150" height="150" rx="20"/>
</svg>
However if we use stroke-dashoffset
to shift the pattern left/anti-clockwise, we will lose some of the first dash, but we will also be "pulling" some of the next repeat of the dash pattern back through that start/end "portal". This relies on the dash pattern being the exact right length. That's why we were so careful at the start to calculate all the lengths accurately.
Spo what is the value we need to use for stroke-dashoffset
? The way the dash offset works is that it specifies how far into the pattern we should start drawing from. So it needs to be after the length of the rounded corner, or 31.416
.
So if we add that we get:
rect {
stroke-width: 4px;
stroke: black;
fill:red;
stroke-dasharray: 172.832 110;
stroke-dashoffset: 31.416;
}
<svg width="400" height="400">
<rect x="10" y="10" width="150" height="150" rx="20"/>
</svg>
You can see that if you want your dash pattern to start and stop at the correct places, it is possible. You just need to calculate the lengths in your dash pattern accurately.
If you need to have the same sort of pattern on rectangle of other sizes you need to recaclculate the lengths using the formulas I list at the start of this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With