I have the following code:
.container{
width: 100px;
height: 200px;
background-color: red;
resize: both; /* Just to make it... */
overflow: hidden; /* ...resizable for testing. */
}
<div class="container">
<svg width="100%" height="100%">
<circle cx="50%" cy="50%" r="25%" fill="black"></circle>
</svg>
</div>
As I resize .container
, I can easily see that:
cx
is percentage of the widthcy
is percentage of the height
But I cannot understand what r
is percentage of. What is r
percentage of?
2
As commented by Roko C. Buljan when using % units the relative value refers to the normalized diagonal length.
See the W3C SVG 2 specs (working draft) “8.9. Units”
For any other length value expressed as a percentage of the SVG
viewport, the percentage must be calculated as a percentage of the
normalized diagonal of the ‘viewBox’ applied to that viewport. If no
‘viewBox’ is specified, then the normalized diagonal of the SVG
viewport must be used. The normalized diagonal length must be
calculated withsqrt((width)**2 + (height)**2)/sqrt(2)
.
here’s an example
let w = 100;
let h = 200;
let c = Math.sqrt(w ** 2 + h ** 2) / Math.sqrt(2)
let rAbsolute = c * 0.25
// get absolute radius via baseVal
let r = c1.r.baseVal.value
console.log(rAbsolute, r)
.container {
width: 100px;
height: 200px;
background-color: red;
}
<div class="container">
<svg width="100%" height="200px">
<circle id="c1" cx="50%" cy="50%" r="25%" fill="#ccc"></circle>
<circle cx="50%" cy="50%" r="39.52847075210474" fill="none" stroke="blue" />
</svg>
</div>
You can also check your calculations using the baseVal
property from the SVGAnimatedLength
interface.
If you actually need the circle scale more predictably you may also add a square-shaped viewBox
. In this case the preserveAspectRatio
(in the example below the default “xMidYMid meet”) attribute will affect the alignment and scaling.
.container {
width: 100px;
height: 200px;
background-color: red;
resize: both;
overflow: hidden;
}
<div class="container">
<svg width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
<rect width="100%" height="100%" fill="none" stroke="#ccc"/>
<circle cx="50%" cy="50%" r="25%" fill="black" />
</svg>
</div>
As you can see the radius of the circle stays at 25% relative to the 100×100 viewBox
(so the circle stays 50% wide).
2
I’m posting in case others are looking for the same thing I was looking for.
I needed the radius to be expressed as percentage of the smallest of the width and the height of the SVG element. I don’t know how well browsers support it, but using the new container functionality in CSS with the cqmin
unit worked well for me (tested in Firefox and Chrome).
.container{
width: 100px;
height: 200px;
background-color: red;
resize: both; /* Just to make it... */
overflow: hidden; /* ...resizable for testing. */
container-type: size; /* Add this one. */
}
<div class="container">
<svg width="100%" height="100%">
<circle cx="50%" cy="50%" r="25cqmin" fill="black"></circle>
</svg>
</div>
2