HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Incrementing letter-spacing of one line of text

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
linetextincrementingoneletterspacing

Problem

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:

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++;
}
} );

Solution

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:

  • Cache h1.width() since it doesn't change.



  • Make your comparison be >= because you may never get ==.



  • 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()  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) 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/

Code Snippets

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');
    }
}
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');
        }
    }
}
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");
}

Context

StackExchange Code Review Q#60531, answer score: 8

Revisions (0)

No revisions yet.