|
/** |
|
* Increases/decreases font of element so that it fits on one line |
|
* @returns {jQuery} original jQuery object |
|
*/ |
|
$.fn.edgetoedge = function() { |
|
return this.each( function( ) { |
|
var $element = $( this ), |
|
display = $element.css('display'), |
|
|
|
// easy way to get height metrics |
|
// NOTE: this will trigger reflow!!! Use sparingly. |
|
metrics = function() { |
|
var height = $element.height(), |
|
// get target height as if container was wide enough to fit it all |
|
lineHeight = $element.css('white-space', 'nowrap' ).height(); |
|
|
|
// put font-wrapping back to normal |
|
$element.css( 'white-space', 'normal' ); |
|
|
|
return { |
|
height: height, |
|
lineHeight: lineHeight |
|
}; |
|
}, |
|
// NOTE: this will trigger reflow!!! Use sparingly. |
|
resize = function( size ) { |
|
$element.css('font-size', size + 'px'); |
|
}, |
|
stats, delta, dir, growths = 0; |
|
|
|
// element must be block-level to avoid inline spacing issues |
|
if( display !== 'block' ) { |
|
$element.css( 'display', 'block' ); |
|
} |
|
|
|
// if there are child elements, process those instead |
|
var $children = $element.find( '*' ); |
|
if( $children.length ) { |
|
$children.edgetoedge(); |
|
return; |
|
} |
|
|
|
// EXTRA: exit if no text inside |
|
if( !$element.text() ) { |
|
console.log( 'no text' ); |
|
return; |
|
} |
|
|
|
// increase font size until we are wrapping at least one line |
|
while( ( stats = metrics() ) && stats.height === stats.lineHeight ) { |
|
growths++; |
|
resize( parseInt( $element.css('font-size' ) ) * 2 ); |
|
}; |
|
|
|
// this will be our basis for checking |
|
var overflowingFontSize = parseInt( $element.css('font-size' ) ); |
|
|
|
// for debugging |
|
var runs = 0, original = overflowingFontSize; |
|
|
|
// use logarithmic reduction to determine best font size for one line |
|
while( true ) { |
|
stats = metrics(); |
|
|
|
// +/- font size by half of it's last change. |
|
delta = ( delta || overflowingFontSize ) / 2; |
|
|
|
// once the delta is too low, stop. |
|
if( delta < 1 ) { |
|
// sometimes, the last change is 1px over instead of under. Compensate. |
|
if( stats.height > stats.lineHeight ) { |
|
runs++; |
|
resize( parseInt( $element.css( 'font-size' ) ) - 1 ); |
|
} |
|
|
|
break; |
|
} |
|
runs++; |
|
|
|
// -1 for decrease, 1 for increase. Decrease if equal |
|
dir = stats.height > stats.lineHeight && -1 || 1; |
|
|
|
// increase or decrease font size by half of last increase/decrease. |
|
// EXTRA: Round number down for browser consistency. |
|
resize( Math.floor( overflowingFontSize += delta * dir ) ); |
|
}; |
|
|
|
$element.css('white-space', 'normal'); |
|
|
|
//* |
|
// for debugging |
|
var finalFontSize = parseInt( $element.css('font-size' ) ), |
|
expectedRuns = Math.ceil( Math.log( finalFontSize ) / Math.log( 2 ) ); |
|
|
|
console.log( { |
|
'element': $element, |
|
'original font size': original, |
|
'new font size': finalFontSize, |
|
'expected runs': expectedRuns + ' - ' + ( expectedRuns + 1 ), |
|
'actual runs': runs |
|
} ); |
|
//*/ |
|
} ); |
|
}; |
|
|
|
$( function() { |
|
$( 'header, blockquote' ).edgetoedge(); |
|
} ); |