Adding Location Awareness to Your Site

January 9th, 2009 by Robert

I recently launched a new personal site.  I wanted to integrate some level of location awareness to it.  My initial design sketches called for the weather information and a position on a map of my last known location.

Initially, I was using a program on my iPhone called Loopt.  Loopt is like Twitter with location.  That involved jumping through hoops, as Loopt’s RSS feed only shows the GPS position of the last post.  Not only would I have to post a message every time I got somewhere, I’d have to reverse geocode my position to grab the zip code to send to get the weather information.  I achieved this through JavaScript with the Google Maps API.  This worked until I found out about Fire Eagle.

All Fire Eagle does is log your location. Luckily, Fire Eagle has an API. Eagle Feed turns your location into a publicly accessible RSS feed. So, getting your location is as easy as parsing an RSS feed. By setting the read level of Eagle Feed to my zip code, the title of the single item in the RSS feed reports my city, state, and zip (e.g. Birmingham, AL 35223), and my GPS coordinates are also in the feed.

You can update Fire Eagle by manually by entering your location on the site. However, there are mobile applications, such as Active Eagle on the iPhone, that use the GPS functionality of your device to update Fire Eagle. In Active Eagle, I simply tap “Update Fire Eagle” to update my location, and my Eagle Feed.

Once you can get your feed there are plenty of cool things you can do.

I wrote a simple PHP script to open my feed (or pull it from a cached file), grab the human-readable location from the title and parse out the zip code and my GPS position.

1
2
3
4
5
6
7
8
9
10
11
$out = file_get_contents($feed_url);
 
preg_match_all('/<title>(.*?)<\/title>/', $out, $loc_matches);
$human_loc = $loc_matches[1][1];
preg_match('/\d{5}/', $human_loc, $loc_matches);
$human_zip = $loc_matches[0];
 
preg_match('/<abbr class="latitude".*?>(.*?)<\/abbr>/', $out, $lat);
$loc_lat = $lat[1];
preg_match('/<abbr class="longitude".*?>(.*?)<\/abbr>/', $out, $long);
$loc_long = $long[1];

I then pass my zip code to Yahoo’s weather feeds to get weather data. I also pass my GPS position to Google Maps Static API to get a map of where I am.

Another idea would be to show Flickr photos in your area via the Flickr API. I’m sure there are tons of other things that would be fun or useful. Come up with some more ideas and make some cool stuff.

The State of Web Fonts

January 8th, 2009 by Robert

A long time ago, Microsoft started making use of @font-face (also called web fonts) in CSS. This would have been revolutionary if not for the fact that using fonts required the designer to encode them into a weak DRM file called an EOT, which stands for Embedded OpenType. Open indeed. Things are starting to look up now.

The great thing about Microsoft trying to introduce this is that it would have ended an era of Web Safe fonts and “download this font to view my page properly” messaging before Web Safe fonts were understood. Unfortunately, no other browser bothered implementing the CSS or EOT and @font-face fell into obscurity for many years, forcing web designers to use images of text. EOT’s major flaw was that it pandered to font makers and left web designers jumping through hoops to create font files.

Microsoft apparently has strong corporate ties to certain Font Industry big-wigs, and they didn’t want to upset them. Better to make life hard for your developers than help font makers come up with workable solutions for licensing web fonts (like hosting font files and checking the HTTP_REFERER for the correct domain before allowing access to the font file, which seems as good as the weak DRM of EOT files). When you are the most commonly used browser, I guess you can do stuff like that and still have your CEO chant, “Developers! Developers! Developers!” The problem is that Microsoft didn’t anticipate empowering font creation software like FontStruct that lets mere mortals create fonts under Creative Commons licenses. Frankly, it’s unfair to force me to put DRM on stuff I create if I don’t want it.

Eventually, some good people created sIFR, which allowed designers to (with great effort) cobble together a Flash file that embedded a font. Adding some JavaScript code to the page allowed designers to add fonts in a more accessible, user-friendly manner than simply using images of text. While sIFR had some problems (for example, links in headings were buggy and the text wouldn’t resize with the browser), it was a breath of fresh air. Suddenly, it was only a little work to have nice typographic options for limited use in headers and the like.

Recently, Apple (in the form of WebKit) and Opera have brought back the @font-face. Luckily, Apple and Opera didn’t bend over for the Font Industry. They boldly allowed support of plain-old TrueType fonts. With half of the major rendering engines supporting easy web fonts (and Firefox support on the way), I decided to give EOT another shot. That would allow me to have four out of five browsers (that I support) rendering my fonts out-of-the-box with sIFR as a worse-case fallback.

The results were mixed. Using @font-face is progressive enhancement with CSS and using sIFR is progressive enhancement with JavaScript and Flash. To start, I went through the lengthy and buggy trial and error process of creating an EOT with WEFT. After getting that worked out, I added the following to my screen stylesheet:

1
2
3
4
5
6
7
8
9
10
11
@font-face {
	font-family: "MyFont Sans";
	src: url("../media/myfont_sans.ttf") format("truetype");
}
 
@font-face {
	font-family: "MyFont Sans IE";
	font-style: normal;
	font-weight: normal;
	src: url("../media/MYFONTS0.eot");
}

I could then set a font by specifying font-family: MyFont Sans, MyFont Sans IE, sans-serif;. In Safari, Opera, and Internet Explorer, my site used a custom font. Other browsers fell back so a system chosen sans serif font if the font MyFont Sans was not installed on the system. That gets us half way there.

The next step is to create the sIFR and load it only if it is needed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var MYSITE = {
	sifr: true,
	init: function() {
		if(window.getComputedStyle) {
			var ff = document.defaultView.getComputedStyle(h,null).getPropertyValue('font-family');
			switch(ff.toLowerCase()) {
				case 'myfont sans':
				case '"myfont sans"':
				case "'myfont sans'":
					MYSITE.sifr = false;
			}
		} else {
			MYSITE.sifr = false;
		}
		if(MYSITE.sifr) {
			MYSITE.setSifr();
		}
		return true;
	},
	setSifr: function() {
		// Code enabling sIFR
	}
};
 
if(window.addEventListener) {
	window.addEventListener('load', MYSITE.init, false);
} else if(window.attachEvent) {
	window.attachEvent('onload', MYSITE.init);
} else {
	window.onload = MYSITE.init;
}

The script runs after the page loads. Checking for window.getComputedStyle ensures that any standards compliant browser that supports web fonts will not get sIFR, since the browser will report that it is using MyFont Sans. Firefox, if I remember correctly, reports a list of fonts, but it ends up in the result of Firefox getting sIFR. Once Firefox has web fonts support, this script will need to be reevaluated. If the browser doesn’t support getComputedStyle, the browser is (probably) Internet Explorer, which supports web fonts. So, we can turn sIFR off.

Finally, any browser that needs sIFR will execute MYSITE.setSifr();, adding the custom fonts to the page.

This should provide custom font support in most major browsers. The only caveat is that a suitable fallback should be chosen (one that looks similar to the @font-face font, rather than sans-serif mentioned above), as browsers without Flash or without JavaScript will see the fallback font if the browser doesn’t support web fonts.

Since we have a suitable fallback with sIFR when web fonts aren’t available to the browser, there is a good enough methodology for implementing custom typography on live sites that don’t support web fonts. Until Firefox releases support for web fonts, it may be too much trouble to implement. However, in the spirit of progressive enhancement, one could skip the sIFR step and simply allow the installed system font fallback, as pixel-perfect cross browser support is turning into an obsolete, undesirable practice and progressive enhancement is becoming common place.

The final rub is Microsoft’s persistence in supporting EOT and not TrueType or OpenType fonts. While it is possible to get web fonts in Internet Explorer, it is a royal pain to create EOT files. If it’s too much effort, using sIFR or keeping the tenants of progressive enhancement with CSS may be a workable solution.

So, it seems web fonts have almost come of age. Once Firefox supports @font-face, web fonts can be used on a wide scale. While you may not want to jump on the bandwagon yet, it is definitely time to start looking into web fonts.

Robertdot Relaunch

January 7th, 2009 by Robert

Welcome to the relaunch of Robertdot. As you can see, there isn’t much here. I still have a ton of work importing relevant old posts, fleshing out the site, and debugging.

The reason for all the changes is to help take Robertdot away from its original purpose as personal blog and move it toward my new goal for the site as a web design blog. That means I’ve purged everything, and I’ll slowly bring back content relevant to the site while letting the unneeded parts fall away.

If you’re used to keeping up with my personal life here on Robertdot, you may want to take a look at my new personal site, Robert Brodrecht’s Vanity Site.

So, keep an eye out in the coming weeks for things to get finalized and Robertdot to turn into a finished product, rather than the live beta you see now.

Forms With Elements With Form Attribute Names

September 23rd, 2008 by Robert

I commonly create a form element that dictates the action I want the server to perform, like <input type="hidden" name="action" value="save">. This allows me to have a switch to determine what to do with the data in any situation instead of posting and getting to multiple places. I found a bug in Internet Explorer 7’s JavaScript today that introduces a problem with my naming scheme.

When doing Ajax, I often use form.getAttribute('action') to get the location to send the request to. This allows me to keep my code more portable. However, in Internet Explorer 7 (or IE7 for short), if there is also a form element with name="action", IE7 returns the input object instead of the value of the attribute as though I typed formname.action or, in long hand, document.forms['formname'].elements['action'].

To my knowledge, there is no work around other than changing the name of the element. So, I’ll be using name="faction" from now on. That’s short for “form action” but “faction” itself is fairly apt given IE’s behavior is different from all other browsers, making it a faction.

A Rant: Something I’m Tired Of

August 13th, 2008 by Robert

Recently, there have been a slough of “25 Great Whatevers” or “15 Awesome Ways To Do Something.” Smashing Magazine does this constantly, and SitePoint is guilty, too. Many of these articles aggregate links to the same tired sites and tout some little nook of it as very well done. I mean, how many times do I have to look at Avalon Star? Jeeeeesus.

My main problem is that these lists are a poor excuse for content. I would ignore them (easily, since I’m not subscribed to their feeds), but people like Paul Boag love them. So, I have to notice them, even though I don’t want to.

Ok. End Poorly Written Rant.

MySQL FIND_IN_SET

July 31st, 2008 by Robert

I always forget this mySQL function, so I figured I should make note of it somewhere. It’s called FIND_IN_SET. You specify a variable and a list of possible matches and it returns the position of the string in the list. It’s very helpful for sorting things in a defined list provided by the client.

NYTimes Hand Codes

April 30th, 2008 by Robert

For future reference, the NYTimes.com Art Director says (search for “Visual Consistency”) they hand code their site. It still uses a loose DTD and table-based layout, but at least they aren’t using DreamWeaver.

Internet Explorer Version Targeting Finally Makes Sense

March 4th, 2008 by Robert

I kept mum about Internet Explorer 8’s version targeting to see how things played out. It looks like Microsoft did the right thing for real web developers.

Version targeting allows the web developer to pick which version of Internet Explorer’s rendering engine he or she would like to use. This is great for big sites (like banks) because they can forever have a site that works in buggy Internet Explorer 6. No more freak outs when Internet Explorer updates like there were with the update to version 7. The problem wasn’t that they were introducing a proprietary header / meta tag. The problem was that all future versions of Internet Explorer would render like version 7 unless the developer opted in for the newest rendering mode. That’s right. A large majority of people would be forever designing with Internet Explorer 7!

The solution several web celebs they would adopt would be to set the version to edge to always get the latest version in an attempt to tell Microsoft that good developers don’t want to use it. The problem is that developers had to use it to not use it.

Fortunately, Microsoft came to their senses and announced they would keep version targeting but have the default behavior use the latest rendering engine. The claim is that they are trying to support the new Interoperability Principles published in February. No doubt part of the problem was the overwhelming response against defaulting to version 7 from the web standards community. Either way, I’m glad Microsoft decided not to pander to the people causing the problem.

Everyone is happy now that Internet Explorer 8 will really pass Acid 2.

  1. Jeffery Zeldman’s Post
  2. Lachlan Hunt’s Post
  3. Roger Johansson’s Post
  4. Hixie’s Blurb
  5. Web Standard Project’s Post
  6. And it even made it to Slashdot

I am thankful I don’t have to add (in addition to conditional comments) more Microsoft related junk to the head of my boilerplate.

Saving Images For The Web

February 11th, 2008 by Robert

There are a lot of people creating graphics for the web. A significant portion of those people have no understanding of how to optimize images. I’ll attempt to explain it.

Typically, I’d explain when to use each format by looking at the format and exposing the flaws and virtues. Most non-geeks would get lost, though. While I will discuss file formats out of necessity, my aim is to discuss styles of graphics and how to optimize them the best way.

All the instructions are given in Gimpshop, the GIMP with modifications to make it more Photoshop-like. Typically these are similar to Photoshop. I planned to do Photoshop, but I don’t have regular access to it. I tried to note differences where I could remember. I’ll try to update this eventually with Photoshop instructions.

A Quick Note About The Scope of This Article

There are two ways to display images: vector and raster. Vector images are stored as formulas that, when combined, represent an image. Raster images are stored colors and coordinates of dots (called pixels). The web-safe raster formats (the subject of this article) are JPEG, GIF, and PNG.

Vector graphics have a very strong place in the design industry. Any serious designer making logos will be making them as vector art, for example. Vector images are infinitely scalable without quality loss and are very powerful in the right hands. The web at this time, however, is raster.

While there are vector image formats for the web (SVG and Flash are two major ones), most web graphics are raster. Vector graphic support, at the time of this writing, requires plug-ins for viewing or has limited browser support. To boot, I’m not clear how much optimization can be done to vector graphics compared to the likes of raster web formats. So, I’ll be sticking to raster images.

Three Typical Scenarios

When creating art for the web, there are three typical scenarios where images are needed:

  1. Line art and Icons
  2. Photography
  3. Design Graphics

I’ll go over each scenario and explain what it is, how it is used, and the typical way to output an attractive looking, lightweight image file.

Line Art and Icons

Line art and icons are either very simple images of varying dimensions, or very complex images at a very small dimensions. The line art moniker includes graphics like clip art, comic style art, or any graphic that has very few colors with lots of solid colors. Icons, in this instance, can be things like logos, simple graphical representations of concepts (for example, a contact us link may be represented as an icon of an envelope), or very small thumbnails (say, 50 x 50) of larger images.

What line art and icons have in common is low color depth. This makes these images ripe for indexed colors. That is, by throwing out unneeded colors, the file can be reduced in size. Likewise, changing similar colors to the same value reduces the file size. Two file formats play well with indexed color: GIF and PNG. To boot, both of these formats allow for transparency.

Before you create the file, make sure your image is 72 DPI. You can do this by opening Image > Image Size in both Gimpshop and Photoshop. The resolution should be set to 72. If you are using Gimpshop, you get the odd choice of setting independent resolutions for X and Y. Make both 72. You may have to adjust your width and height after you change the DPI.

In Gimpshop, select Image > Mode > Indexed Color…. In the Indexed Color Conversion dialog, select Generate Optimum Pallet. You will need to use trial and error to pick the maximum number of colors since GIMP provides on way to preview the image. The fewer the colors, the better, though. Once you’ve figured out the optimum number of colors, click OK. Gimpshop will then do the heavy lifting of removing extraneous colors. Then select File > Save a Copy…. In the save dialog, type in your file name with the .gif or .png extension. In either format, I suggest using interlacing (since it shows a visual progressive download). I usually disable all the other options, and set the compression level to 9 on PNG images. This will yield a similar file size for either format.

Photography

Photography is typically comprised of millions of colors and / or shades and is presented at larger dimensions than icons. Due to this, a format that can handle higher colors is needed. GIF is only good for up to 256 colors and full-color PNGs are often very large. This is where JPEG comes in. It allows you to present photography at full color while offering varying levels of compression / quality.

Determining the best quality setting is a per-photo trial-and-error process. Dark colors against light colors at lower quality settings tend to look particularly bad at the edges. So, it is important to always adjust the quality to various places to finesse the best file size / quality ratio (or bang for the buck, if you will). I’ve also found that Photoshop outputs better looking JPEGs at a given quality than Gimpshop. So, if you have the option, try Photoshop.

Before you create the file, make sure your image is 72 DPI. You can do this by opening Image > Image Size in both Gimpshop and Photoshop. The resolution should be set to 72. If you are using Gimpshop, you get the odd choice of setting independent resolutions for X and Y. Make both 72. You may have to adjust your width and height after you change the DPI.

In Gimpshop, File > Save a Copy… and enter your filename with a .jpg extension. After you click Save, you will be presented with JPEG settings. Click the Show Preview in image window checkbox. Then adjust the slider until you get the best picture at the lowest file size (shown dynamically just below the slider). Under Advanced Options, turning on the Optimize checkbox will further shrink the file size. Turning off Progressive will make the file smaller, but will also make the image not appear progressively as it loads in the web browser. If the file size is already low, you may not need progressive. If it is larger, a few extra kilobytes may be worth it to pop the image content up sooner in an attempt to grab the viewers attention and keep them on your page. You’ll want to turn off the Save Thumbnail. The other options may yield subtle changes to your photo and may change the file size a little. You probably won’t need to change these from the default. Finally, click OK.

Design Graphics

The graphics that make up the design of the site are often sort of like photography and sort of like iconography. That is, they may have far more than 256 colors, but don’t show a photo. Also, these graphics tend to have drop shadows or transparency, which makes them a little more unique.

With one exception, optimizing design graphics is a trial and error between GIF / PNG and JPEG. Sometimes indexed color works best, and sometimes JPEG’s lossy compression works best. The bonus for design graphics is that you don’t have to wrestle with bang-for-the-buck as much. Due to the way browsers work, the images are cached (stored on the user’s computer) and aren’t downloaded every time the page loads. So, you can typically have a little bit heavier file sizes to make the page look better. Just don’t forget: the user still has to download the image, and long downloads irritate people.

The one exception is transparency, and that comes in two flavors: translucency and transparency. Translucency is usually referred to as alpha transparency or just alpha.

If you need an area to be fully transparent, GIF or PNG will work in the indexed mode. Follow the directions above for line art (even if it isn’t technically line art by my definition).

Things like drop shadows or antialiased edges (rounded corners, for example), however, need to be full-color (or 24-bit) PNG in order to take advantage of alpha transparency. You’ll notice if you have antialiased edges and you use an indexed PNG or GIF, your edges will be jaggy and/or you’ll have to specify a matte color. Mattes are problematic if your background color isn’t solid, as the matte may not match the color of the background. In this case, you’ll want to use 24-bit PNG. 24-bit PNGs tend to be much bigger. You may want to manually index the image or use tools such as PNGCrush.

Saving alpha PNGs differs from saving indexed PNGs in that you simply don’t index the colors before exporting. Simply File > Save a Copy… with the .png extension. If you are using Photoshop, you must select the PNG 24 option in the Save For Web dialog. Once it’s saved, drop it on PNGCrush to remove any unneeded data.

One final note about design graphics is that PNGs can store additional information about an image to specify a color space (called gamma) that can cause the colors in the image to be different than identical color values in a browser. If you are using Gimpshop, you should be able to uncheck the Save gamma option to prevent this problem. Also, if you use PNGCrush, these values should be removed automatically. Since the gamma debacle is a big topic by itself, you can see how other people remove them or read the number one article in Google at the time of this writing.

You’re Done

That is the short version of exporting graphics for the web. If you find that clarification is needed or that I missed something, please leave a comment below or e-mail me from my contact form and I’ll do my best to answer your questions.

Element Swapping with Unobtrusive JavaScript

February 11th, 2008 by Robert

There may come a time when you need to show different content on one page based on a user-selected option. Here’s a quick tutorial.

The first step is to set up your content properly. In this example, I’ll use a select to swap between two form elements, though the basic premise can be applied to other design patters such as module tabs. Here is how the form should look.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<form method="post" action="post.php">
 <div>
  <label>
   How Should I Reply To You?
   <select name="type" id="type">
    <option value="email">E-mail</option>
    <option value="phone">Phone</option>
   </select>
  </label>
 </div>
 <div id="byemail">
  <label>
   Enter Your Email:
   <input type="text" name="email">
  </label>
 </div>
 <div id="byphone">
  <label>
   Enter Your Phone Number:
   <input type="text" name="phone">
  </label>
 </div>
</form>

That is the basic setup you need. You have something for the user to select (that has an id to assign, in this case, an onchange event), and something to swap between that have ids. Now you need some JavaScript. Comments are inline to explain things.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/* Assign the onload event to the function init. */
/* Test which way adding events is supported. */
if(window.addEventListener) {
	/* W3C method. */
	window.addEventListener('load', init, false);
} else if(window.attachEvent) {
	/* IE method. */
	window.attachEvent('onload', init);
} else {
	/* Old school method. */
	window.onload = init;
}
 
/* This is the function that runs after the page loads. */
function init() {
	/* Get the select element you want the onchange to be applied to. I use the j_ prefix because sometimes errors happen when variables are named the same thing as IDs in the HTML. */
	var j_type = document.getElementById('type');
	/* If the element exists, we can assign the onchange event to call the swap function using the same type test we used before. */
	if(j_type) {
		if(j_type.addEventListener) {
			j_type.addEventListener('change', swap, false);
		} else if(j_type.attachEvent) {
			j_type.attachEvent('onchange', swap);
		} else {
			j_type.onload = swap;
		}
		/* Now, we need to fire the event to get the default. */
		if(document.createEvent) {
			/* The W3C method. */
			var j_event = document.createEvent('HTMLEvents');
			j_event.initEvent("change", true, true);
			j_type.dispatchEvent(j_event);
		} else if(document.createEventObject) {
			/* The IE method. */
			j_type.fireEvent("onchange");
		}
	}
}
 
/* This is the function that does the work of swapping the elements. */
function swap(e) {
	/* Get both the elements you want to swap between. */
	var j_email = document.getElementById('byemail');
	var j_phone = document.getElementById('byphone');
	/* Grab the event from the W3C method or the IE method. */
	var e = e || window.srcEvent;
	/* Grab the event target from the W3C method or the IE method. */
	var target = e.target || e.srcElement;
	/* Grab the target's value */
	var t_value = target.value;
	/* If both swap elements exist... */
	if(j_email && j_phone) {
		/* Depending on which option, hide or show the form elements. */
		if(t_value == 'email') {
			j_email.style.display = 'block';
			j_phone.style.display = 'none';
		} else if(t_value == 'phone') {
			j_email.style.display = 'none';
			j_phone.style.display = 'block';
		} else {
			j_email.style.display = 'none';
			j_phone.style.display = 'none';
		}
	}
	return true;
}

Save the script above to a file and include it in the head of your document that the form is in. You’ll have the swapping capabilities you desire using unobtrusive JavaScript and modern DOM techniques.

This was tested in Safari 3, FireFox 2, Opera 9.25, and Internet Explorer 7.