Reputation: 6954
I want to vertically and horizontally centre a letter inside of an SVG circle so that it stays centred and stays in the same proportions with the circle. While I have the code below, I also have this JSFiddle where if you resize the preview, then you can see the letter does not stay in proportion with the circle.
li {
list-style-type: none;
position: relative;
}
li div {
font-size: 60vw;
position: absolute;
text-align: center;
top: 7vw;
left: -3vw;
width: 100%;
}
<ul>
<li class="circleIcon" id="{{ item.id }}">
<svg viewBox="0 0 100 100">
<circle cx="46" cy="46" r="45" stroke="black" stroke-width="1" fill="grey" />
</svg>
<div>I</div>
</li>
</ul>
What can I do to keep the text in proportion with the circle without using Javascript? Thanks.
Upvotes: 1
Views: 1110
Reputation: 101918
You can horizontally centre text in SVG, but there is no perfect way to do it in the vertical direction.
Some people will suggest using <foreignObject>
to embed a little piece of HTML in the SVG. Then take advantage of HTMLs ability to do the centering. But IMO this is overkill for simple SVGs like yours.
Another suggestion is to use dominant-baseline
CSS property as seen here. But that relies on browser support for those font tables and the font having those tables.
My preferred solution is to to use a dy
with a value in em
units. All you need to do is find the correct em value for the font you are using. And it will work at any font size.
For example the correct value for Verdana is around 0.36em. Demo below.
li {
list-style-type: none;
position: relative;
}
li div {
font-size: 60vw;
position: absolute;
text-align: center;
top: 7vw;
left: -3vw;
width: 100%;
}
<ul>
<li class="circleIcon" id="{{ item.id }}">
<svg viewBox="0 0 100 100">
<circle cx="46" cy="46" r="45" stroke="black" stroke-width="1" fill="grey" />
<text x="46" y="46" font-family="Verdana" font-size="80" dy="0.36em" text-anchor="middle">I</text>
</svg>
</li>
</ul>
Upvotes: 1
Reputation: 4385
If you don't need to use an svg, you can just do this by making the element circular, and giving it a border and a background color.
Edit: Noticed your comment about animating the border. CSS animations aren't limited to svg
s - I've added a border color animation to my solution (learn the basics of CSS animations at W3Schools, and get more in-depth on MDN).
Note that this result doesn't even require more than one element. Run this snippet and scroll down to see it working with just <div>i</div>
!
ul {
margin: 0;
padding: 0;
}
li, div {
width: 80vw;
height: 80vw;
margin: 0 auto;
text-align: center;
/* the circle */
background: gray;
border: 1vw solid black; /* I would usually just use a px weight, but I'm trying to make it look like your example */
border-radius: 50%; /* makes it circular */
/* the letter */
font-size: 60vw;
line-height: 80vw; /* making the line-height the same as the parent element's height centers the letter vertically */
/* animate the borders */
-webkit-animation: pulse 5s infinite ease-in 0s;
animation: pulse 5s infinite ease-in 0s;
}
/* the animation */
@-webkit-keyframes pulse {
0% { border-color: black }
50% { border-color: red }
}
@keyframes pulse {
0% { border-color: black }
50% { border-color: red }
}
<ul>
<li>I</li>
</ul>
<div>i</div>
Upvotes: 0
Reputation: 7109
If you don't have any issues with using text
property of SVG, then this can help you out.
li {
list-style-type: none;
position: relative;
}
li text {
font-size: 4em;
line-height: 1;
}
<ul>
<li class="circleIcon" id="{{ item.id }}">
<svg viewBox="0 0 100 100">
<circle cx="46" cy="46" r="45" stroke="black" stroke-width="1" fill="grey" />
<text x="45" y="45" font-family="Verdana" font-size="60" fill="black" alignment-baseline="central" text-anchor="middle">I</text>
</svg>
</li>
</ul>
Upvotes: 0
Reputation: 5118
You can do this without using an svg and take advantage of Flexbox:
Now your html looks cleaner:
<ul>
<li class="circleIcon" id="{{ item.id }}">
<div>I</div>
</li>
</ul>
Here the css with some explanation of what I did:
li{
position:relative;
list-style:none;
}
li div {
position: relative;
/* We center vertically and horizontally using flexbox */
display: flex;
align-items:center;
justify-content:center;
/* until here */
width: 100%;
height:0;
padding: 50% 0;
border-radius: 50%;
font-size:60vw;
/* just styling the circle */
border: 5px solid black;
background:grey;
}
I added a fiddle for you: https://jsfiddle.net/3frft2gd/2/
NOTE: if you want the text to keep scaling you can use media queries and it'll work, hope it helps.
Upvotes: 0