2

I hate doing this. This is THE small piece to end a large project and my mind is fried...

Here's the code. It checks to see if an element is overflowing and resizes the font. It is supposed to resize it until it doesn't overflow. The condition for the loop seems to be ignored and the browser freezes... I feel that I'm missing something crucial in how jQuery works here.

$.fn.fontBefitting = function() {
    var _elm = $(this)[0];
    var _hasScrollBar = false; 
    while ((_elm.clientHeight < _elm.scrollHeight) || (_elm.clientWidth < _elm.scrollWidth)) {
        var fontSize = $(this).css('fontSize');
        fontSize = parseInt(fontSize.substring(0,fontSize.length-2))*0.95;
        $(this).css('fontSize',fontSize+'px');          
    }

}

Thanks in advance.

14
  • 6
    Where is the 'while' loop? Commented Sep 12, 2011 at 20:31
  • There is no while loop? Is this the matrix? Commented Sep 12, 2011 at 20:32
  • Whoops, I posted it as a condition. Edited... Commented Sep 12, 2011 at 20:32
  • 2
    The "I had doing this" was referring to dumping a problem that I feel I should be able to figure out, on the community. It's one of those, problems where I feel I should know this. Commented Sep 12, 2011 at 20:36
  • 1
    @Eric: Actually $(this)[0] !== this because when you try to send a jQuery object to $(), it doesn't double wrap it, but instead gives you a new jQuery object referencing the same elements, so $(this)[0] === this[0]. Commented Sep 12, 2011 at 20:43

6 Answers 6

4

Change:

 fontSize = parseInt(fontSize.substring(0,fontSize.length-2))*0.95;

to:

 fontSize = parseInt(fontSize.substring(0,fontSize.length-2))-1;

Here's a Working Demo. When the font size reached 10px, 10*.95 was 9.5 which the browser was rounding up to 10px. Thus infinite loop.

Sign up to request clarification or add additional context in comments.

4 Comments

You comparisons are correct. but fontSize of 9.5 is returning back to 10.
No problem, I've been there. Looking at the same code for too long, knowing it's something I just can't see. I can't believe that guy told you to quit your job. That's not very classy. Glad I could help.
Now try it with this markup to see why @rpophessagr's code is still not right. Compare it with my fixed version here
When you sit across from a computer all day you can forget that the text you see was written by an actual someone else. I appreciate your help!
3

You need to step through your code in a debugger and actually check your condition values to make sure they are changing how you expect. My guess is _elm.clientHieght and _elm.clientWidth aren't actually changing.

1 Comment

They were changing, the code worked with a condition instead of a loop.
1
var fontSize = $(this).css('fontSize');
fontSize = parseInt(fontSize, ...

The unit you get from font-size is not necessarily (a) pixels, nor (b) the same unit as you put in.

It's not specified what unit is used to return the length, but in many browsers it is currently points. Since points are smaller than pixels, the integer length will be longer, so you can quite easily keep on *0.95ing it forever.

Even if it were pixels, the browser could round the size up to the nearest pixel, making 95%-size the same size as 100% when you read it back. Or you could hit the minimum-font-size setting and you wouldn't be able to reduce it any more.

So instead of reading the current font size back on each step, keep the pixel size you want in a variable and reduce that variable each time. Then if you reach a predetermined lower bound for the value of that variable, give up.

1 Comment

"The unit you get from font-size is not necessarily (a) pixels, nor (b) the same unit as you put in." When I debugged the solution it was in px, even though the font was set to 100%. Would this vary from site to site?
1

You are probably running into an endless loop because the font size doesn't actually change. E.g. if the font size found is 10px you will update it to become 9.5px which is probably rounded back to 10px by the browser. In that case nothing changes and the function will keep running forever.

1 Comment

I appreciate the help, that IS the answer. @abstract got the green check because of the working example.
1

You've got an unrelated problem when you do

$('div').fontBefitting()

This will make the text in the first div fit it's box, then make the font size of all the other divs the same as the first. This does not sound like intended behaviour. You would hope that it would make each div resize its text and only its text to fit.

You need to change your code to this:

$.fn.fontBefitting = function() {
    /* $.fn.* runs on a jQuery object. Make sure to return it for chaining */
    return this.each(function() {
        var fontSize = parseInt($(this).css('fontSize'));
        while (this.clientHeight < this.scrollHeight ||
               this.clientWidth < this.scrollWidth) {
            fontSize--;
            $(this).css('fontSize', fontSize + 'px');          
        }
    });
}

4 Comments

Why the downvote? The OP's code was making false assumptions about how $.fn works, and how browsers handle font sizes.
I appreciate your effort and optimization but I imagine you were down voted because of your phrasing. I'd recommend for future edits to say: "Here are some ways you can optimize your code." Instead of: "Your code is badly written." I will happily use your code to improve mine. Thanks
@rpophessagr: It's not just optimization though, your code behaved incorrectly - calling $('div').fontBefitting() would make the text in the first div fit it's box, and make the font size of all the other divs the same as the first. Probably not intended behaviour.
+1, not only this fixes the problem elegantly, it fixes the mentioned bug and is optimized besides creating a new anonymous function on each call.
0

You're checking to see if the clientHeight or clientWidth are LESS than the scrollHeight or scrollWidth, and if they are you are REDUCING the font size? It will never converge under those circumstances. You want to INCREASE the font size.

1 Comment

I am reducing the font size so that it won't overflow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.