Tips for changing font-weight dynamically with CSS and JavaScript

I recently had to load a lot of font weights (100+) and change them dynamically to give the illusion of an interactive animated font based on mouse position. There were a few issues I ran into that I thought I’d share.

Technically font weights should be 100–900. I found Safari and Chrome were fine with weights outside this range but Firefox wasn’t. Some developers say font weights should be multiples of 100 but I found, regardless of whether it’s valid code or not, font weights within the above range are fine so long as they’re whole numbers. With over 100 weights I could not rely on multiples of hundred.

Once I got the above weights to work I found that they flickered when I changed them — and this eventually resolved itself once animation had run through. It seems, for whatever reason, the first time a browser loads a character (at least when you bombard it with lots of font weights) there is a slight delay in rendering it. I fixed this by adding a div that was positioned off screen (but wasn’t set to display: none or visibility: hidden) that showed every font weight and every character in the font. This forced the browser to load everything immediately.

This in itself doesn’t stop the flickering. Even though each font weight wasn’t that great in size each weight creates an additional HTTP request, adding some noticable lag to the page. So, even on a fast connection there will still be some delay in the browser loading the files and then rendering them.

Enabling your animation once all font files have loaded is not that simple. While Firefox won’t trigger $(window).ready() until all font files are loaded, other browsers will. You can use libraries to check for fonts being loaded; I tried one but found it didn't work with large numbers of fonts. But, by specifiying the default weight of the animated font to the first weight in the CSS — and by making the @font-face declarations in ascending order — what happens is the animation will play only up to the “frame” (i.e. the weight) that has loaded. So, you get no jumping or flickering. If you need the animation to be playable in full, however, this method won’t work and you should probably try out the various libraries.