A JavaScript Fix For Text That's Too Tiny

The Problem

If you want your text to be resizable in all major browsers, and smaller than the default, you're probably using em units with values less than 1 in your style sheet, e.g.

p {font-size:0.75em}

As long as you're careful you've probably got it to work. But then someone complains that they browse the Web with IE for Windows set to a text size of Smaller and your site is unreadable. You take a look, squint, and despair. You do similar tests on a Mac and in Netscape 6 and despair further. You're all set to join the pixels-are-the-only-way club.

The Solution

This problem bothered me, and I needed a workaround for sites I was developing for myself and in my day job. Using JavaScript I found a solution that, if applied with care, helps make many sites readable no matter what the text size setting.

To see it in action, open up this test page, then make your text size smaller (head for View/Text Size in most browsers). Much of the text on the screen should become tiny, possibly unreadable.

To activate the fix, Refresh/Reload the page. You won't necessarily get the text back to precisely the size it was originally, but it should be an improvement and keep everything readable.

How It Works

Note: the function and sample page use XHTML; the function will still work with HTML 4, but purists may want to switch <br /> to <br> in the function's document.writeln.

To use this fix, simply insert a function call just after the body tag:

<script type="text/javascript"><!--

It can go at the bottom of the page instead, but the user may momentarily see the page with font sizes unadjusted just before the fix kicks in.

The function can be placed either in the head of the page or in an external .js file:

function emsTweak()
	if ((document.createElement) && (document.createTextNode))
		document.writeln('<div id="emsTest" style="position:absolute; visibility:hidden; font-family:arial,helvetica,sans-serif">&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br /></div>');
		var scaling=100;
		if ((navigator.platform=="Win32") && (navigator.appName=="Microsoft Internet Explorer")) scaling=105;
		var h=999;
		if (document.getElementById('emsTest').clientHeight) h=parseInt(document.getElementById('emsTest').clientHeight);
		else if (document.getElementById('emsTest').offsetHeight) h=parseInt(document.getElementById('emsTest').offsetHeight);
		if (h<85) document.body.style.fontSize=Math.round(scaling*90/h)+"%";

The fix only works in modern, DOM-capable browsers; detection is taken care of by the first if statement. So far it's been tested in Win IE5/5.5/6, Mac IE5 and Netscape 6.

A hidden div containing a few lines of text is written into the page. Its height is then measured, and if it's too small the font size applied to the body tag is increased to compensate. An extra 5% is added for Win IE just to nudge it into being more accurate.

All font sizes within the page must be in ems. You may get it working without problems simply by leaving the body tag without any font size set, but it's more likely you'll need to set it to 100%, along with font-size:100% for table, td and th if they have no existing font size, e.g. with the following in the style sheet:

body,table,td,th {font-size:100%}

See below for an explanation of this seemingly needless CSS...

Bugs, Quirks and Workarounds

OK, now for the bad news. It isn't always possible to get this fix to work properly in all browsers for a particular site. The problems arise from strange and inconsistent behaviour in various browsers.

Tables are a real headache. If text within table cells is also within another tag which handles its formatting, e.g.

body, table, td, th {font-size:100%}
td {}
p {font-size:0.8em}
<p>Goodbye cruel world</p>

then as long as the font-size:100% 'bodge' is there it all works OK. Without it Win IE fails to resize any text within tables; with it Win IE resizes text by a lesser amount when the Text Size setting is altered (smaller text isn't so small, larger not so large). I haven't a clue why this is.

If text is instead formatted by the td/th (not wrapped in a paragraph) then it seems to stubbornly refuse to resize at all in Mac IE and I've not yet found a workaround. Nested tables can get yet more complicated.


This fix should be suitable and work OK if...

It won't work for every site, or every browser, and relies on JavaScript being enabled, but it's allowed me to use ems rather than pixels for a few sites already. If you discover any improvements or additional workarounds let me know and I'll see if I can improve the code.

Matt Round
malevolent design
malevole weblog