[jquery] resize font to fit in a div (on one line)

I wasn't in love with the other solutions out there, so, here's another one. It requires the tag you're resizing the text inside of:

  1. Be fixed height

  2. Not be so long that it'd overrun the boundaries at 10px - the idea being, you don't want it to shoot below that and resize text to become unreadable. Not an issue in our use case, but if it's possible in yours you'd want to give some thoughts to separately truncating before running this.

It uses a binary search to find the best size so I suspect it outperforms a lot of the other solutions here and elsewhere that just step the font-size down by a pixel over and over. Most browsers today support decimals in font sizes as well, and this script has some benefits there since it will get to within .1px of the best answer, whatever that is, even if it's a relatively long decimal. You could easily change the max - fontSize < .1 to some other value than .1 to get less precision for less CPU usage.

Usage:

$('div.event').fitText();

Code:

(function() {
    function resizeLoop(testTag, checkSize) {
        var fontSize = 10;
        var min = 10;
        var max = 0;
        var exceeded = false;

        for(var i = 0; i < 30; i++) {
            testTag.css('font-size', fontSize);
            if (checkSize(testTag)) {
                max = fontSize;
                fontSize = (fontSize + min) / 2;
            } else {
                if (max == 0) {
                    // Start by growing exponentially
                    min = fontSize;
                    fontSize *= 2;
                } else {
                    // If we're within .1px of max anyway, call it a day
                    if (max - fontSize < .1)
                        break;

                    // If we've seen a max, move half way to it
                    min = fontSize;
                    fontSize = (fontSize + max) / 2;
                }
            }
        }

        return fontSize;
    }

    function sizeText(tag) {
        var width = tag.width();
        var height = tag.height();

        // Clone original tag and append to the same place so we keep its original styles, especially font
        var testTag = tag.clone(true)
        .appendTo(tag.parent())
        .css({
            position: 'absolute',
            left: 0, top: 0,
            width: 'auto', height: 'auto'
        });

        var fontSize;

        // TODO: This decision of 10 characters is arbitrary. Come up
        // with a smarter decision basis.
        if (tag.text().length < 10) {
            fontSize = resizeLoop(testTag, function(t) {
                return t.width() > width || t.height() > height;
            });
        } else {
            testTag.css('width', width);
            fontSize = resizeLoop(testTag, function(t) {
                return t.height() > height;
            });
        }

        testTag.remove();
        tag.css('font-size', fontSize);
    };

    $.fn.fitText = function() {
        this.each(function(i, tag) {
            sizeText($(tag));
        });
    };
})();

http://jsfiddle.net/b9chris/et6N6/1/