How to make font-size relative to parent div?

104,547

Solution 1

Using font-size: x% is not relative to the width of the parent but the font-size the element would normally have.

So if your element's parent sets font-size: 12px then font-size: 50% in element means that element has a font-size of 6px

What you want to use is viewport percentage: vw

for example: font-size: 2vw

.counter-holder{
	display: block;
	position: absolute;
	width:90%;
	height:20%;
	top: 70%;
	left: 50%;
	/* bring your own prefixes */
	transform: translate(-50%, -50%);
}


.counter-element-box{
	position:relative;
	vertical-align: text-top;
	border-style: solid;
    border-width: 1px;
    width: 20%;
    height: 100%;
    float:left;
    margin: 6%;
}

.counter-element-text{
	position:absolute; 
	top:50%; 
	display: inline-block;
	margin-left:40%;
	font-size : 2vw;overflow: hidden;
}

.counter-element-value{
	position:absolute; 
	top:50%; 
	width: 50%;
	max-width:50%;
	display: inline-block;
	height:100%;
	padding-left:30%;
	font-size : 2vw;overflow: hidden;
}
<div class="counter-holder">
			
			<div class="counter-element-box">
				<div id="years" class="counter-element-value">
					0
		    	</div>
		    	<div class="counter-text counter-element-text" >
		    		Years
		    	</div> 
	    	</div>
	    	<div class="counter-element-box">
		    	<div id="missions" class="counter-element-value">
					0  
		    	</div>
		    	<div class="counter-text counter-element-text" >
		    		Missions
		    	</div>
	    	</div> 
		    <div class="counter-element-box">	
		    	<div id="team" class="counter-element-value">
					0 
		    	</div>
		    	<div class="counter-text counter-element-text" >
		    		Team
		    	</div>
	    	</div>		    	
</div>

Solution 2

The way I solved this problem was to use javascript to measure the container and then set the font size in px on that container. Once that baseline is set for the container then the relative font sizing of all the content will scale correctly using em or %.

I'm using React:

<div style={{ fontSize: width / 12 }} >
  ...
</div>

CSS:

div {
  font-size: 2em;
}

Solution 3

If you talk about responsive scaling, then you can implement it, but all depends on what you are trying to achieve. In the code below i have created a div container with ratio (height/width = 1/2). When you change the size of the browser window, container and text will scale responsively.Depending on the window size it will change the font according to VW(viewport width) and VH(viewport height). To add new font size you have to set it twice once according to the -vw and second time according to -vh. I have used CSS variables(var), that way its easier to understand the code.

Example

body {
    background-color: #000;
    padding: 0;
    margin:0;
}

/* position element in the middle */
.middle {
    position: absolute;
    top:50%;
    left: 50%;
    transform: translate(-50%, -50%);
} 


/* Ratio: height/width */ 
:root {
    --ratio: 0.5;
    --reverse-ratio: 2;
    --container-width: 50vw;
    --container-height: 50vh;

    --font1-sizeVW: 15vh;
    --font1-sizeVH: calc(var(--ratio) * 15vw);

    --font2-sizeVW: 6vh;
    --font2-sizeVH: calc(var(--ratio) * 6vw);
}

#container {

    background-color: pink;
    width: var(--container-width);
    height: calc(var(--ratio) * var(--container-width));

    max-width: calc(var(--reverse-ratio) * var(--container-height));  
    max-height: var(--container-height);
}

#span1 {
    font-size: var(--font1-sizeVW);   
}

#span2 {
    font-size: var(--font2-sizeVW);  
}

/* max-width: (reversRatio * 100vh) */
@media all and (max-width: 200vh) {  

    #container {
        background-color: green;
    }

    #span1 {  
        font-size: var(--font1-sizeVH); 
    } 

    #span2 {  
        font-size: var(--font2-sizeVH);
    } 
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
    </style>
</head>
<body>
    <div id="container" class="middle">
        <span id="span1">Hello</span>
        <span id="span2">Hello again</span>
    </div>
</body>
</html>

Solution 4

There's no way to achieve what this question is asking for in CSS. A font size can only be set in a certain number of ways, and any setting that is a percentage value is relative to the size of the font, not a width or height of a block.

So, while this doesn't offer a solution to your problem, it is an answer to the question of whether this can be done in CSS: it can't.

There are a lot of answers here which appear to answer the wrong question, and recommend the use of the vw unit, which is relative to the viewport and not the parent element's size. There are also some which resort to Javascript, which is doable if you don't mind that sort of thing. Then there is slaviboy's answer which advocates the use of CSS user variables which is a creative solution that I admire, even though it can't achieve the end effect asked for by the OP.

In many cases, when you want to set font size relative to the parent element's width, you have enough information to be able to do this with some math: work out how the parent element's width is calculated, and see if you can re-use a calculation like that in your font size setting.

For example, if parent element's width is the viewport width or a known percentage of it, then the answers based on vw will work, you just have to do the math to work out the right ratio. If parent element's width is some absolute value such as 500px, then that's even easier. Only if the parent element's width is completely unpredictable will this be difficult, though presumably the OP's situation is exactly that. For example, if the parent element's width is based on content, and content may be user-submitted or its size is otherwise not predictable.

Share:
104,547
Tachi
Author by

Tachi

Updated on January 26, 2022

Comments

  • Tachi
    Tachi over 2 years

    I want text inside my div to remain same size in % percentage ratio to a parent div. I.E. I want my text to have font-size of 50% of parents div width. So when page size is changing, text always remains the same size in %.

    Here Is what I'm talking about:

    .counter-holder{
    	display: block;
    	position: absolute;
    	width:90%;
    	height:20%;
    	top: 70%;
    	left: 50%;
    	/* bring your own prefixes */
    	transform: translate(-50%, -50%);
    }
    
    
    .counter-element-box{
    	position:relative;
    	vertical-align: text-top;
    	border-style: solid;
        border-width: 1px;
        width: 20%;
        height: 100%;
        float:left;
        margin: 6%;
    }
    
    .counter-element-text{
    	position:absolute; 
    	top:50%; 
    	width: 50%;
    	max-width:50%;
    	display: inline-block;
    	height:100%;
    	margin-left:50%;
    	font-size : 80%;overflow: hidden;
    }
    
    .counter-element-value{
    	position:absolute; 
    	top:50%; 
    	width: 50%;
    	max-width:50%;
    	display: inline-block;
    	height:100%;
    	padding-left:30%;
    	font-size : 80%;overflow: hidden;
    }
    <div class="counter-holder">
    	<div class="counter-element-box">
    		<div id="years" class="counter-element-value">
    			0
    		</div>
    		<div class="counter-text counter-element-text" >
    		    Years
    		</div> 
    	</div>
    	<div class="counter-element-box">
    		<div id="missions" class="counter-element-value">
    			0  
    		</div>
    		<div class="counter-text counter-element-text" >
    		    Missions
    		</div>
    	</div> 
    	<div class="counter-element-box">	
    		  <div id="team" class="counter-element-value">
    			   0 
    		  </div>
    		  <div class="counter-text counter-element-text" >
    		    	Team
    		  </div>
    	</div>		    	
    </div>

    Run this snippet in full screen and try resizing the page and see how text size is changing and not fitting inside the div borders. How can I prevent it from happening, so it always remains inside the borders?

  • Tachi
    Tachi about 9 years
    Great explanation, never heard of vw before.
  • bryan
    bryan over 7 years
    Isn't vw and vh the size of the viewport window, not it's parent?
  • MrMerrick
    MrMerrick about 7 years
    Indeed, this answer should not have been marked as valid! I'm guessing you would need some javascript to size text relative to a parent, but viewport units are definitely not the way to achieve this.
  • Serg
    Serg almost 7 years
    Absolutely agree - I can't imagine a real example when it's necessary to have text size relative to the size of a browser viewport. It's much more common to have a situation when text size should be relative to a size of a parent block. And one of the solutions is to use JavaScript similar to github.com/davatron5000/FitText.js
  • stephan.com
    stephan.com over 6 years
    I have a perfectly good use case for this - I have an element that can be configurable by an admin for display on an ordinary user's page. For the user, this element is the width of the screen, scaling using vw and vh works great. I would like the admin to have a smaller preview of this which may be some variable proportion of the width of the page, for example 6 bootstrap columns, switching responsively to full width at the medium breakpoint. Scaling to a percentage of the enclosing box's width would be ideal here.
  • John
    John almost 5 years
    That is relative to the viewport, not the parent element.
  • John
    John almost 5 years
    That is relative to the viewport, not the parent element.
  • slaviboy
    slaviboy almost 5 years
    Make sure you make your parent size relative to the viewport too. That way you can set ratio between the child and parent elements, and when page size changes both elements keep there ratio and scale responsively.
  • gothaf
    gothaf over 4 years
    @slaviboy I feel that your above example might be the solution to my problem, but unfortunately I am missing something. I have an svg that scales on window resize, and some divs that don't. I want them to scale all together and keep their relative positions. I tried setting the top property like this top: calc(var(--container-height) * 5%); with no success. Is there a way to acheive this? Also can you explain, what is the purpose of the transform property on the middle class? Here is a blitz of what I am trying to do.. <stackblitz.com/edit/lock-resizing-divs-wsemvn>
  • Roshan Khandelwal
    Roshan Khandelwal over 3 years
    I am using Angular and this helped me
  • ThomasRones
    ThomasRones about 3 years
    Can you add the JS you used to get the width?
  • DeoxyribonucleicAcid
    DeoxyribonucleicAcid about 3 years
    That is relative to the viewport, not the parent element.
  • thomasrutter
    thomasrutter almost 3 years
    Instead of taking a min(), you can use the vmin (viewport min) unit, which is another unit like vw and vh but is based on the shorter of the width and height of the viewport.
  • thomasrutter
    thomasrutter almost 3 years
    My guess is because the question is asking for something different - OP wants to have a text string, and size the text relative to the parent element's width. While you can use vw to size the text according to the viewpoint width, you can't do it according to the parent element width. So I don't think what OP wants is possible without modifying their approach, as most answers are suggesting. But I think they're downvoted because they don't provide exactly what OP wanted.
  • Patanjali
    Patanjali over 2 years
    There is a way to do it in pure css, but it is verbose. See my answer