如何根据容器大小设置字体大小?

我有一个容器,它具有% 的宽度和高度,因此它可以根据外部因素进行调整。我希望容器内的字体是一个相对于容器大小的恒定大小。有没有什么好的方法可以用 CSS 来做到这一点?font-size: x%只能根据原始字体大小(即100%)调整字体大小。

112834 次浏览

It cannot be accomplished with css font-size

Assuming that "external factors" you are referring to could be picked up by media queries, you could use them - adjustments will likely have to be limited to a set of predefined sizes.

You may be able to do this with CSS3 using calculations, however it would most likely be safer to use JavaScript.

Here is an example: http://jsfiddle.net/8TrTU/

Using JS you can change the height of the text, then simply bind this same calculation to a resize event, during resize so it scales while the user is making adjustments, or however you are allowing resizing of your elements.

If you want to set the font-size as a percentage of the viewport width, use the vwunit:

#mydiv { font-size: 5vw; }

The other alternative is to use SVG embedded in the HTML. It will just be a few lines. The font-size attribute to the text element will be interpreted as "user units", for instance those the viewport is defined in terms of. So if you define viewport as 0 0 100 100, then a font-size of 1 will be one one-hundredth of the size of the svg element.

And no, there is no way to do this in CSS using calculations. The problem is that percentages used for font-size, including percentages inside a calculation, are interpreted in terms of the inherited font size, not the size of the container. CSS could use a unit called bw (box-width) for this purpose, so you could say div { font-size: 5bw; }, but I've never heard this proposed.

I've given a more detailed answer of using vw with respect to specific container sizing in this answer, so I won't just repeat my answer here.

In summary, however, it is essentially a matter of factoring (or controlling) what the container size is going to be with respect to viewport, and then working out the proper vw sizing based on that for the container, taking mind of what needs to happen if something is dynamically resized.

So if you wanted a 5vw size at a container at 100% of the viewport width, then one at 75% of the viewport width you would probably want to be (5vw * .75) = 3.75vw.

Another js alternative:

Working Example

fontsize = function () {
var fontSize = $("#container").width() * 0.10; // 10% of container width
$("#container h1").css('font-size', fontSize);
};
$(window).resize(fontsize);
$(document).ready(fontsize);

Or as stated in torazaburo's answer you could use svg. I put together a simple example as a proof of concept:

SVG Example

<div id="container">
<svg width="100%" height="100%" viewBox="0 0 13 15">
<text x="0" y="13">X</text>
</svg>
</div>

I used Fittext on some of my projects and it looks like a good solution to a problem like this.

FitText makes font-sizes flexible. Use this plugin on your fluid or responsive layout to achieve scalable headlines that fill the width of a parent element.

Here is the function:

document.body.setScaledFont = function(f) {
var s = this.offsetWidth, fs = s * f;
this.style.fontSize = fs + '%';
return this
};

Then convert all your documents child element font sizes to em's or %.

Then add something like this to your code to set the base font size.

document.body.setScaledFont(0.35);
window.onresize = function() {
document.body.setScaledFont(0.35);
}

http://jsfiddle.net/0tpvccjt/

You can also try this pure CSS method:

font-size: calc(100% - 0.3em);

If you want to scale it depending on the element width, you can use this web component:
https://github.com/pomber/full-width-text

Check the demo here:
https://pomber.github.io/full-width-text/

The usage is like this:

<full-width-text>Lorem Ipsum</full-width-text>

I had a similar issue but I had to consider other issues that @apaul34208 example did not tackle. In my case;

  • I have a container that changed size depending on the viewport using media queries
  • Text inside is dynamically generated
  • I want to scale up as well as down

Not the most elegant of examples but it does the trick for me. Consider using throttling the window resize (https://lodash.com/)

var TextFit = function(){
var container = $('.container');
container.each(function(){
var container_width = $(this).width(),
width_offset = parseInt($(this).data('width-offset')),
font_container = $(this).find('.font-container');
	

if ( width_offset > 0 ) {
container_width -= width_offset;
}
                

font_container.each(function(){
var font_container_width = $(this).width(),
font_size = parseFloat( $(this).css('font-size') );


var diff = Math.max(container_width, font_container_width) - Math.min(container_width, font_container_width);
 

var diff_percentage = Math.round( ( diff / Math.max(container_width, font_container_width) ) * 100 );
      

if (diff_percentage !== 0){
if ( container_width > font_container_width ) {
new_font_size = font_size + Math.round( ( font_size / 100 ) * diff_percentage );
} else if ( container_width < font_container_width ) {
new_font_size = font_size - Math.round( ( font_size / 100 ) * diff_percentage );
}
}
$(this).css('font-size', new_font_size + 'px');
});
});
}


$(function(){
TextFit();
$(window).resize(function(){
TextFit();
});
});
.container {
width:341px;
height:341px;
background-color:#000;
padding:20px;
}
.font-container {
font-size:131px;
text-align:center;
color:#fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


<div class="container" data-width-offset="10">
<span class="font-container">£5000</span>
</div>

https://jsfiddle.net/Merch80/b8hoctfb/7/