In JavaScript/jQuery, how can I scale a varying-length line of text inside a fixed-width Div so that the one line always fits inside the Div (as one line)?
-
Yes, I want it to scale the font size based on how many letters are in the text so that it always fits as one line in the Div. – Stephen Watkins Nov 12 '10 at 15:02
-
May be the same as http://stackoverflow.com/questions/4131844 ? – Mic Nov 12 '10 at 15:09
-
@StephenWatkins I know this is an old question, but I recommend you checking my answer. – Hoffmann Jul 01 '13 at 16:21
-
https://github.com/rikschennink/fitty – Lance May 12 '22 at 02:59
20 Answers
This is somewhat of a hack, but will do what you want.
<div id="hidden-resizer" style="visibility: hidden"></div>
Place this at the bottom of your page, where it will not be moving other elements on the page.
Then do this:
var size;
var desired_width = 50;
var resizer = $("#hidden-resizer");
resizer.html("This is the text I want to resize.");
while(resizer.width() > desired_width) {
size = parseInt(resizer.css("font-size"), 10);
resizer.css("font-size", size - 1);
}
$("#target-location").css("font-size", size).html(resizer.html());

- 1,461
- 12
- 13
-
16Great answer, +1. A refinement would be to add the `#hidden-resizer` div using jQuery, to avoid mucking up the semantics of the HTML. `$('', {id: 'hidden-resizer'}).hide().appendTo(document.body);` – lonesomeday Nov 12 '10 at 15:22
-
-
5+1 This is great. Also, I like it when people prove that things are not impossible ;-) – Stephen Watkins Nov 12 '10 at 15:35
-
8This approach is VERY slow, each time the element font-size changes the element is redrawed and this can freeze the user browser if you use it periodically. I recommend checking my answer and my jQuery plugin that solves this problem in a better way: https://github.com/DanielHoffmann/jquery-bigtext – Hoffmann Jul 01 '13 at 16:23
-
2-1 for wrong HTML element. You should use a not a. The width of the will always be equal to the real width of the word inside the . The width of the– Kawd Jan 23 '14 at 11:44will always be equal to the width of the if left undefined, regardless of the actual width of the word inside the. Use .
-
lol. If you really want to search, at least use binary search. And don't forget to `removeChild()` at first and add it back later. – Chen Jun 20 '14 at 05:11
-
-
Nice answer!. but what if I want to resize something that is sometimes smaller than the desired width (and sometimes bigger) – frankelot Sep 15 '14 at 17:58
HTML:
<div class="box" style="width:700px">This is a sentence</div>
<div class="box" style="width:600px">This is a sentence</div>
<div class="box" style="width:500px">This is a sentence</div>
<div class="box" style="width:400px">This is a sentence</div>
JavaScript:
$( '.box' ).each(function ( i, box ) {
var width = $( box ).width(),
html = '<span style="white-space:nowrap"></span>',
line = $( box ).wrapInner( html ).children()[ 0 ],
n = 100;
$( box ).css( 'font-size', n );
while ( $( line ).width() > width ) {
$( box ).css( 'font-size', --n );
}
$( box ).text( $( line ).text() );
});
Live demo: http://jsfiddle.net/e8B9j/2/show/
Remove "/show/" from the URL to view the code.

- 4,732
- 6
- 28
- 29

- 182,163
- 62
- 281
- 385
-
-
Demo is fantastic, thanks! One thing I found though: using .css(width) to fetch the width of elements fails with short lines of text (in my case at least). This is because the values returned by .css(width) have 'px' appended to them. I use .width() to fetch widths instead, which returns numbers better suited to mathematic calculations. – Jonathan Nicol Aug 23 '11 at 01:53
-
@Jonathan Thanks. I've incorporated this into my answer. Btw, I also heavily re-factored my code - this new version is shorter and more readable. – Šime Vidas Aug 23 '11 at 17:27
-
1If got a Problem with your code, $( line ).width() always return 0 for me. – Frederick Behrends Oct 14 '11 at 17:20
-
@FrederickBehrends Can you provide your code (you can use jsfiddle)? – Šime Vidas Oct 14 '11 at 17:21
-
@FrederickBehrends IE requires the close tag when using wrapInner. I have update the answer to include this. – Chad DeShon Nov 23 '11 at 00:24
-
@Chat It works in IE8 and IE7. What version do you mean? **Live demo:** http://jsfiddle.net/5AaYP/ – Šime Vidas Nov 23 '11 at 00:31
-
Here's an example that is closer to the posted code: http://jsfiddle.net/5AaYP/3/. It works in Chrome, but to get it to work in IE8 (WinXP) you have to add the closing span tag. I don't know why your simpler example works, but this one doesn't. – Chad DeShon Nov 30 '11 at 15:26
-
@ChadDeShon Your demo doesn't work because the text content is to small so even a font-size of 100px won't overflow the container. Set `n` to a higher number... **Live demo:** http://jsfiddle.net/5AaYP/5/ – Šime Vidas Nov 30 '11 at 16:12
-
jsfiddle.net/5AaYP/5 doesn't work in IE8. It will start working if you close the span tag. Here's a discussion on jQuery's website: http://bugs.jquery.com/ticket/7355. – Chad DeShon Dec 01 '11 at 16:45
-
3Instead of using a while loop, calculate the proportions directly: $(box).css('font-size', width/$(line).width()*100-1); http://jsfiddle.net/e8B9j/411/ – teambob Sep 21 '12 at 04:09
-
was struggling with fittextjs, bigtext.js etc, this one works like a charm! – Cheong D Mun Pong May 20 '14 at 08:13
-
what does the last line do? Seems like it's appentidng a text, but it's obviously already appended in to elements, so why is it here? Edit: Ok got it, it's here to get rid of span wrapping element. – Max Yari Apr 07 '15 at 23:57
-
Works great. I changed start value of n to $(box).height(), because my boxes also have limited height. Otherwise short strings get too large for the box. – Christian Nov 27 '15 at 07:33
-
Thanks! One thing though: hyphens can cause line breaks, replace them with a non-breaking hyphen: `‑` to get the best result. – Jon List Apr 13 '16 at 20:58
I have written a jQuery plugin to do this:
http://michikono.github.com/boxfit
The plugin will scale the text both horizontally and vertically to the maximum available size inside the box and then center it.
The only thing you need to do is define a div with text inside it:
<div id="scale">some text</div>
And then call:
$('#scale').boxfit()
The method will accept some arguments to disable/enable text wrapping and centered alignment.

- 316
- 2
- 6
For new Browsers you can use Inline-SVG. This can be scaled like an image via CSS .. !
.smallerVersion{
max-width: 50%
}
<!DOCTYPE html>
<html>
<head>
<title>Scale SVG example</title>
</head>
<body>
<h2>Default version:</h2>
<svg viewBox="0 0 240 80" xmlns="http://www.w3.org/2000/svg">
<style>
.small { font: italic 13px sans-serif; }
.heavy { font: bold 30px sans-serif; }
/* Note that the color of the text is set with the *
* fill property, the color property is for HTML only */
.Rrrrr { font: italic 40px serif; fill: red; }
</style>
<text x="20" y="35" class="small">My</text>
<text x="40" y="35" class="heavy">cat</text>
<text x="55" y="55" class="small">is</text>
<text x="65" y="55" class="Rrrrr">Grumpy!</text>
</svg>
<h2>Scaled version:</h2>
<svg class="smallerVersion" viewBox="0 0 240 80" xmlns="http://www.w3.org/2000/svg">
<style>
.small { font: italic 13px sans-serif; }
.heavy { font: bold 30px sans-serif; }
/* Note that the color of the text is set with the *
* fill property, the color property is for HTML only */
.Rrrrr { font: italic 40px serif; fill: red; }
</style>
<text x="20" y="35" class="small">My</text>
<text x="40" y="35" class="heavy">cat</text>
<text x="55" y="55" class="small">is</text>
<text x="65" y="55" class="Rrrrr">Grumpy!</text>
</svg>
</body>
</html>
(width: 100%;
)

- 961
- 1
- 11
- 23
Most of the other answers use a loop to reduce the font-size until it fits on the div, this is VERY slow since the page needs to re-render the element each time the font changes size. I eventually had to write my own algorithm to make it perform in a way that allowed me to update its contents periodically without freezing the user browser. I added some other functionality (rotating text, adding padding) and packaged it as a jQuery plugin, you can get it at:
https://github.com/DanielHoffmann/jquery-bigtext
simply call
$("#text").bigText();
and it will fit nicely on your container.
See it in action here:
http://danielhoffmann.github.io/jquery-bigtext/
For now it has some limitations, the div must have a fixed height and width and it does not support wrapping text into multiple lines.
Edit2: I have now fixed those problems and limitations and added more options. You can set maximum font-size and you can also choose to limit the font-size using either width, height or both (default is both). I will work into accepting a max-width and max-height values in the wrapper element.

- 14,369
- 16
- 76
- 91
I don't know of an exact way, but here's an approximation:
var factor = 1/3; // approximate width-to-height ratio
var div = $('#mydiv');
div.css('font-size', div.width() / (div.text().length * factor) + 'px');
You will need to adjust factor
based on the font you are using. 1/3 seems to work okay for Times New Roman.

- 69,683
- 7
- 133
- 150
Modified version of @sworoc with the support of the target class
function resizeText(text, size, target) {
var fontSize = 0;
var resizer = $('<span>');
resizer.html(text).hide();
resizer.attr('class', target.attr('class'));
$('body').append(resizer);
while(resizer.width() < size) {
fontSize++
resizer.css("font-size", fontSize);
}
target.css('font-size', fontSize).html(text);
resizer.remove();
}
Usage
resizeText("@arunoda", 350, $('#username'));

- 2,516
- 1
- 25
- 30
Inside your div, have the text in a span that has no padding. Then the span's width will be the length of the text.
Untested code for finding the correct font-size to use:
var objSpan = $('.spanThatHoldsText');
var intDivWidth = $('.divThatHasAFixedWidth').width();
var intResultSize;
for (var intFontSize = 1; intFontSize < 100; intFontSize++)
objSpan.css('font-size', intFontSize);
if (objSpan.width() > intDivWidth) {
intResultSize = intFontSize - 1;
break;
}
}
objSpan.css('font-size', intResultSize);

- 1,089
- 1
- 13
- 28
-
Great minds sometimes think alike, yours might be better by using a number to only set the font-size, whereas mine I had it parsing the value from font-size. Not sure what will be most reliable. – sworoc Nov 12 '10 at 15:29
-
it would be nice if it also checks for height. http://jsfiddle.net/ad5pf/1/ if (objSpan.width() > intDivWidth || objSpan.height() > intDivHeight) { intResultSize = intFontSize - 1; break; } – user566245 Dec 28 '11 at 18:55
Here is a coffeescript solution I came up with. I clone the element that is needing to have it's font resized then remove that at the end of the calculation. To increase performance I have some code that only executes the calculation after resizing has stopped for 200ms.
Tag elements with class autofont for this to be done unobtrusively.
#
# Automagically resize fonts to fit the width of the
# container they are in as much as possible.
#
fixfonts = ->
scaler = 1.2
for element in $('.autofont')
size = 1
element = $(element)
desired_width = $(element).width()
resizer = $(element.clone())
resizer.css
'font-size': "#{size}em"
'max-width': desired_width
'display': 'inline'
'width': 'auto'
resizer.insertAfter(element)
while resizer.width() < desired_width
size = size * scaler
resizer.css
'font-size': "#{size}em"
$(element).css
'font-size': "#{size / scaler }em"
resizer.remove()
$(document).ready =>
fixfonts()
timeout = 0
doresize = ->
timeout--
if timeout == 0
fixfonts()
$(window).resize ->
timeout++
window.setTimeout doresize, 200

- 30,949
- 17
- 114
- 217
-
The timeout code is a nice idea, but there are better ways of doing it. `timeoutId = null; $(window).resize -> { window.clearTimeout(timeoutId); timeoutId = window.setTimeout fixfonts, 200; }` – Peter Taylor Dec 13 '13 at 23:31
I had a similar issue, which made me write my own plugin for this. One solution is to use the shrink-to-fit-approach, as described above. However if you have to fit multiple items or are concerned with performance, e.g., on window resize, have a look at jquery-quickfit.
It meassures and calculates a size invariant meassure for each letter of the text to fit and uses this to calculate the next best font-size which fits the text into the container.
The calculations are cached, which makes it very fast (there is virtually no performance hit from the 2nd resize on forward) when dealing with multiple texts or having to fit a text multiple times, like e.g., on window resize.

- 284
- 4
- 5
Here's my modification to @teambob's suggestion (in above comments) that takes also the height of the container into account:
<div class="box" style="width:700px; height:200px">This is a sentence</div>
<div class="box" style="width:600px; height:100px">This is a sentence</div>
<div class="box" style="width:500px; height:50px">This is a sentence</div>
<div class="box" style="width:400px; height:20px">This is a sentence</div>
And then..
$('.box').each(function(i, box) {
var width = $(box).width(),
height = $(box).height(),
html = '<span style="white-space:nowrap">',
line = $(box).wrapInner(html).children()[0],
maxSizePX = 2000;
$(box).css('font-size', maxSizePX);
var widthFontSize = Math.floor(width/$(line).width()*maxSizePX),
heightFontSize = Math.floor(height/$(line).height()*maxSizePX),
maximalFontSize = Math.min(widthFontSize, heightFontSize, maxSizePX);
$(box).css('font-size', maximalFontSize);
$(box).text($(line).text());
});
See Fiddle
I couldn't figure out how to add this to sworoc's post but i thought i would share anyway: Lonesomeday's solution gets messed up if you are using any sort of AJAX navigation. I modified it slightly to:
if ($('#hidden-resizer').length == 0){
$('<div />', {id: 'hidden-resizer'}).hide().appendTo(document.body);
}

- 2,238
- 2
- 30
- 37
-
1You should probably just post it as another comment on the answer. – Nightfirecat Nov 29 '11 at 20:46
-
Here is my solution: I measure the text in a new div within the provided div, so that the styling should be inherited. Then I insert the text into the div with a span to set the font-size. It will max out to the default font size but will shrink to fit.
It does not loop: it only draws the text once in a throw-away div before drawing directly to the supplied div. See @Hoffmann answer - I just did not like an entire 'plugin' to answer the question.
requires jquery.
var txt = txt || {}
txt.pad_factor = 1.1;
txt.insertText_shrinkToFit = function(div,text)
{
var d = txt.cache || $('<div></div>');
txt.cache = d;
d.css('white-space','nowrap');
d.css('position','absolute');
d.css('top','-10000px');
d.css('font-size','1000px');
var p = $(div);
var max_w = parseInt(p.css('max-width')) || p.width();
var max_h = parseInt(p.css('font-size'));
p.append(d);
d.html(text);
var w = d.width() * txt.pad_factor;
d.remove();
var h = Math.floor(max_w*1000/w);
var s = ( max_h < h ? max_h : h ) + "px";
p.html('<SPAN style="font-size:' + s + '">' + text + '</SPAN>');
}
For example:
<html><head><script src=http://code.jquery.com/jquery-latest.min.js></script>
<script>/*insert code, from above, here.*/</script></head><body>
<div id=mysmalldiv style="max-width:300px;font-size:50px"></div>
<script>
txt.insertText_shrinkToFit("#mysmalldiv","My super long text for this div.");
</script>
</body></html>
For testing: this is how I found that I needed the 1.1 pad_factor; which you may tune to your needs.
<div id=mytestdiv style="max-width:300px;font-size:50px"></div>
<script>
var t = "my text ";
var i = 0;
var f = function() {
t += i + " ";
txt.insertText_shrinkToFit("#mytestdiv",t);
i++;
if(i < 100)
setTimeout(f,1000);
}
f();
</script>
Note: this is assuming px font-size. I have not tested with em or pt.

- 158
- 8
There is a great way to do this for single line texts, like headers and such, in pure CSS:
h1{
font-size: 4.5vw;
margin: 0 0 0 0;
line-height: 1em;
height: 1em;
}
h1:after{
content:"";
display: inline-block;
width: 100%;
}
Make sure your font-size stays small enough to keep the header 1 line. Using 'vw' (viewport width) instead of 'px' makes it very easy to do this and scale at the same time. viewport width has the tendency to get nasty when you make your browser window very big, many sites use this to keep the site under a certain width on really wide screens:
body{
max-width: 820px;
margin: 0 auto;
}
To make sure your font is not based on how big the viewport window is once the rest of your site stops scaling use this:
@media(min-width:820px){
h1{
font-size: 30px;
}
}

- 11,519
- 8
- 71
- 80
you can do multiple things like
overflow:hidden
this cuts the extra line
overflow:auto
// this shows the scroll bar
see this
http://www.w3schools.com/Css/pr_pos_overflow.asp
try to do this //check the length of the text
if($('#idfortext').length>sometthing)
{
var fontsize=10;
}
$('#yourid').css('font-size',fontsize)

- 15,671
- 15
- 64
- 91
-
Thanks, but this is not what I'm looking for. I need the line of text to always fit a certain width. This means some kind of technique for actually changing the font size or scaling the contents of the div. – Stephen Watkins Nov 12 '10 at 15:04
-
@stjowa , you can achieve that , you know how much text with a particular font size fits the div. you can calculate the length of text and if it cross some lenght you can change the font using jquerys$('#yourid').css('font-size',desiredfontsize),this you can do in document.ready. – kobe Nov 12 '10 at 15:07
Im not sure there is any accurate way to measure text's width in pixels (which is what you're really looking for at the root of your problem), as each browser may display the fonts differently. You might want to try using this CSS code, in addition to doing some "Fuzzy" resizing based on the number of letters in the sentence. You can try using a fixed-width font (or style) to display the text so that each character takes up the same amount of space. This way, you can make a best guess, and the CSS will at least give you a nice "..." before cropping the text, if needed.
.truncate
{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

- 28,798
- 20
- 92
- 109
This is what I found today:
- Set a really big fake font-size (f) to the target text
measure width (w) height (h) of the text container and divide by font-size (f):
iw = w/f
ih = h/f
Divide main container width (W) by iw and main container height (H) by ih:
kw = W/iw
kh = H/ih
Pick lowest between kw and kh: that is the wanted FontSize.
https://jsfiddle.net/pinkynrg/44ua56dv/
function maximizeFontSize($target) {
var testingFont = 1000;
$target.find(".text-wrapper").css("font-size", testingFont+"px");
var textWidth = $(".text-wrapper").width()/1000;
var textHeight = $(".text-wrapper").height()/1000;
var width = $(".container").width();
var height = $(".container").height();
var kWidth = width/textWidth;
var kHeight = height/textHeight;
var fontSize = kWidth < kHeight ? kWidth : kHeight;
// finally
$(".text-wrapper")
.css("font-size", fontSize+"px")
.css("line-height", height+"px");
}

- 2,484
- 2
- 21
- 52
I'm using vanilla js. A solution that worked for me for changes in horizontal sizing is when I create the div, I set a default font size % for a given width. In my case, I'm wrapping the div in a bigger class, but for these purposes, you could use:
document.getElementById("mydiv").fontScale = {scaleVal: scaleFactor, defaultWidth: defaultWidth}
the scaleFactor is the size of the font (in percentage) that you want for a given width (the default width). Then when I get a resize event:
let myDiv = document.getElementById("mydiv");
let width = myDiv.offsetWidth;
myDiv.style[fontSize] = String(width/myDiv.fontScale.defaultWidth * myDiv.fontScale.scaleFactor * 100) + "%";

- 23
- 6
I worked off a few posts here and made a jQuery plugin out of it. I found that starting from the bottom and going up wasn't very performant, so I make the assumption that the current font-size is close, and worked from there.
$.fn.fitTextToWidth = function(desiredWidth) {
// In this method, we want to start at the current width and grow from there, assuming that we are close to the desired size already.
var $el = $(this);
var resizer = $('<'+$el.get(0).tagName+' />').css({'vsibility':'hidden','position':'absolute','left':'-9999px','display':'inline'}).html($el.html());
resizer.appendTo(document.body);
var size = parseInt($el.css('font-size'));
resizer.css('font-size',size+'px');
var growing = desiredWidth > resizer.width() ? true : false;
var adder = growing ? 1 : -1;
do {
size += adder;
resizer.css('font-size',size+'px');
} while(((growing && resizer.width()<desiredWidth) || (!growing && resizer.width()>desiredWidth)) && size>10 && size<100);
if (growing)
size -= 2; //we never want to go over
resizer.remove();
$el.css('font-size',size+'px');
}
// Example use:
$('#main h1').fitTextToWidth(350);
The only gotcha with this is that it assumes the CSS for the element is global and only applied to the element type. In other words, it creates a tag of the same name in and assumes it will have the same CSS attributes as the element we want to change. If this isn't true for you, just modify the line where resizer
gets created.

- 770
- 1
- 8
- 13
Simple solution
<div class="fitt-text"><span>text</span></div>
js
$(".fitt-text").css('font-size', '1vw');
var cw = $(".fitt-text").width();
var w = $(".fitt-text span").width();
var f = cw/w;
$(".fitt-text").css('font-size', f + 'vw');

- 21
- 3