This is the most elegant solution I have created. It uses binary search, doing 10 iterations. The naive way was to do a while loop and increase the font size by 1 until the element started to overflow. You can determine when an element begins to overflow using element.offsetHeight and element.scrollHeight. If scrollHeight is bigger than offsetHeight, you have a font size that is too big.
Binary search is a much better algorithm for this. It also is limited by the number of iterations you want to perform. Simply call flexFont and insert the div id and it will adjust the font size between 8px and 96px.
I have spent some time researching this topic and trying different libraries, but ultimately I think this is the easiest and most straightforward solution that will actually work.
Note if you want you can change to use offsetWidth
and scrollWidth
, or add both to this function.
// Set the font size using overflow property and div height
function flexFont(divId) {
var content = document.getElementById(divId);
content.style.fontSize = determineMaxFontSize(content, 8, 96, 10, 0) + "px";
};
// Use binary search to determine font size
function determineMaxFontSize(content, min, max, iterations, lastSizeNotTooBig) {
if (iterations === 0) {
return lastSizeNotTooBig;
}
var obj = fontSizeTooBig(content, min, lastSizeNotTooBig);
// if `min` too big {....min.....max.....}
// search between (avg(min, lastSizeTooSmall)), min)
// if `min` too small, search between (avg(min,max), max)
// keep track of iterations, and the last font size that was not too big
if (obj.tooBig) {
(lastSizeTooSmall === -1) ?
determineMaxFontSize(content, min / 2, min, iterations - 1, obj.lastSizeNotTooBig, lastSizeTooSmall) :
determineMaxFontSize(content, (min + lastSizeTooSmall) / 2, min, iterations - 1, obj.lastSizeNotTooBig, lastSizeTooSmall);
} else {
determineMaxFontSize(content, (min + max) / 2, max, iterations - 1, obj.lastSizeNotTooBig, min);
}
}
// determine if fontSize is too big based on scrollHeight and offsetHeight,
// keep track of last value that did not overflow
function fontSizeTooBig(content, fontSize, lastSizeNotTooBig) {
content.style.fontSize = fontSize + "px";
var tooBig = content.scrollHeight > content.offsetHeight;
return {
tooBig: tooBig,
lastSizeNotTooBig: tooBig ? lastSizeNotTooBig : fontSize
};
}