3

So I am working on a function that resizes font size so the text fills as much of the container as possible across multiple lines without overflow. For instance,

I want the text to cover as much of the 1200px of area within the div without overflowing as possible. This script does this on resize but not on load.

$(document).ready(textFill);
$(window).resize(textFill);

function textFill() {
  $(".textFill").each(function() {
    var
      $text = $(this),
      $parent = $text.parent();

    var
      textW = $text.width(),
      textH = $text.height(),
      parentW = $parent.width(),
      parentH = $parent.height(),
      ratio = (parentW + parentH) / (textW + textH);

    var
      originalSize = parseFloat($text.css('font-size')),
      newSize = originalSize * (.9 * ratio);

    $text.css("font-size", newSize);

  });
}
#container {
  width: 400px;
  height: 300px;
  border: 1px solid blue;
}
.textFill {
  display: inline;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <h1 class="textFill">Make this fit as large as possible.</h1>
</div>

When I resize, it fills the container, but onload it does not seem to fire.

EDIT: The function does fire upon document ready, however it does not account for the fully loaded dimensions of the parent. Instead it measures the parents height as the height of the text.

Additionally, I am not sure if the resize event is the one I'd like to use, since it should only adjust font size, maybe I should only execute on change of parent dimensions, is that possible?

Here is the fiddle..

Ruslan López
  • 4,433
  • 2
  • 26
  • 37
Chris
  • 767
  • 4
  • 8
  • 22
  • For some reason your function works on the second time it gets called. e.g. if you call your function twice in document.ready it will work. Im working on why it acts like that – A Web-Developer May 31 '15 at 23:51
  • Also works with just a little delay added. Does not need to run twice to work. It seems as if the script is executing to quickly: http://jsfiddle.net/nz7h2858/46/ – HaukurHaf May 31 '15 at 23:53
  • 3
    If you run it without calling the function the text is even smaller. Your function makes it a bit bigger with the first call, then bigger still on the 2nd, around the third call or so it reaches roughly an equilibrium. It has nothing to do with when or how it's called, it's the logic of the function, it takes a few calls to even out, which makes sense because it's based on the "original size" which changes with each call.. – James Montagne May 31 '15 at 23:55
  • 3
    Following up on @JamesMontagne comment, you can watch the variables change by repeatedly clicking the button here: http://jsfiddle.net/2Lojj87t/1/ – Rick Hitchcock Jun 01 '15 at 00:14
  • @JamesMontagne the button fiddle illustrates how it takes multiple firings to reach "equilibrium", I guess my question is why isn't the correct value – Chris Jun 01 '15 at 06:11
  • You can combine ready and resize like this `$(window).on('resize',function(){ ... }).trigger('resize');` – davidcondrey Jun 09 '15 at 08:49
  • Have you seen that? http://stackoverflow.com/questions/687998/auto-size-dynamic-text-to-fill-fixed-size-container – Beamer Jun 09 '15 at 15:26
  • @Chris Check my answer you can do this using 'DOMContentLoaded' – Daniel Jun 10 '15 at 20:25

8 Answers8

3

Your function in the fiddle actually runs the first time, which you can see if you specify a font-size for .textFill.. say 10px. You'll see that it does scale up to the max width even on the first call.

The main problem is that you re-read the font-size (originalSize) on every resize event (every time the function is called) and then calculate again with the new size. Only after the max is reached you have the result you expected.

The problem however has been dealt with before and because I don't really deserve any credit for the answer, I'll just link to it here. Make sure to check out the gist that is included in that answer!

Community
  • 1
  • 1
BenMann
  • 248
  • 3
  • 15
1

It is because of

textH = $text.height()

which returns a different value every time you resize and the text keeps growing in height making the value of newSize bigger. This is why if you call the function more times like this:

     textFill();
     textFill();
     textFill();
     textFill();
     textFill();

it will make the text bigger. The solution is to control the height in css.

Claudiu Creanga
  • 8,031
  • 10
  • 71
  • 110
  • This is correct, but you can't control the height with css because that's the whole point. The idea behind the function is to compare the size of the `h1` with the size of the `div` to be able to increase the font size of the `h1` to make the h1 content the same height as the div. To "fill" the div. – James Montagne Jun 01 '15 at 00:13
  • @James Montagne then you should set the text height depending on the parent height. Something like textH = parent dimensions ratio – Claudiu Creanga Jun 01 '15 at 00:43
  • 1
    @Claudiu, could you follow up your comment on how setting the text height to the parent ratio would fill the container? – Chris Jun 01 '15 at 06:07
1

The "textFill" function did fire on document.ready event. You can simply prove this by adding some CSS style to make it visible, e.g

$text.css({"font-size", newSize, "color": "red"});

I did confuse about the way the "ratio" was calculated. If you just tried to make the "h1" font big enough to fill the outer container, the only thing to consider is to keep enough vertical space to avoid the "h1" overlapping out of the "div" box. So that the ratio could be something like:

var ratio = parentH / textH;

Also there's a magic number of "0.9" in the "newSize" calculation. I have to say I did not know how it goes out :).

XuChu LIU
  • 238
  • 3
  • 11
1

you are calling textFill() function on window resize event only.

if you want to call this function on load you can implement as below.

$(window).load(function() {

  textFill()

});

To call your function on both events load and resize events. you can use below snippet.

$(window).on("load resize",function(){

  textFill()

})
Daniel
  • 598
  • 1
  • 6
  • 23
Srinivas
  • 133
  • 6
1

Just some thoughts and a plan to do this:

First off, you are fixing the width of the container. Therefore, re-sizing the window does nothing. If your container could change size, you may want to re-size, and there is plenty of examples on how to do that already available. For now, though, you can remove the resize() line. It just adds confusion.

Second, since you are word wrapping, the calculation isn't easy. One word could determine the font size (so it doesn't become bigger than the container width). You could probably figure this out by setting the font size to the container height and finding out the longest word, than calculating a max font size from that. The other possibility is that the font size will be limited to however many lines the text wraps. You possibly could come up with an initial guess by looking at line spacing and how wide the text is at 1px font size, but you ultimately are going to have to try a few font sizes to see how many lines the text actually wraps into. For that reason, I suggest writing a loop.

You don't want the trials visible, so you will have to learn to make it invisible or move it off screen in such a way that the size is still calculated by the browser but nothing changes in the document or the scrollbars.

Third, I would start with a minimum and maximum guess of font size (1 pixel and the height of the container), then I would pick a value in the middle, try it, find out if it fits in the container (width and height) or not, and if it does, make it the min value, and if it does not, make it the max (if it turns out to be equal, you are done). I would keep doing this until the max and min are within a small value of each other (say, 1%), then I would choose the min and be done with it. I would also put a maximum number of guesses on it (say, 25), and if I didn't get an answer within those, I would also choose the min and be done with it (browsers may not always behave consistently, so this is a "just in case" sort of situation).

Code:

 textFill();

 function textFill() {
     $(".textFill").each(function () {
         var
         $text = $(this),
             $parent = $text.parent();

         var
         parentW = $parent.width(),
             parentH = $parent.height();

         var minFontSize = 1;
         var maxFontSize = parentH;

         for (loop = 0; loop < 25; ++loop) {
             var newFontSize = (minFontSize + maxFontSize) / 2;
             $text.css("font-size", newFontSize);
             var textW = $text.width();
             var textH = $text.height();

             if (textW > parentW || textH > parentH) {
                 maxFontSize = newFontSize;
             } else {
                 minFontSize = newFontSize;
             }

             if ((maxFontSize - minFontSize) * 100 < minFontSize) break;
         }

         $text.css("font-size", minFontSize);
     });
 }

fiddle: http://jsfiddle.net/tncmrya6/

Guy Schalnat
  • 1,697
  • 15
  • 26
0

If I understood well, you're looking to fit text to div by width and height. Maybe you should just remove .9 from calculations. Check this to see if this is what you searched for.

$(document).ready(textFill);
$(window).resize(textFill);

function textFill() {
$(".textFill").each(function() {
var
  $text = $(this),
  $parent = $text.parent();

var
  textW = $text.width(),
  textH = $text.height(),
  parentW = $parent.width(),
  parentH = $parent.height(),
  ratio = (parentW + parentH) / (textW + textH);
  console.log(ratio);

var
  originalSize = parseFloat($text.css('font-size')),
  newSize = originalSize * ratio;//HERE'S BIG CHANGE :)

$text.css("font-size", newSize);

});
}
Marko Vasic
  • 690
  • 9
  • 27
0

use

window.onload = function() {
    textFill();
}

you don't really need specifically to use jQuery to handle stuff that window handles natively.

rokyed
  • 420
  • 5
  • 9
0

If you want your script to execute onload you could do this. Works every time.

<script type='text/javascript'>
window.addEventListener('DOMContentLoaded', function () { 
    textFill(); //Call your function here
});

</script>
Daniel
  • 598
  • 1
  • 6
  • 23