a/20541563/1636522

HTML

<p>Click the boxes to justify the content (<a href="#">debug</a>).</p>
<div class="title"><span class="justifiable">hello world!</span></div>
<div class="subtitle"><span class="justifiable">How are you?</span></div>

CSS

div {
    width: 490px;
    line-height: 50px;
    background: gray;
    text-align: center;
}

.title
{
    font-family: 'Muli', Arial, Helvetica, sans-serif;
    font-size: .8em;
}

.subtitle
{
    font-family: 'Muli', Arial, Helvetica, sans-serif;
    font-size: .3em;
}

div > span {
    color: black;
}
/* following rules are for demonstration purpose only */
body {
    font: normal 1em Arial;
}
div {
    float: left;
    margin: 0 10px 10px 0;
    /* following rules make the DIV unselectable */
    /* http://stackoverflow.com/a/4407335/1636522 */
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
a {
    color: #999;
}
a.debug {
    color: red;
}
div.debug {
    border: 10px solid lightblue;
}
span.debug {
    background: yellow;
    color: black;
}

JavaScript

// A "bit" is a portion of the free space.
// It's half the space between two characters :
//
//  - "abc"   : 4 bits ("a..b..c").
//  - "ab cd" : 8 bits ("a..b.. ..c..d").
//
// The "gap" is the number of pixels remaining
// after splitting the free space into bits.
// Those pixels are assigned to each "bit"
// until no pixels remain. Let's say gap = 1 :
//
//     bitWidth + (gap && (--gap, 1)) // gap = gap - 1 THEN bitWidth + 1
//     // next bit
//     bitWidth + (gap && (--gap, 1)) // bitWidth + 0
//
// Depending on your configuration, there is one
// pixel which remains free in the second demo.
// I haven't investigated about that yet.

jQuery.fn.justify = function () {
    return this.each(function () {
        var el = $(this),
            ct = el.parent(),
            chars = el.text().split(''),
            bits = (chars.length - 1) * 2,
            freeSpace = ct.width() - el.width(),
            bitWidth = Math.floor(freeSpace / bits),
            gap = freeSpace % bits;
        el.html(jQuery.map(chars, function (char, i) {
            var paddings = ['0', null, '0', null];
            if (!i) {
                paddings[1] = (bitWidth + (gap && (--gap, 1))) + 'px';
                paddings[3] = '0';
            } else if (i + 1 === chars.length) {
                paddings[1] = '0';                
                paddings[3] = (bitWidth + (gap && (--gap, 1))) + 'px';
            } else {
                paddings[1] = (bitWidth + (gap && (--gap, 1))) + 'px';                
                paddings[3] = (bitWidth + (gap && (--gap, 1))) + 'px';
            }
            return '<span style="padding:' + paddings.join(' ') + '">' + char + '</span>';
        }).join(''));
    });
};

$('div').click(function () {
    $(this).find('.justifiable').justify();
});

$('a').click(function (e) {
    e.preventDefault();
    $('div,.justifiable').add(this).toggleClass('debug');
});