Wednesday, August 5, 2009

Improved Solution for Embedding Fonts With CSS & jQuery

After explaining in a previous post about how to embed fonts with @font-face and have a fallback with jQuery, I realized that what I had explained wasn’t working correctly in Internet Explorer, so I have made some improvements to the technique.
So here is a better explained version… I hope.
Firs thing in your CSS define the new font of your choice with the @font-face; watch out for the license on your font :)

@font-face {
font-family: "Your New Font";
src: url(Your_New_Font.otf) format('opentype');
}

body {
font: normal 18px/24px "You New Font", Arial, Helvetica, Verdana, Geneva, sans-serif;
}

The @font-face technique is only available with certain browsers, what it does is that it loads a font file into the browser, the same way it loads background images. The definition also give the font a font-family which can then be used across the page and it will be as though the font is installed on the user’s computer; alas it's only available on newer browsers. Internet Explorer claims to have had support since IE4 but it’s support is only limited to Embedded OpenType (EOT)

Load up the JavaScript files in the HTML document, the libraries you will need are:
<script type="text/javascript" src="jquery-1.3.2.js"> </script>

<script type="text/javascript" src="jquery.fontavailable-1.1.js"> </script>

<script type="text/javascript" src="main.js"> </script>

<!--[if IE]>
<script type="text/javascript" src="Cufon.js"> </script>
<script type="text/javascript" src="[Cufon Font File].js"> </script>
<![endif]-->
</body>
</html>

As you may have noticed, I am only loading the Cufon library in the HTML document in Internet Explorer, because it would fail to load up Cufon dynamically.
Because I will be updating elements on the page with JavaScript, older browsers will need their updated text to refresh their font. So I made this little JSON object to take care of that. It holds a variable to check if the font is available (that is it has been loaded via @font-face, or user already has it installed),
Font = {
// check if font is available with jQuery Plug-In
available: $.fontAvailable('Your New Font'),

// flag to tell if the font is already loaded
// remember that the font if it's IE then the Cufon library
// has already been loaded.
// Also check with the jQuery Plug-In just in case.
loaded: $.browser.msie || $.fontAvailable('Your New Font') || false,

load: function(callback) {
$.getScript('js/lib/cufon/font.min.js', function() {
Font.loaded = true;
callback();
});
},

place: function(elem) {
// If font is already loaded via @font-face or installed
// on the computer, then no further work is needed
if (Font.available)
return;

function _place() {
if (typeof elem === 'string')
Cufon.replace(elem);
else
for (var i = 0; i < elem.length; i++) {
Cufon.replace(elem);
}

Cufon.refresh();
}

if (!Font.loaded) Font.load(_place);

else _place();
},

refresh: function() {
// If font is already loaded via @font-face or installed
// on the computer, then no further work is needed
if (Font.available)
return;

Cufon.refresh();
}
};

// Usage Example

// Hook up Cufon if font is not available
Font.place('h1');

// Replace the content of the element
$('h1').eq(0).text('A New Header Text');

// Refresh the font replacements if font is not available
Font.refresh();

As you might have noticed in the highlighted line is that — unlike my previous post — I am loading a font.min.js JavaScript file. What I did is I combined the Cufon.js, and [Cufon Font File].js files into a single file called font.js and minified it, to font.min.js so that I could decrease the number of requests to the server, and reduce my file size.
So that means my actual HTML code is something like this:
<script type="text/javascript" src="jquery-1.3.2.js"> </script>

<script type="text/javascript" src="jquery.fontavailable-1.1.js"> </script>

<script type="text/javascript" src="main.js"> </script>

<!--[if IE]>
<script type="text/javascript" src="font.min.js"> </script>
<![endif]-->
</body>
</html>

So that way we could replace fonts and keep things somewhat light.
Objections and insults are welcome. Fixes and better solutions will be much appreciated as well.

0 comments: