Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I was asked to create a script which will increment the letter-spacing of one line of text, until its width matches that of the first line; for use in headline/subheadline text to maintain a block effect as illustrated:

enter image description here

The problem is, it's very slow. Is there a faster way of calculating this?

$(window).resize(function() {
var h1,h2;
var x = 1;
h1 = $('#header').find('h1');
h2 = $('#header').find('h2');
h2.css( { 'letter-spacing':'1px' } );


while(h1.width() !== h2.width() && x < 1000) {
    if (x == 1000) { break; }
    h2.css( 'letter-spacing','+=0.1px' );
    x++;
}
} );
share|improve this question

1 Answer 1

up vote 8 down vote accepted

As with all things related to performance, you must measure. Here's a jsperf with your original code in it and several other iterations: http://jsperf.com/set-text-width

You can do several things to speed it up considerably:

  1. Cache h1.width() since it doesn't change.
  2. Make your comparison be >= because you may never get ==.
  3. Use a larger pixel increment until you get close, then step down to a smaller increment

Per jsperf, this is about 5x faster than your original code.

function matchSize3() {
    var h2,w;
    var x = 1;
    w = $('#header').find('h1').width();
    h2 = $('#header').find('h2');
    h2.css( { 'letter-spacing':'1px' } );

    while(h2.width() < w) {
        if (x++ > 1000) { break; }
        h2.css('letter-spacing', '+=1px');
    }

    for (var i = 0; i < 10; i++) {
        if (h2.width() <= w) break;
        h2.css('letter-spacing', '-=0.1px');
    }
}

And, here's an even faster version that just attempts to calculate the desired pixel spacing and starts with that. This is 14x faster than your original. I don't think the last two loops are probably needed at all.

function matchSize4() {
    var h2, w;
    w = $('#header').find('h1').width();
    h2 = $('#header').find('h2');
    h2.css( { 'letter-spacing':'1px' } );

    // try to calculate the best starting point
    var l = h2.text().length;
    var diff = w - h2.width();
    h2.css("letter-spacing", ((diff/l) + 1) + "px");

    // these may not be needed at all
    if (h2.width() < w) {
        for (var i = 0; i < 10; i++) {
            if (h2.width() >= w) break;
            h2.css('letter-spacing', '+=0.1px');
        }
    } else {
        for (var i = 0; i < 10; i++) {
            if (h2.width() <= w) break;
            h2.css('letter-spacing', '-=0.1px');
        }
    }
}

And here's a version that just calculates the desired letter-spacing with no iteration. This is 27x faster than your original version:

function matchSize5() {
    var h2, w;
    w = $('#header').find('h1').width();
    h2 = $('#header').find('h2');

    // calc the desired spacing
    var len = h2.text().length;
    var diff = w - h2.width();
    h2.css("letter-spacing", (diff/(len - 1)) + "px");
}

For speed reasons, this one assumes the letter-spacing is initially 0. If it won't reliably be zero, then you have to obtain the initial value and use that in the calculation or set it to zero initially.

And here is a jsFiddle of this one to show that it works: http://jsfiddle.net/jfriend00/trazumeh/

share|improve this answer
1  
Added two more versions that are successively faster and a jsFiddle that shows the last one working. –  jfriend00 Aug 20 at 2:21
    
jsperf.. great utility! Never seen that before. Thx. –  dcc Aug 21 at 1:20

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.