Tuesday, July 7, 2009

Embedding your font with @font-face

Last night I found out about @font-face, which allows web authors to embed a font into a web page. The only problem here is the browser comparability.
After much research overnight (and some freak outs) I found this jQuery plugin called fontAvailable. It basically creates a dummy span element with a fake font, and then tests it against the input front from the parameter; it checks the width and height for changes.
So after embedding the font with @font-face, the font should act as though the font is installed on the client’s computer.
The tools that I have used to achieve a lightweight embedded fonts are Cufon, jQuery, fontAvailable, and @font-face.

The HTML
<link rel="stylesheet" type="text/css" href="css/style.css" >
<script type="text/javascript" src="js/lib/jquery/jquery-1.3.2.js"> </script>
<script type="text/javascript" src="js/lib/jquery/plugins/jquery.fontavailable-1.1.js"> </script>

Note: The Cufon library is dynamically loaded with jQuery

The CSS
@font-face {
font-family: Kartika;
src: url(kartika.ttf) format('truetype');
}


The JavaScript
if (!$.fontAvailable('Kartika')) {
// load the cufon library
$.getScript('js/lib/cufon/cufon.js', function() {
// load the font
$.getScript('js/lib/cufon/Kartika_400.font.js', function() {
Cufon.replace('#nav ul li a');
});
});
}

It’s important to have the font file loaded in the callback after loading the Cufon library, and same thing goes for applying the fonts.

Edit:
So it turns out that dynamically loading the javascripts doesn’t work in Internet Explorer (haven't tested it in others) so it’s best to load the Cufon library and it’s font files with the script tags.

Sunday, June 7, 2009

A Little About XHTML

In the past few days I’ve been reading the specifications for xhtml 1.1 & 2.0, and html 4.01 & 5.0. I myself have been using xhtml 1.0 & 1.1 ever since I started web development about 4 years ago, and I thought that it was the standard format to build a web page. There was one little detail that I overlooked. While I was sending the proper xhtml doctype:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

I was sending the page as text/html with the following meta tag:
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
Now while the doctype was right, the content-type wasn’t. The browser would still render the page as text/html because of the meta tag. The page should then be sent as application/xhtml+xml with the changed meta tag:
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
But that’s not all, the web server (ie apache) would still need modification in order to send out the proper MIME Type:
application/xhtml+xml xhtml xht
That means also renaming the file with a .xhtml extension. So now that we have the proper file name, headers and doctype, how’s the browser support? Firefox, Safari, and other legacy web browser know how to parse the XML file. The only problem is that some browsers render the entire XML file, while validating for errors, and then display the page to the user, and if an error in the XML file was encountered the rendering would break displaying an error to the page. HTML display the page as it renders, also called incremental rendering. I don’t personally see anything wrong with non-incremental rendering, instead of having the page slowly unravel in front of the user, why not just wait until the whole thing is done loading, and as long as the code is valid xhtml, then there is no reason to fear errors getting thrown at the user.

Internet Explorer, on the other hand, doesn't understand application/xhtml+xml, there is a little hack though to allow it to do so. It's by adding the following line to the xhtml file:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="copy.xsl"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

Then create a file called copy.xsl with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<?xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<?xsl:output method="html" indent="yes" encoding="UTF-8" />

<?xsl:template match="/">
<?xsl:copy-of select="." />
<?/xsl:template>
<?/xsl:stylesheet>

What this XSLT file does is copy the root element and spits it back out as html. This will allow Internet Explorer, and other browsers to that matter, to parse the file as application/xhtml+xml, and then render it as text/html to the user.

Sunday, May 10, 2009

jBoingPic

So the other day I StumbledUpon-ed this little experiment by Kelvin Luck. It’s a very small piece of JavaScript that turns a picture into a grid that is repelled by the movements of the mouse.

The script can get quite heavy, basically the less columns and rows you have the smoother it will run, and of course if you enable that effect on more than one picture… So anyway I loved the code and I decided to modify it so it would work as a jQuery plugin.

First make sure you have the jQuery library loaded.
<script type="text/javascript" src="http://www.google.com/jsapi"> </script>
<script type="text/javascript">
google.load('jquery', '1.3.2');
</script>

Then insert the CSS file. It can be modified, I used the width and height dimensions of the picture that I’m using for the demo. Feel free to experiment.
.jBoingPic {
width: 596px;
height: 569px;
margin: 60px auto;
position: relative;
}

.jBoingPic-block {
position: absolute;
width: 18px;
height: 18px;
}

The markup:
<div class="jBoingPic">
<img src="images/pic.png" alt="" />
</div>

That way if JavaScript is disabled, the picture will remain.

And finally call the function:
$(function() {
$('.jBoingPic').jBoingPic();
});

The options are:
$('.jBoingPic').jBiongPic({
'image': $(this).children('img'),
'mouseX': 1000,
'mouseY': 1000,
'force': 1500,
'rows': 10,
'cols': 10
});

The Links:

Sunday, December 14, 2008

Hackers Have Lost It

Well it's official now, hacker have officially lost it: http://www.bbspot.com/News/2008/12/linux-on-a-potato.html
:D

Tuesday, December 2, 2008

How I style my side of the cloud

Just wanted to share how I organize my CSS rules. The sample below shows how I order the different declarations if they happened to all be there. So I would never have a width declared before a position for example.

I haven't kept the "clockwise" order for the positioning for elements. I guess it happened because I use top and left the most.
selector {
clear
float
position
top
left
bottom
right
z-index
margin
padding
width
height
display
overflow
border
background
font
text-decoration
letter-spacing
line-height
/* opacity through JavaScript */
/* border corner radius through JavaScript */
}

I don't like using PNGs to get a rounded corner effects, I simply find it too messy and time consuming. The only good thing about it is you can get the "boxes" to display 100% as you intended them to.

The other best way to do it is by using the jQuery corner plug-in. It will create a rounded corner with the canvas HTML 5 element which has a background of whatever the CSS background is and a rounded edge of the same colour as the CSS border. This will look fine as long as the element behind it has a plain background as well, meaning you can't have a picture behind it otherwise you'll end up with a squared box with rounded borders running along the "inside" instead of a rounded box; of course that's only on Internet Explorer.
It's not until recently that I find out that CSS3 is working towards making a border-radius
selector {
border-radius: 10px;
}

It was great and all, but it's not quite implemented by browsers yet, so it was pretty much useless to me. So I went about modifying the stylesheet with firebug and then I mistyped something and firebug autocompleted -moz-border-radius. Seeing that I quickly hit the tab key and entered a value, and the corners were round! I took a look around Google and I found that WebKit also has -webkit-border-radius.
selector {
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}

No dice, it worked and all but only for Mozilla and WebKit based browsers, and it's not valid CSS. So I threw it into a JavaScript file and have it handle everything.
function corner(aElem, aRadius) {
if ($.browser.mozilla)
$(aElem).css('-moz-border-radius', aRadius);
else if ($.browser.safari)
$(aElem).css('-webkit-border-radius', aRadius);
else
$(aElem).corner(aRadius);
}

I use jQuery to check if it's Mozilla or Safari browsers and apply a style property to the element, otherwise use the corner plugin to place the canvas.

Another issue I had with validation was the opacity. CSS3 is working towards a opacity, although it may work on some browsers. So I threw this into my CSS:
selector {
opacity: 0.2; /* CSS3 */
-moz-opacity: 0.2; /* Old Mozilla */
-khtml-opacity: 0.2; /* KHTML Engine */
filter: alpha(opacity=20); /* IE5 - IE7 */
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)"; /* IE 8 */
}

It works well and my elements have a transparency in them, but it doesn't validate and my file comes out with errors, so again I turn to JavaScript & jQuery:
$(...).css({opacity: 0.2});
I also leave a commented line in the CSS file for those elements that have rounded corners or opacity as indicated in my first sample above. It's good to have it there for reference.

Saturday, October 4, 2008

BookmarkQuery Tests

err forgot to post about this last week.
So last week I finished up the test for BookmarkQuery. The test was very small and somewhat incomplete that I didn't test for fuelIBookmarkQuery.type
I tried to use that property and concluded that it only worked when null.
The tests is very small, simple and straight forward.
I start off by adding a new bookmark folder, with 3 bookmarks in it. Then I create a new query object set it's searchTerm to 'dev' and execute.
I'm expecting just 1 bookmark to return since dmo is the only one with 'dev' in it.
const Ci = Components.interfaces;
const Cc = Components.classes;

function url(spec) {
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
return ios.newURI(spec, null, null);
}

function test() {
// Create bookmarks to test with
var menu = Application.bookmarks.menu;
var folder = menu.addFolder("FUEL Test Bookmarks");

folder.addBookmark('www.moz.org', url('http://www.mozilla.org'));
folder.addBookmark('dev.moz.org', url('http://developer.mozilla.org'));
folder.addBookmark('wik.moz.org', url('http://wiki.mozilla.org'));

// Test creating a new query object
var query = menu.newQuery();
ok(query, "Check BookmarkFolder.newQuery()");

// Test searchTerms setter and getter
query.searchTerms = "dev";
is(query.searchTerms, "dev", "Check 'BookmarkQuery.searchTerms' after setter");

// Test execute()
var result = query.execute();
ok(result, "Check 'BookmarkQuery.execute' after execution")

// Test results returned
is(result.length, 1, "Check 'BookmarkQuery.execute()' after checking result.length");

// Test traversing of bookmarks
var bookmark = result[0];
is(bookmark.title, "dev.moz.org");

// Delete the added bookmarks
folder.remove();
}

Now I'm waiting for Mark Finkle to review my code and let me know how it went :)

Tuesday, September 16, 2008

Problem Solved

So I finally figured out why I wasn't able to pull out information from the returned objects in FUEL. In the FUEL source code I had a typo:
if (node.type == this._type || this._type == null) {
if (node.type == node.RESULT_TYPE_FOLDER)
item = new BookmarkFolder(node.itemId, this._folder);
else
item = new Bookmark(node.itemId, this._folder, node.type);
}

I had node.itemId spelled as node.itemID, so pretty much the uppercase D broke everything :D
On to finish the tests.