<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Web 3.0, 6 Bladed Razors, 7 Minute Abs</title>
	<atom:link href="http://www.zachleat.com/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zachleat.com/web</link>
	<description></description>
	<lastBuildDate>Thu, 25 Feb 2010 05:27:08 +0000</lastBuildDate>
	
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Internet Explorer Array.sort Unreliable</title>
		<link>http://www.zachleat.com/web/2010/02/24/array-sort/</link>
		<comments>http://www.zachleat.com/web/2010/02/24/array-sort/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 02:09:52 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Internet Explorer]]></category>
		<category><![CDATA[JScript]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=568</guid>
		<description><![CDATA[What would you expect to be the result of executing the following code?

// Create a medium size array, at least 100 items
var obj = &#91;&#93;;
for&#40;var j=0, k=150; j&#60;k; j++&#41; &#123;
    // the value here doesn't matter.
    obj.push&#40;'ABCD'+j&#41;;
&#125;
&#160;
// Sort the array alphabetically.
obj.sort&#40;function&#40;m,p&#41;&#123;
    m=&#40;''+m&#41;.toLowerCase&#40;&#41;;
    p=&#40;''+p&#41;.toLowerCase&#40;&#41;;
&#160;
 [...]]]></description>
			<content:encoded><![CDATA[<p>What would you expect to be the result of executing the following code?</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Create a medium size array, at least 100 items</span>
<span style="color: #003366; font-weight: bold;">var</span> obj <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> j<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> k<span style="color: #339933;">=</span><span style="color: #CC0000;">150</span><span style="color: #339933;">;</span> j<span style="color: #339933;">&lt;</span>k<span style="color: #339933;">;</span> j<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// the value here doesn't matter.</span>
    obj.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'ABCD'</span><span style="color: #339933;">+</span>j<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Sort the array alphabetically.</span>
obj.<span style="color: #660066;">sort</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>m<span style="color: #339933;">,</span>p<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    m<span style="color: #339933;">=</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">''</span><span style="color: #339933;">+</span>m<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    p<span style="color: #339933;">=</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">''</span><span style="color: #339933;">+</span>p<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>m <span style="color: #339933;">&gt;</span> p<span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>m <span style="color: #339933;">&lt;</span> p<span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The <code>obj</code> Array should now be sorted, in alphabetical order based on value.  <strong>BUT, in our best friend Internet Explorer, a <code>Number Expected</code> error may be the result.</strong>  Don&#8217;t be fooled if your test array behaves correctly, it only happens intermittently for arrays of varying size!</p>
<p>So, I <a href="http://www.zachleat.com/test/numberexpected/">whipped up a quick test to check the damage</a>.  Iterating over array sizes from 1 to 150, running the Array sort algorithm.  The following failures resulted:</p>
<table>
<thead>
<tr>
<th>Browser</th>
<th>Failures *</th>
</tr>
</thead>
<tbody>
<tr>
<td>Internet Explorer 6</td>
<td>4 sizes out of 150</td>
</tr>
<tr>
<td>Internet Explorer 7</td>
<td>18 sizes out of 150</td>
</tr>
<tr>
<td>Internet Explorer 8 (and Compatibility Mode)</td>
<td>2 sizes out of 150</td>
</tr>
</tbody>
</table>
<p>* Failures may vary to the specifications of the test machine.</p>
<p>Of course, the <code>Number Expected</code> error is going to result whenever your code doesn&#8217;t return a number inside of the function callback.  But the problem here is something deeper than simple application code failure.  The problem is in JScript itself.  Any modification to the sort arguments may result in the <code>Number Expected</code> error.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">    m<span style="color: #339933;">=</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">''</span><span style="color: #339933;">+</span>m<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// modifies the argument m and is unreliable.</span></pre></div></div>

<p>This problem will manifest itself more frequently if you use the Google Closure Compiler, which restructures JavaScript to reuse argument variables if possible, probably to save the 4 character penalty of a &#8220;var &#8221; declaration.</p>
<p>Normally, reusing argument variables is a safe practice for primitives, since they are passed by value and not by reference, as is the case in this Array sort example <sup><a href="#by-ref">1</a></sup>.  So, what exactly is going on here?  One commenter at the <a href="http://code.google.com/p/closure-compiler/issues/detail?id=58">Google Closure Compiler bug</a> seems to think that the actual array values are being passed by reference instead of by value.  I&#8217;m not completely convinced that&#8217;s the case.</p>
<h2>The Fix</h2>
<p><strong>Don&#8217;t reuse the argument variables inside of an Array sort function.</strong></p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Changing the above example</span>
obj.<span style="color: #660066;">sort</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>m1<span style="color: #339933;">,</span>p1<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> m<span style="color: #339933;">=</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">''</span><span style="color: #339933;">+</span>m1<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        p<span style="color: #339933;">=</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">''</span><span style="color: #339933;">+</span>p1<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>m <span style="color: #339933;">&gt;</span> p<span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>m <span style="color: #339933;">&lt;</span> p<span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><em>Check the <a href="http://www.zachleat.com/test/numberexpected/">source code of the demo file</a> to see the different methods of modifying the arguments that I attempted.</em></p>
<ol>
<li id="by-ref">If you want to learn more about passing by value or reference, <a href="http://snook.ca/archives/javascript/javascript_pass">Jonathan Snook has a nice explanation</a>.</li>
</ol>
<p><em style="font-size: 80%">Internet Explorer can&#8217;t make you do anything, it can only make you wish you hadn&#8217;t.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2010/02/24/array-sort/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>If the Menu Fitts, We Must Acquit</title>
		<link>http://www.zachleat.com/web/2010/02/15/if-the-menu-fitts-we-must-acquit/</link>
		<comments>http://www.zachleat.com/web/2010/02/15/if-the-menu-fitts-we-must-acquit/#comments</comments>
		<pubDate>Tue, 16 Feb 2010 05:52:14 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Interface Design]]></category>
		<category><![CDATA[Usability]]></category>
		<category><![CDATA[Fitts's Law]]></category>
		<category><![CDATA[Gmail]]></category>
		<category><![CDATA[Google Reader]]></category>
		<category><![CDATA[MacOS]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=542</guid>
		<description><![CDATA[One of the first things you&#8217;ll learn when diving into a self-taught course on usability is the hugely popular Fitts&#8217;s Law.  In a nutshell, Fitts&#8217;s Law tries to predict the time needed to move to a &#8220;target area&#8221; (usually a link, menu, button, or form element) as a function of the distance to the [...]]]></description>
			<content:encoded><![CDATA[<p>One of the first things you&#8217;ll learn when diving into a self-taught course on usability is the hugely popular Fitts&#8217;s Law.  In a nutshell, Fitts&#8217;s Law tries to predict the time needed to move to a &#8220;target area&#8221; (usually a link, menu, button, or form element) as a function of the distance to the element and its size.  <strong>The bigger/closer the element, the faster a user can move to it.</strong></p>
<p>Now, upon discovering myself a newly minted Mac OS convert from the hugely popular World of Windows, I quickly discovered that the application menus (File, Edit, etc) were one of the glaring differences I&#8217;d have to adjust to.  Mac OS had all menus separated from the application window, all the way at the top of the screen.  Coming from the Windows environment, this seemed unintuitive.  But after reading more about Fitts&#8217;s Law, I discovered the reasoning: the <a href="http://www.codinghorror.com/blog/2006/08/fitts-law-and-infinite-width.html">edges of the screen are treated as an infinite height or width</a>!  Which is just a way of modifying the Fitts&#8217;s Law to say: <strong>the easiest things to click on are at the edges of the screen.</strong>  That&#8217;s why the close icon or the Start Menu is so easy to access on Windows, and <a href="http://www.asktog.com/basics/firstPrinciples.html#fittsLaw">why the Application Menu is at the top of the screen in Mac OS</a>.</p>
<p>We know about Fitts&#8217;s Law, but <strong>why aren&#8217;t we applying it to our web applications?</strong>  Why aren&#8217;t we using the power of infinite height/width to help out on our designs?  It seems like this crucial usability law has been overlooked on the web, and without good reason. Let&#8217;s look at a few applications that get it wrong (of course, in my humble opinion).</p>
<p><img src="http://www.zachleat.com/web/wp-content/uploads/2010/02/Screen-shot-2010-02-15-at-11.08.15-PM.png" alt="Wordpress Admin Menu" title="Screen shot 2010-02-15 at 11.08.15 PM" width="174" height="307" class="alignleft size-full wp-image-550"/><img src="http://www.zachleat.com/web/wp-content/uploads/2010/02/Screen-shot-2010-02-15-at-11.12.57-PM.png" alt="Google Mail Menu" title="Screen shot 2010-02-15 at 11.12.57 PM" width="176" height="251" class="alignleft size-full wp-image-552"/><img src="http://www.zachleat.com/web/wp-content/uploads/2010/02/Screen-shot-2010-02-15-at-11.09.16-PM.png" alt="Google Reader Menu" title="Screen shot 2010-02-15 at 11.09.16 PM" width="192" height="367" class="alignleft size-full wp-image-551" /></p>
<div style="clear: left"></div>
<p>All of these screenshots were taken from 100% width designs, with no real reason not to incorporate the ideas behind Fitts&#8217;s Law into the menuing system.  At first glance when I brought up Google Reader, I was excited.  The hover behavior appeared when the mouse cursor was positioned at the very far left of the screen, but was disappointed to discover that the although the hover background color had changed, the entire hover target was not clickable.</p>
<p>Naturally, I decided to make a test of my own, to test which web browsers allowed <em>Fitts&#8217;s Law Menus</em>.  The test case encompassed both left and bottom aligned menus, for completeness.  A top menu was excluded, given that the top of the screen is reserved for browser chrome or application menuing.  A right menu was also excluded as the right portion of the screen is reserved for the page scrollbar (which is the easiest scrollbar to manipulate with your mouse, per the same rules).</p>
<p>Also, on the Mac OS 10.6 and Windows XP operating systems, a <em>Fitts&#8217;s Law Menu</em> at the bottom of the screen is not possible, given that the Dock and Taskbar in these operating systems occupy at least a 4 pixel trough of the bottom-most space on the monitor, even as a hover target in &#8220;auto-hide&#8221; mode.  <strong>Everyone is fighting over these crucial and very useful edge pixels.</strong></p>
<p>To test whether or not this behavior is working correctly, <strong>maximize your browser window</strong> and <strong>move the cursor as far left on the screen as possible</strong>, but still over the menu.  If the links are still clickable, congratulations, your browser works!</p>
<h2><a href="/test/fittmenu/">View the Demo / Test Page for the Fitts&#8217;s Law Menu</a></h2>
<h2>Compatibility Table</h2>
<style type="text/css"> 
#compatibility td { font-family: Verdana; }
#compatibility td.yes { background-color: #00882D; color: #fff; }
#compatibility td.no { background-color: #CB000F; color: #fff; }
#compatibility td.emulate { background-color: #40A662; color: #fff; }</p>
</style>
<table id="compatibility">
<thead>
<tr>
<th>Browser</th>
<th>Operating System</th>
<th>Left Menu</th>
<th>Bottom Menu</th>
<th>Status Bar</th>
<th>Detail</th>
</tr>
</thead>
<tbody>
<tr>
<td>Internet Explorer 8</td>
<td>Windows XP</td>
<td class="no">no</td>
<td class="no">no</td>
<td>yes</td>
<td>IE8 has a small 3 pixel border on the left and right of each window.</td>
</tr>
<tr>
<td>Internet Explorer 7</td>
<td>Windows XP</td>
<td class="no">no</td>
<td class="no">no</td>
<td>yes</td>
<td>IE7 has a small 3 pixel border on the left and right of each window.</td>
</tr>
<tr>
<td>Internet Explorer 6</td>
<td>Windows XP</td>
<td class="no">no</td>
<td class="no">no</td>
<td>yes</td>
<td>IE6 has a small 3 pixel border on the left and right of each window.</td>
</tr>
<tr>
<td>Google Chrome</td>
<td>Windows XP and Mac OS 10.6</td>
<td class="yes">yes</td>
<td class="no">no</td>
<td>no</td>
<td></td>
</tr>
<tr>
<td>Mozilla Firefox 3.5 and 3.6</td>
<td>Windows XP and Mac OS 10.6</td>
<td class="yes">yes</td>
<td class="no">no</td>
<td>yes</td>
<td></td>
</tr>
<tr>
<td>Safari 4.0.4</td>
<td>Windows XP and Mac OS 10.6</td>
<td class="yes">yes</td>
<td class="no">no</td>
<td>no</td>
<td></td>
</tr>
</tbody>
</table>
<p><em>The full screen mode of each individual browser was considered outside the scope of this study.</em></p>
<h2>Conclusion</h2>
<p>We should stand on the shoulders of giants and reuse the usability studies already completed on software that has gone before us.  The left side of the browser window is the best place to utilize Fitts&#8217;s Law, and we should move our left-aligned menus on fluid width designs to occupy the space flush with the window&#8217;s edge to increase the speed at which those menus will be accessible by users.  Having an infinite width menu is a big click target to hit.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2010/02/15/if-the-menu-fitts-we-must-acquit/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>CSS 3 Text: A Tale of writing-mode Woe</title>
		<link>http://www.zachleat.com/web/2010/02/12/css3-text-writing-mode/</link>
		<comments>http://www.zachleat.com/web/2010/02/12/css3-text-writing-mode/#comments</comments>
		<pubDate>Sat, 13 Feb 2010 04:45:54 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Web Browsers]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=496</guid>
		<description><![CDATA[After reading an interesting article on using the writing-mode CSS property to display vertical text (I&#8217;m always interested in how to abuse what browsers currently support into something new and exciting), I decided to look into this writing-mode property and see what opportunities it might present.
Generally when exploring a development opportunity, I tend to prioritize [...]]]></description>
			<content:encoded><![CDATA[<p>After reading an interesting article on using the <a href="http://www.thecssninja.com/css/real-text-rotation-with-css">writing-mode CSS property</a> to display vertical text (I&#8217;m always interested in how to abuse what browsers currently support into something new and exciting), I decided to look into this <code>writing-mode</code> property and see what opportunities it might present.</p>
<p>Generally when exploring a development opportunity, I tend to prioritize my adventures towards things that are supported in Internet Explorer first.  This often has the biggest cross-browser payoff, since the other browser vendors tend to have a quicker draw than the Microsoft Team.  However, surprisingly enough, this <code>writing-mode</code> study proved the opposite to be true.  It seems very interesting that Microsoft has decided to implement a portion of the CSS 3 specification, given its general stance of moving slower than an iceberg to avoid &#8220;breaking the web.&#8221;  But I, for one, welcome our new choose-your-own-adventure standards loving overlords.</p>
<p>As far as my tests go, the only browser to support the <code><a href="http://www.w3.org/TR/2003/CR-css3-text-20030514/#writing-mode">writing-mode</a></code> property at all is Internet Explorer, which was very surprising.  At it&#8217;s heart, though, <code>writing-mode</code> is just shorthand for two other properties: <code><a href="http://www.w3.org/TR/2003/CR-css3-text-20030514/#direction">direction</a></code> and <code><a href="http://www.w3.org/TR/2003/CR-css3-text-20030514/#block-progression">block-progression</a></code>.  Luckily, <strong>Firefox, Safari, Chrome and IE back through at least version 6 support the <code><a href="https://developer.mozilla.org/en/CSS/direction">direction</a></code> property</strong> and have proprietary options for rotation, which <strong>allows for emulation of a few of the unsupported <code>writing-mode</code>&#8217;s</strong>, but not all of them.  The missing piece of <code>writing-mode</code> emulation belongs to the <code>block-progression</code> property, which isn&#8217;t supported by anyone, and would allow elements to flow reverse vertically (start at the bottom of a block and flow upwards).</p>
<p><em>It&#8217;s important to note that while <a href="http://blogs.msdn.com/ie/archive/2009/05/29/the-css-corner-writing-mode.aspx">IE8 has really set the bar for implementation here</a> and has chosen to support <code>writing-mode: lr-bt</code> and <code>writing-mode: rl-bt</code>, they aren&#8217;t used to display any known language text.  They&#8217;re just included for completeness, and aren&#8217;t a part of the <a href="http://www.w3.org/TR/2003/CR-css3-text-20030514/">W3C CSS 3 Text Module specification.</a></em></p>
<h2><a href="http://zachleat.com/test/writing-mode/">View the Demo / Test Page</a></h2>
<h2>Compatibility Table</h2>
<style type="text/css">
#compatibility td { font-family: Verdana; }
#compatibility td.yes { background-color: #00882D; color: #fff; }
#compatibility td.no { background-color: #CB000F; color: #fff; }
#compatibility td.emulate { background-color: #40A662; color: #fff; }</p>
</style>
<table id="compatibility">
<thead>
<tr>
<th rowspan="2">writing-mode</th>
<th colspan="3">Internet Explorer<br/>(Trident)</th>
<th>Mozilla Firefox<br/>(Gecko)</th>
<th>Apple Safari<br/>(Webkit)</th>
<th>Google Chrome<br/>(Webkit)</th>
</tr>
<tr>
<th>6</th>
<th>7</th>
<th>8</th>
<th>3.6</th>
<th>4</th>
<th>4</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>lr-tb</code></td>
<td class="yes">yes</td>
<td class="yes">yes</td>
<td class="yes">yes</td>
<td class="yes">yes</td>
<td class="yes">yes</td>
<td class="yes">yes</td>
</tr>
<tr>
<td><code>rl-tb</code></td>
<td class="emulate">emulatable</td>
<td class="yes">yes</td>
<td class="yes">yes</td>
<td class="emulate">emulatable</td>
<td class="emulate">emulatable</td>
<td class="emulate">emulatable</td>
</tr>
<tr style="background-color: #eee;">
<td><code>lr-bt</code></td>
<td class="no">no</td>
<td class="no">no</td>
<td class="yes">yes</td>
<td class="no">no</td>
<td class="no">no</td>
<td class="no">no</td>
</tr>
<tr style="background-color: #eee;">
<td><code>rl-bt</code></td>
<td class="no">no</td>
<td class="no">no</td>
<td class="yes">yes</td>
<td class="no">no</td>
<td class="no">no</td>
<td class="no">no</td>
</tr>
<tr>
<td><code>tb-lr</code></td>
<td class="no">no</td>
<td class="no">no</td>
<td class="yes">yes</td>
<td class="no">no</td>
<td class="no">no</td>
<td class="no">no</td>
</tr>
<tr>
<td><code>tb-rl</code></td>
<td class="yes">yes</td>
<td class="yes">yes</td>
<td class="yes">yes</td>
<td class="emulate">emulatable</td>
<td class="emulate">emulatable</td>
<td class="emulate">emulatable</td>
</tr>
<tr>
<td><code>bt-lr</code></td>
<td class="no">no</td>
<td class="no">no</td>
<td class="yes">yes</td>
<td class="no">no</td>
<td class="no">no</td>
<td class="no">no</td>
</tr>
<tr>
<td><code>bt-rl</code></td>
<td class="emulate">emulatable</td>
<td class="yes">yes</td>
<td class="yes">yes</td>
<td class="emulate">emulatable</td>
<td class="emulate">emulatable</td>
<td class="emulate">emulatable</td>
</tr>
</tbody>
</table>
<h2>CSS Code for Emulation</h2>
<table>
<thead>
<tr>
<th>writing-mode</th>
<th>CSS</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>lr-tb</code></td>
<td>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">// Default</pre></div></div>

</td>
</tr>
<tr>
<td><code>rl-tb</code></td>
<td>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">direction</span><span style="color: #00AA00;">:</span> rtl<span style="color: #00AA00;">;</span></pre></div></div>

</td>
</tr>
<tr style="background-color: #eee;">
<td><code>lr-bt</code></td>
<td>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">// Not possible using W3C spec</pre></div></div>

</td>
</tr>
<tr style="background-color: #eee;">
<td><code>rl-bt</code></td>
<td>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">// Not possible using W3C spec</pre></div></div>

</td>
</tr>
<tr>
<td><code>tb-lr</code></td>
<td>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">// Not possible using W3C spec</pre></div></div>

</td>
</tr>
<tr>
<td><code>tb-rl</code></td>
<td>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">-webkit-transform<span style="color: #00AA00;">:</span> rotate<span style="color: #00AA00;">&#40;</span>90deg<span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>
-moz-transform<span style="color: #00AA00;">:</span> rotate<span style="color: #00AA00;">&#40;</span>90deg<span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>
filter<span style="color: #00AA00;">:</span> progid<span style="color: #3333ff;">:DXImageTransform</span><span style="color: #6666ff;">.Microsoft</span>.BasicImage<span style="color: #00AA00;">&#40;</span>rotation<span style="color: #00AA00;">=</span><span style="color: #cc66cc;">1</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span></pre></div></div>

</td>
</tr>
<tr>
<td><code>bt-lr</code></td>
<td>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">// Not possible using W3C spec</pre></div></div>

</td>
</tr>
<tr>
<td><code>bt-rl</code></td>
<td>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">direction</span><span style="color: #00AA00;">:</span> rtl<span style="color: #00AA00;">;</span>
-webkit-transform<span style="color: #00AA00;">:</span> rotate<span style="color: #00AA00;">&#40;</span>90deg<span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>
-moz-transform<span style="color: #00AA00;">:</span> rotate<span style="color: #00AA00;">&#40;</span>90deg<span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>
filter<span style="color: #00AA00;">:</span> progid<span style="color: #3333ff;">:DXImageTransform</span><span style="color: #6666ff;">.Microsoft</span>.BasicImage<span style="color: #00AA00;">&#40;</span>rotation<span style="color: #00AA00;">=</span><span style="color: #cc66cc;">1</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span></pre></div></div>

</td>
</tr>
</tbody>
</table>
<h2>Conclusion</h2>
<p>Given that <strong>4 of the 6 known writing modes are available</strong> or available through CSS emulation means we&#8217;re in pretty good shape on the internationalization front.  Consulting the Microsoft provided table for common use cases, we&#8217;re only in trouble when trying to use the &#8220;Mongolian script writing system&#8221; and an &#8220;Arabic script block quote embedded in Mongolian script document.&#8221;</p>
<p>In some far fetched fantasy-world legacy application where a page may use tables for layout, I could see an application team possibly using the <code>direction</code> property to redistribute the tables for a print stylesheet.  But that certainly wouldn&#8217;t be a common use case, since using CSS for layouts is going to give you much more flexibility in that regard.  If you can think of any other off the wall uses for <code>writing-mode</code> or <code>direction</code>, I&#8217;d love to hear them!</p>
<h2>Related</h2>
<ul>
<li>Very <a href="http://fantasai.inkedblade.net/style/discuss/vertical-text/#logical">complete article on CSS 3 writing-mode</a>, including some <code>direction</code> properties that don&#8217;t exist in the specification (like <code>ttb</code>, <code>ltr-ttb</code>, and <code>ltr-btt</code>)</li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=writing-mode">Bugzilla Bug for writing-mode in Firefox</a></li>
<li>As of the time of this writing, I was unable to find any results for writing-mode on the Webkit bug tracker.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2010/02/12/css3-text-writing-mode/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Trash that &#8220;Back to Top&#8221; Link</title>
		<link>http://www.zachleat.com/web/2010/02/05/trash-that-back-to-top-link/</link>
		<comments>http://www.zachleat.com/web/2010/02/05/trash-that-back-to-top-link/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 01:30:30 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Interface Design]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Page Fold]]></category>
		<category><![CDATA[Scrolling]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=376</guid>
		<description><![CDATA[It would seem that perfection is attained not when no more can be added, but when no more can be removed.
- Antoine de Saint Exupéry


While most would argue that the principles espoused in the above quote might also be applied to the quote itself, it would serve us better to consider how we can attempt [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>It would seem that perfection is attained not when no more can be added, but when no more can be removed.</p>
<div style="text-align: right;">- Antoine de Saint Exupéry</div>
</blockquote>
<p><br/><br />
While most would argue that the principles espoused in the above quote might also be applied to the quote itself, it would serve us better to consider how we can <strong>attempt perfection in our User Interface designs</strong> instead.</p>
<p>The most complete litany of reasons why you should spend your page weight on more useful bytes has been <a href="http://www.cs.tut.fi/~jkorpela/www/totop.html">compiled by Jukka Korpela</a>, although he seems to both confirm that they are harmful and still use them on his site.</p>
<p>The rules of engagement I find useful when dealing with the ill-fated &#8220;Back to Top&#8221; or its ugly stepsister &#8220;Top of Page&#8221; link are as follows:</p>
<ol>
<li><strong>Delete the link.</strong></li>
</ol>
<p>Really, you don&#8217;t need the link. It&#8217;s a <strong>sacred cow remnant</strong> of a time when people believed that all content needed to be positioned <a href="http://iampaddy.com/lifebelow600/">above the page fold</a>.</p>
<p>Guess what?  <strong>People know how to scroll!</strong>  They know how to scroll down, they know how to scroll up.  Considering this prerequisite has been met, it becomes very apparent that the &#8220;Back to Top&#8221; link shares an <strong>unnecessary overlap in functionality with the scrollbar</strong> and is thus, unnecessary itself.</p>
<p>If you have an incredibly long page with a full set of &#8220;Table of Contents&#8221; links, it would be better to position your <a href="http://jqueryfordesigners.com/fixed-floating-elements/">table of contents fixed to the viewport</a>, so as to make it always available to the user.  If the Table of Contents is always available, the user will never have to click a link as a shortcut to find it.</p>
<p>While not a usability epidemic, the &#8220;Back to Top&#8221; link is still widely used.  <a href="http://www.instantshift.com/2009/07/14/90-creative-back-to-top-links-and-best-practices/">Instant Shift</a> and <a href="http://www.smashingmagazine.com/2008/11/27/short-story-about-top-links/">Smashing Magazine</a> both have articles with hundreds of examples of sites with these links.</p>
<p>Don&#8217;t agree? If you&#8217;re stubborn as hell and hate simplicity, you&#8217;re going to keep the link on your page no matter what reasons are presented.  In that case, at the very least follow these two guidelines:</p>
<ol>
<li>Use <strong>progressive enhancement</strong>:

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;back-to-top&quot;</span>&gt;</span>Back to Top<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// jQuery Prerequisite</span>
$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#back-to-top'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">click</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    window.<span style="color: #660066;">scrollTo</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// don't change the hash if not needed</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

</li>
<li><strong>Hide the link</strong> if the page doesn&#8217;t have a scrollbar.  If no scrollbar exists, the user will <strong>always be &#8220;at the top.&#8221;</strong>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Continuing with Previous Example</span>
$<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#back-to-top'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">hide</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// If the page scrolls, we know there is a scrollbar.</span>
$<span style="color: #009900;">&#40;</span>window<span style="color: #009900;">&#41;</span>.<span style="color: #000066;">scroll</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#back-to-top'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// For completeness, you may also want to</span>
<span style="color: #006600; font-style: italic;">//   add logic to the &quot;resize&quot; event.</span></pre></div></div>

</li>
</ol>
<p>Really though, <strong>just delete the link.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2010/02/05/trash-that-back-to-top-link/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The &#8220;24&#8243; Clock on ALARMd</title>
		<link>http://www.zachleat.com/web/2010/01/24/the-24-clock-on-alarmd/</link>
		<comments>http://www.zachleat.com/web/2010/01/24/the-24-clock-on-alarmd/#comments</comments>
		<pubDate>Sun, 24 Jan 2010 07:37:52 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Alarmd]]></category>
		<category><![CDATA[font-face]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=465</guid>
		<description><![CDATA[If you&#8217;re only using @font-face for titles and text, you&#8217;re missing out on a whole wealth of use cases that have yet to be explored.  For instance, I created a very simple 7 Segment Display Numeric font to be used for a skin on alarmd.com and changed the color using nothing but CSS to [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re only using @font-face for titles and text, you&#8217;re missing out on a whole <a href="http://www.zachleat.com/web/2010/01/03/css-sprites-using-font-face/">wealth of use cases</a> that have yet to be explored.  For instance, I created a very simple <a href="http://fontstruct.fontshop.com/fontstructions/show/282059">7 Segment Display Numeric font</a> to be used for a skin on <a href="http://www.alarmd.com/">alarmd.com</a> and changed the color using nothing but CSS to create the &#8220;24&#8243; Clock (true fans will note that the actual font is italic and <a href="http://www.panopticist.com/2006/05/there_is_something_weird_going_on_with_the_clock_on_24.php">has a serif on the 1</a>).  Nonetheless, this is just another useful application of @font-face.</p>
<p>Take a look at the <a href="http://www.fontsquirrel.com/fonts/list/style/Dingbat">Dingbats section on fontsquirrel</a> to get your brain going in the same direction.</p>
<p><img src="http://www.zachleat.com/web/wp-content/uploads/2010/01/Screen-shot-2010-01-24-at-1.22.39-AM.png" alt="" title="Screenshot of the 24 Clock on alarmd.com"/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2010/01/24/the-24-clock-on-alarmd/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>DIY Webdings &#8211; CSS Sprites using @font-face</title>
		<link>http://www.zachleat.com/web/2010/01/03/css-sprites-using-font-face/</link>
		<comments>http://www.zachleat.com/web/2010/01/03/css-sprites-using-font-face/#comments</comments>
		<pubDate>Mon, 04 Jan 2010 00:48:29 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[css-sprites]]></category>
		<category><![CDATA[font-face]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=433</guid>
		<description><![CDATA[Almost everyone knows the Webdings font or its sibling Wingdings.  Even if you don&#8217;t, chances are pretty good that it&#8217;s installed on your system.
Webdings is a symbol font designed in 1997 as a response to the need of Web designers for a fast and easy method of incorporating graphics in their pages.
&#8230;
Webdings is ideal [...]]]></description>
			<content:encoded><![CDATA[<p>Almost everyone knows the Webdings font or its sibling Wingdings.  Even if you don&#8217;t, chances are pretty good that it&#8217;s installed on your system.</p>
<blockquote><p>Webdings is a symbol font designed in 1997 as a response to the need of Web designers for a fast and easy method of incorporating graphics in their pages.<br />
&#8230;</p>
<p>Webdings is ideal for enriching the appearance of a Web page. Because it’s a font, it can be installed on the user’s system, (or embedded in the document itself) is fully scaleable [sic] and quick to render. It’s a perfect way of including graphics on your site without making users wait for lots of graphic files to download.</p>
<p> &#8211; Source <a href="http://www.microsoft.com/typography/fonts/family.aspx?FID=5">Microsoft Typography</a></p></blockquote>
<p>Microsoft was onto something here, and there is a nice parallel that can be drawn between the font and a CSS sprite: namely that multiple images are stored under the guise of a single HTTP request.  So, why not create our own font and use it as a CSS sprite?  Each character in the font (glyph) will be a single image in the sprite.</p>
<h2>Why is this awesome?</h2>
<ul>
<li>We can <strong>change the color</strong> of our font using nothing but CSS <code>color</code>.  This is a big one.  We don&#8217;t have to have separate images for hover states!  And if we want to change the color scheme, there are no new images to generate and we don&#8217;t have to make any changes to the font to do so.</li>
<li>Don&#8217;t have to monkey around with difficult to maintain CSS positioning code.</li>
<li>Fonts scale, graphics don&#8217;t.  Zooming in on a graphic will result in a pixelated image, but fonts will be smooth like a 6 blade razor shave.  Try zooming on the demo file below.</li>
</ul>
<h2>Why is this not awesome?</h2>
<ul>
<li>Font glyphs can only contain one color.</li>
<li>May experience the Flash of unstyled text (FOUT) while the font is loading.</li>
<li>Extra markup required for IE6 and IE7.  While @font-face is supported in all non-extinct versions of IE, each @font-face sprite requires a corresponding text character on the screen.  For instance, <code>&lt;span style="font-family: MyCustomFont;"&gt;A&lt;/span&gt;</code>, the A is required to display the @font-face Sprite stored under the A glyph.<br/><br />
Luckily, in most browsers we can inject a character using CSS :after/:before and the <code>content</code> property.  Unfortunately, this is <a href="http://www.quirksmode.org/css/beforeafter_content.html">not supported in IE6 or IE7</a>.  I haven&#8217;t investigated whether or not this might be solved using other means (CSS expressions) yet.</li>
<li>Safari asks for permission to use the font with a scary popup box, which I assume is a security precaution gleaned from the Windows Vista playbook.</li>
</ul>
<h2>Demo</h2>
<p>The following <a href="http://jquery-ui.googlecode.com/svn/trunk/tests/static/icons.html">jQuery UI Icons</a> are currently used in jQuery UI and are stored in <a href="http://jqueryui.com/themeroller/images/?new=888888&#038;w=256&#038;h=240&#038;f=png&#038;fltr[]=rcd|256&#038;fltr[]=mask|icons/icons.png">one big CSS sprite</a>.</p>
<p>It was pretty trivial to create <a href="http://fontstruct.fontshop.com/fontstructions/show/jquery_ui_icons_1">a font</a> with a subset of the jQuery UI icons (only the first 20, just a proof of concept here) using the wonderful <a href="http://fontstruct.fontshop.com/">FontStruct</a> utility.  Then, I took the TTF generated by FontStruct and plugged it into the completely lovely <a href="http://www.fontsquirrel.com/fontface/generator">FontSquirrel @font-face Kit Generator</a>.  That gave me everything I needed for a fully cross-browser test.</p>
<ul>
<li><a href="http://www.zachleat.com/test/fonts/font.html" style="font-size: 160%; font-weight: bold;">View the Demo</a></li>
</ul>
<p>Let me know what you think!</p>
<div style="font-size: 80%">
Successfully tested on:</p>
<ul>
<li>Google Chrome 4 (Mac)</li>
<li>Safari 4 (Mac)</li>
<li>Firefox 3.5 (Mac and Windows)</li>
<li>Internet Explorer 8</li>
<li>With documented limitations above:
<ul>
<li>Internet Explorer 6</li>
<li>Internet Explorer 7 (Compatibility Mode in IE8)</li>
</ul>
</li>
</ul>
<p>Does not work on (no @font-face support):</p>
<ul>
<li>Google Chrome 3 and prior</li>
<li>Firefox 3 and prior</li>
</ul>
</div>
<p>Read more about <a href="http://paulirish.com/2009/bulletproof-font-face-implementation-syntax/">@font-face support from Paul Irish</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2010/01/03/css-sprites-using-font-face/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t Give Up on Internet Explorer Yet</title>
		<link>http://www.zachleat.com/web/2009/12/09/dont-give-up-on-ie/</link>
		<comments>http://www.zachleat.com/web/2009/12/09/dont-give-up-on-ie/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 03:24:46 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Web Browsers]]></category>
		<category><![CDATA[Google Wave]]></category>
		<category><![CDATA[Internet Explorer]]></category>
		<category><![CDATA[Zombies]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=351</guid>
		<description><![CDATA[These days, the browser landscape is more fragmented than ever.  Were times easier back when IE6 and Firefox ruled the internet? Easier perhaps in terms of the number of browsers you had to launch for testing, but not better for any user&#8217;s experience. We are in a new world, where more web browsers are [...]]]></description>
			<content:encoded><![CDATA[<p>These days, the browser landscape is more fragmented than ever.  Were times easier back when IE6 and Firefox ruled the internet? Easier perhaps in terms of the number of browsers you had to launch for testing, but <strong>not better</strong> for any user&#8217;s experience. We are in a new world, where more web browsers are causing developers to become <strong>increasingly pragmatic</strong> with their designs and code. Sure, standards have created a safe haven under the newest versions of the Big 3 (Firefox, IE, Safari), but the lay majority are still using whatever default has been installed onto their computer, and they probably can&#8217;t tell you <a href="http://googlesystem.blogspot.com/2009/06/browser-is-search-engine.html">the difference between their web browser and a search engine</a>.</p>
<p>We must be resilient to resist the transformation from development pragmatism to user abandonment, especially considering a developer&#8217;s trend of being insulated with the latest equipment.  We use the newest hardware and download the most sophisticated browser software because we want the best experiences.  We stack the cards in our favor.  The difficulty lies with the populace that <strong>want a good experience</strong> (they can tell a fast site from a slow site), but they <strong>don&#8217;t want to buy new equipment or install a better browser.</strong>  So the question has become: Where do you place your chips on the spectrum balancing modern hardware/software and the user experience?</p>
<p><img src="http://www.zachleat.com/web/wp-content/uploads/2009/12/zombies.png" alt="zombie" title="zombie" width="200" height="234" class="alignright size-full wp-image-361" />As web developers, it has become increasingly easy to become disenfranchised with the lay majority&#8217;s computing environment.  I&#8217;ve witnessed this personally after purchasing my first Apple computer, a device curiously immune to the plague of IE 6/7 (8 as well, but I would hesitate to label it as a plague, more like a normal run of the mill flesh eating virus).  It&#8217;s an interesting phenomenon, being cutoff from the Windows environment (save virtualization) during development.  It&#8217;s delightfully tempting to declare damnation upon the plague ridden Internet Explorer Zombies, and develop your web presence to standards alone, allowing less focus on the harshest development environment imaginable and more on actual problem solving.</p>
<p>When developers engage in quasi-web development, perhaps in the form of an iPhone specific web application or an Adobe AIR desktop application, it fosters similar feelings.   The work shares many languages and technologies with real (wide-open) web development, but is targeted towards a single web browser.  This benefits of this sort of tunnel vision device targeting must be carefully weighed against the penalties you&#8217;re paying in narrowed default-install client compatibility.  At that point, it&#8217;s just <strong>friends with benefits</strong>.</p>
<p><img src="http://www.zachleat.com/web/wp-content/uploads/2009/12/google-wave-ie8.png" alt="Denial of Access with Internet Explorer Screenshot" title="Denial of Access with Internet Explorer Screenshot" width="454" height="339" class="aligncenter size-full wp-image-363" /><br />
Google Wave, in fact, requires the use of Safari, Firefox, Chrome, or the Google Chrome Frame plugin (which doesn&#8217;t count as actual browser support).  As of the time this article was written, as many as <strong>64% of all users</strong> (<a href="http://en.wikipedia.org/wiki/Usage_share_of_web_browsers">source</a>) are met with the above screen when trying to access Google Wave. Let&#8217;s be clear: <strong>Ease of development is not an excuse to abandon users.</strong>  Whatever happened to <a href="http://www.zachleat.com/web/2009/08/29/device-independence/">Device Independence</a>?</p>
<p>Not surprisingly, Google Wave&#8217;s stand against Internet Explorer <strong>has not started a trend</strong>.  Instead of all out war, the community at large has decided that subtlety is what&#8217;s needed to win this fight.  Let&#8217;s hold back the <a href="http://en.wikipedia.org/wiki/Sexual_Healing">sexual healing</a> of rounded corners, even though perhaps users will call our design harsh or cold.  Let&#8217;s give them plain buttons instead of nice three dimensional buttons with text and box shadows, even though they may be less actionable.</p>
<p>Let&#8217;s make it easier on ourselves at the expense of the user experience of The Zombie Majority.  We make this sacrifice because we assume that Zombies won&#8217;t be able to tell the difference between eating a big juicy Einstein brain and a smaller but nonetheless still tasty brush clearing George W.  And you know what, <strong>I think we&#8217;re right.</strong></p>
<p><em><strong>Updated</strong> to include a few more thoughts on Adobe AIR and the iPhone.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/12/09/dont-give-up-on-ie/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Device Independence on the Open Web</title>
		<link>http://www.zachleat.com/web/2009/08/29/device-independence/</link>
		<comments>http://www.zachleat.com/web/2009/08/29/device-independence/#comments</comments>
		<pubDate>Sat, 29 Aug 2009 18:37:12 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Application Design]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=329</guid>
		<description><![CDATA[Open Web advocacy can get pretty lonely working in Big Enterprise.  Armed with slow moving standards bodies, and held back by antiquated browser support, architectural battles over tools and frameworks can get pretty hairy if you don&#8217;t approach them with the right frame of mind.
Big Enterprise is traditionally known for creating development environments that [...]]]></description>
			<content:encoded><![CDATA[<p>Open Web advocacy can get pretty lonely working in Big Enterprise.  Armed with slow moving standards bodies, and held back by antiquated browser support, architectural battles over tools and frameworks can get pretty hairy if you don&#8217;t approach them with the right frame of mind.</p>
<p>Big Enterprise is traditionally known for creating development environments that foster a &#8220;get it done&#8221; mentality, often rewarding results over correctness (mileage, of course, may vary).</p>
<blockquote><p>My company uses IE6, and the application works in IE6, so it&#8217;s done!</p></blockquote>
<p>This little quagmire is amplified by the fact that when using Open Web technology, there are many ways to get things done, and most of them are incorrect.  But those mistakes don&#8217;t manifest themselves until the project is in the hands of the end user, whom we often punish for our oversight.</p>
<p>But there is hope. Using the power of web standards and Open Web best practices, we can achieve something panoramically, not microscopically, beautiful.</p>
<p>The secret sauce of building for the Web isn&#8217;t its distribution model, in which updates are managed on the web server without the need to update software on the client (although the Anti-IE6 vigilantes would tell you differently).  It most certainly isn&#8217;t development efficiency, as most people new to the game will so readily inform you of.  Cross browser quirks due to non-standard browser implementations of CSS and JavaScript, or vague standards specifications have seen to that.</p>
<blockquote><p>When I was writing Visual Basic, I got my job done so much quicker and easier!</p></blockquote>
<h2>The power of the Open Web is Device Independence.</h2>
<p>Visitors to our sites <strong>shouldn&#8217;t be met with warnings</strong> about what device they&#8217;ve chosen to use.</p>
<blockquote><p>This site viewable only in IE7+, Firefox, Chrome, or Safari, and at minimum 1024&#215;768 resolution.</p></blockquote>
<blockquote><p>This site requires Flash or Silverlight</p></blockquote>
<p>I realize that this is a controversial stance, especially given that most sites are dropping support for IE6, and more are relying on Flash and Silverlight plugins.  <strong>Architect applications to your client device usage statistics, and don&#8217;t let your tools shape the statistics for you.</strong>  Using techniques like progressive enhancement, we can ensure that our sites degrade gracefully to the capabilities of the client device.  At it&#8217;s truest form, this is basic accessibility. But, Device Independence might be a more accurate term, since accessibility is unfortunately an overloaded term scoped solely with devices tied to disabilities (screen readers, for example).  While screen readers are a very important piece, there is a bigger picture.</p>
<p>When the iPhone came out, there was an uproar because it didn&#8217;t support Flash, for battery life and other reasons.  But the uproar was from developers who had designed applications specifically for Flash!  Would you say that those Flash applications were designed with device independence in mind?  YouTube got around this by encoding their videos in MP4 format, which arguably has a higher device independence rating than the Flash format.</p>
<p>Keep in mind that we&#8217;re <strong>not attempting to handle every permutation of end user browser settings</strong>, since most don&#8217;t change the defaults.  Instead we are trying to scoop up the largest base of supported devices with the least amount of effort!  Who cares if an end user disabled JavaScript in their preferences?  I&#8217;m more worried about the mobile browser that doesn&#8217;t even support JavaScript at all.  But when you use Open Web properly, you get support for both!</p>
<h2>Output Device Independence</h2>
<ul>
<li>Full Web Browsers: Does your site work in Opera? Don&#8217;t worry about pixel perfection, that&#8217;s something completely different &#8212; does it work?</li>
<li>Web Browsers on Mobiles</li>
<li>Search Engine Spiders and other Screen Scrapers</li>
<li>Screen Readers</li>
<li>Printers: Ever had to make an entirely separate page for print-friendly version of your application? Flash/Silverlight <strong>do not</strong> print well</li>
<li>Televisions: Xbox 360, Wii, and Other Media Center Devices</li>
<li>Projectors</li>
<li><em>and more&#8230;</em></li>
</ul>
<p>Take a look at the <a href="http://www.w3.org/TR/CSS21/media.html#media-types">CSS specification for media types</a>.  The standards are there!  Support for CSS media types isn&#8217;t fool proof by any means, but the end goal is clearly visible.</p>
<h2>Input Device Independence</h2>
<p>But I&#8217;m not just talking about output device independence either.  User interfaces should be adaptable to different input devices as well.</p>
<ul>
<li>Mouse</li>
<li>Keyboard (often overlooked in web applications)</li>
<li>Touch Screens (Single and <a href="http://hacks.mozilla.org/2009/08/multi-touch-firefox/">Multi-touch</a>)</li>
<li>Voice, Motion Capture, and Facial Recognition (the standards and technology aren&#8217;t quite there yet, but <a href="http://hacks.mozilla.org/2009/06/connecting-html5-video/">progress is being made</a>)</li>
<li><em>and more&#8230;</em></li>
</ul>
<p>The world is developing the Open Web, and it isn&#8217;t limited by a single company&#8217;s goals and timelines.  At times, Open Web may seem like it&#8217;s a very slow moving <strong>glacier</strong> headed our way, but what else can you do but laugh when companies try to <strong>power their Titanic right through it</strong>?</p>
<p><em>Article originally inspired by <a href="http://developer.yahoo.com/yui/articles/gbs/#history">Yahoo&#8217;s Graded Browser Support</a>.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/08/29/device-independence/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Quick Performance Tip: jQuery and addClass</title>
		<link>http://www.zachleat.com/web/2009/06/30/quick-performance-tip-jquery-and-addclass/</link>
		<comments>http://www.zachleat.com/web/2009/06/30/quick-performance-tip-jquery-and-addclass/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 04:51:01 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=226</guid>
		<description><![CDATA[Abstractions are helpful and dangerous.  But the more we know about a library&#8217;s internals, the less danger we&#8217;ll be in later.  Here&#8217;s an issue I ran into where I had assumed that jQuery would be optimized for this case, but it wasn&#8217;t.  I&#8217;ll go over my bad assumption and how to workaround [...]]]></description>
			<content:encoded><![CDATA[<p>Abstractions are helpful and dangerous.  But the more we know about a library&#8217;s internals, the less danger we&#8217;ll be in later.  Here&#8217;s an issue I ran into where I had assumed that jQuery would be optimized for this case, but it wasn&#8217;t.  I&#8217;ll go over my bad assumption and how to workaround it.</p>
<p>As of jQuery 1.3.2, adding multiple HTML classes to an element using jQuery&#8217;s addClass method will add them one at a time, modifying the className property of an element for each class.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#myElement'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">addClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'myFirstClass mySecondClass'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Here&#8217;s the original code inside of jQuery 1.3.2.  Note how the classNames string is split, and elem.className is changed for each split entry.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">add<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span> elem<span style="color: #339933;">,</span> classNames <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    jQuery.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>classNames <span style="color: #339933;">||</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/\s+/</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>i<span style="color: #339933;">,</span> className<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> elem.<span style="color: #660066;">nodeType</span> <span style="color: #339933;">==</span> <span style="color: #CC0000;">1</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span>jQuery.<span style="color: #660066;">className</span>.<span style="color: #660066;">has</span><span style="color: #009900;">&#40;</span> elem.<span style="color: #660066;">className</span><span style="color: #339933;">,</span> className <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
            elem.<span style="color: #660066;">className</span> <span style="color: #339933;">+=</span> <span style="color: #009900;">&#40;</span>elem.<span style="color: #660066;">className</span> <span style="color: #339933;">?</span> <span style="color: #3366CC;">&quot; &quot;</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> className<span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
<span style="color: #006600; font-style: italic;">// ...</span></pre></div></div>

<p>This may cause longer than needed delays, as reflow may occur after every class is added individually.  If absolutely necessary, you can always fall back to modifying the className yourself, like so:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#myElement'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
   <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">className</span> <span style="color: #339933;">+=</span> <span style="color: #3366CC;">' myFirstClass mySecondClass'</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Most likely, this isn&#8217;t a tip that will be needed, but it is useful to be aware of.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/06/30/quick-performance-tip-jquery-and-addclass/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Adobe Reverts Flex Store to Open Web</title>
		<link>http://www.zachleat.com/web/2009/05/23/adobe-reverts-flex-store-to-open-web/</link>
		<comments>http://www.zachleat.com/web/2009/05/23/adobe-reverts-flex-store-to-open-web/#comments</comments>
		<pubDate>Sat, 23 May 2009 18:19:08 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Reviews]]></category>
		<category><![CDATA[Adobe]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=220</guid>
		<description><![CDATA[A few weeks ago in the process of doing some research about the Adobe Flex platform, I came across their online store, a dogfooded full page application using Flex.
This morning I went back to the same URL to find a site that was no longer using the full page Flex application I had been expecting. [...]]]></description>
			<content:encoded><![CDATA[<p>A few weeks ago in the process of doing some research about the Adobe Flex platform, I came across their online store, a dogfooded full page application using Flex.</p>
<p>This morning I went back to the <a href="https://store1.adobe.com/cfusion/store/html/index.cfm?store=OLS-US&#">same URL</a> to find a site that was no longer using the full page Flex application I had been expecting.  Instead it was now using native Open Web technology.</p>
<p>Naturally, my first assumption was that I had hallucinated the original research.  But as it turns out, I wasn&#8217;t the only one that noticed the Flex application.  This blogger <a href="http://www.cfinternals.org/blog/2007/06/adobes_flashfle.html">complained about the accessibility</a> of a full page Flash/Flex store.  Another blogger had a <a href="http://www.abdulqabiz.com/blog/archives/adobe/adobe_store_is_still.php">similar complaint</a>.</p>
<p>I have no idea how long the Flash/Flex Adobe store experiment went on before they changed it back.  I&#8217;m just glad I&#8217;m not crazy.</p>
<p><strong>Update</strong>: Turns out they are using a whitelist/blacklist of user agents to decide whether or not to show the Flex store.  The <a href="https://store1.adobe.com/cfusion/store/index.cfm">original entry point</a> above is incorrect, and shouldn&#8217;t have the html subdirectory.  If you go to the site in Chrome, it will redirect you to the HTML version.  My apologies, Adobe, although I do think the HTML version is much more accessible.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/05/23/adobe-reverts-flex-store-to-open-web/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Performance Caveat with jQuery Selectors and Live Events</title>
		<link>http://www.zachleat.com/web/2009/05/08/performance-caveat-with-jquery-selectors-and-live-events/</link>
		<comments>http://www.zachleat.com/web/2009/05/08/performance-caveat-with-jquery-selectors-and-live-events/#comments</comments>
		<pubDate>Fri, 08 May 2009 13:00:04 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Event Delegation]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=211</guid>
		<description><![CDATA[Prerequisite: Knowledge/Experience with jQuery Live Events (new in jQuery 1.3), and the concept of Event Delegation.
When developing on the front end, it&#8217;s easy to prioritize correctness over performance.  Performance is the step child that gets lost while you&#8217;re pulling your hair out worrying about cross browser compatibility.  It&#8217;s very important to regularly benchmark [...]]]></description>
			<content:encoded><![CDATA[<p><em>Prerequisite: Knowledge/Experience with <a href="http://docs.jquery.com/Events/live">jQuery Live Events</a> (new in jQuery 1.3), and the concept of <a href="http://icant.co.uk/sandbox/eventdelegation/">Event Delegation</a>.</em></p>
<p>When developing on the front end, it&#8217;s easy to prioritize correctness over performance.  Performance is the step child that gets lost while you&#8217;re pulling your hair out worrying about cross browser compatibility.  It&#8217;s very important to regularly benchmark your JavaScript code, using a <a href="http://getfirebug.com/js.html">profiler</a> or some form of benchmarking code paired with a cross browser logging utility (see <a href="http://getfirebug.com/lite.html">Firebug Lite</a>, <a href="http://developer.yahoo.com/yui/logger/">YUI Logger</a>, or <a href="http://log4javascript.org/">log4javascript</a>).</p>
<p>Event delegation is a great way to program for performance.  The <code>live</code> jQuery method was a great addition to the jQuery core, it makes event delegation really easy (see also the <code>closest</code> method).  Unfortunately, it isn&#8217;t quite what I expected.</p>
<p>For example, say you have a page containing approximately 500 custom tooltip components on it (not typical, but stick with me, this is to prove a point). How might one go about adding a simple live event to activate each tooltip when the user hovers over it?</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'span.myTooltip'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'mouseover'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// activate tooltip</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>See the problem?  jQuery will actually run the selector on the document, resulting in unnecessary overhead. jQuery is only assigning a single event handler to top level of the document, why does it need to know what nodes it will be binding to before assigning the callback?</p>
<p>What can we do?  Let&#8217;s create a jQuery function, instead of a method, so it won&#8217;t query the document.  Try this on for size:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$.<span style="color: #660066;">live</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>selector<span style="color: #339933;">,</span> type<span style="color: #339933;">,</span> fn<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> r <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    r.<span style="color: #660066;">selector</span> <span style="color: #339933;">=</span> selector<span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>type <span style="color: #339933;">&amp;&amp;</span> fn<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        r.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span>type<span style="color: #339933;">,</span> fn<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000066; font-weight: bold;">return</span> r<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<h2>Usage</h2>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Single event type</span>
$.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'span.myTooltip'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'mouseover'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// activate tooltip</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// Multiple event types (you can call the jQuery live method on the return value from the function)</span>
$.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'span.myTooltip'</span><span style="color: #009900;">&#41;</span>
    .<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'mouseover'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// activate tooltip</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
    .<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'mouseout'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// deactivate tooltip</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Also, as a side note, keep in mind that jQuery <code>live</code> <strong>doesn&#8217;t</strong> support space separated events, like <code>bind</code> does.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Will not work.</span>
$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'span.myTooltip'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'mouseover mouseout'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/05/08/performance-caveat-with-jquery-selectors-and-live-events/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Jonathan Sharp at The Ajax Experience</title>
		<link>http://www.zachleat.com/web/2009/02/20/jonathan-sharp-at-the-ajax-experience/</link>
		<comments>http://www.zachleat.com/web/2009/02/20/jonathan-sharp-at-the-ajax-experience/#comments</comments>
		<pubDate>Sat, 21 Feb 2009 03:35:51 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[People]]></category>
		<category><![CDATA[Ajaxian]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[The Ajax Experience]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=200</guid>
		<description><![CDATA[Former co-worker and all around good guy Jonathan Sharp gave a presentation at The Ajax Experience about a project that he developed, and subsequently passed onto me around 3Q2008.]]></description>
			<content:encoded><![CDATA[<p>Former co-worker and all around good guy <a href="http://jdsharp.us/">Jonathan Sharp</a> gave a presentation at The Ajax Experience about a project that he developed, and subsequently passed onto me around 3Q2008.  A custom built UI component library based on jQuery, used by 450+ developers on 80+ internal and external web applications.  You wouldn&#8217;t think it, but railroads have pretty large IT departments. This presentation was <a href="http://ajaxian.com/archives/jquery-ajax-experience-framework-videos">posted on Ajaxian</a> this week.  Enjoy!</p>
<p><embed src="http://services.brightcove.com/services/viewer/federated_f8/1596744118" bgcolor="#FFFFFF" flashVars="videoId=1828663222&#038;playerId=1596744118&#038;viewerSecureGatewayURL=https://console.brightcove.com/services/amfgateway&#038;servicesURL=http://services.brightcove.com/services&#038;cdnURL=http://admin.brightcove.com&#038;domain=embed&#038;autoStart=false&#038;" base="http://admin.brightcove.com" name="flashObj" width="486" height="412" seamlesstabbing="false" type="application/x-shockwave-flash" swLiveConnect="true" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"></embed></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/02/20/jonathan-sharp-at-the-ajax-experience/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ALARMd Unix Time Format for 1234567890 Day</title>
		<link>http://www.zachleat.com/web/2009/02/13/alarmd-unix-time-format-for-1234567890-day/</link>
		<comments>http://www.zachleat.com/web/2009/02/13/alarmd-unix-time-format-for-1234567890-day/#comments</comments>
		<pubDate>Fri, 13 Feb 2009 19:11:18 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=196</guid>
		<description><![CDATA[In honor of 1234567890 day, I&#8217;ve added the Unix time format to ALARMd.
Hit Options, then the Clock Format tab to change to Unix Time.  Enjoy!
]]></description>
			<content:encoded><![CDATA[<p>In honor of <a href="http://www.1234567890day.com/">1234567890 day</a>, I&#8217;ve added the Unix time format to <a href="http://www.alarmd.com/">ALARMd</a>.</p>
<p>Hit <strong>Options</strong>, then the <strong>Clock Format tab</strong> to change to Unix Time.  Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/02/13/alarmd-unix-time-format-for-1234567890-day/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Registration Forms Suck, Let&#8217;s Mitigate Suckiness</title>
		<link>http://www.zachleat.com/web/2009/01/10/registration-forms-suck-lets-mitigate-suckiness/</link>
		<comments>http://www.zachleat.com/web/2009/01/10/registration-forms-suck-lets-mitigate-suckiness/#comments</comments>
		<pubDate>Sat, 10 Jan 2009 23:59:45 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Application Design]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Forms]]></category>
		<category><![CDATA[OpenID]]></category>
		<category><![CDATA[Registration]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=181</guid>
		<description><![CDATA[A lot of people <strong>complain about registration forms</strong>. Some people have suggested getting rid of them altogether, allowing users to utilize login credentials from accounts they already have through OpenID.  But registration forms aren't going away.  How can we make them more friendly?]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.zachleat.com/web/wp-content/uploads/2009/01/signup-form.png" alt="Signup Form" title="signup-form" width="250" height="293" class="size-full wp-image-183" style="float:right" /> A lot of people <strong>complain about registration forms</strong>. Some people have suggested getting rid of them altogether, allowing users to utilize login credentials from accounts they already have through OpenID.  But even with a highly technical audience, OpenID adoption is <a href="http://blog.stackoverflow.com/2008/10/stack-overflow-openid-case-study/">problematic</a>.</p>
<p>So, some sites have gone two ways, allowing OpenID, but also a proprietary registration system.  This too, <a href="http://www.wetpaintcentral.com/page/OpenID?t=anon">is problematic</a>.  It would seem that given a choice, the <strong>John Doe the Plumber style user will choose a proprietary account</strong> over the confusing user experience presented to them through OpenID.</p>
<p>But the annoyance doesn&#8217;t just lie with account registration for web applications.  Typing your personal information on every blog you comment at is also repetitive and unnecessary.  <a href="http://www.ajaxian.com">Some sites</a> even require account registration for something so minor and transient as a blog comment.</p>
<p>Unfortunately, for the time being, it looks like <strong>registration forms are here to stay</strong>.  So, what can we do to make those registration forms more usable, more efficient, and ultimately downright friendly?  I know that you&#8217;re ahead of me on this one: <strong>Let&#8217;s auto-complete information for the user</strong>.</p>
<p>Please keep in mind that this power can be used for both good and evil.  Essentially what we&#8217;re discussing here is data mining available information from various social networking sites on the internet, trying to glean personal information about an end user that has volunteered a piece of their data already.  What can we get from what we already have?</p>
<p>Once a user has typed in their <strong>e-mail address</strong>, we can:</p>
<ul>
<li>Retrieve Twitter profile information (<a href="http://www.wait-till-i.com/2009/01/08/using-twitter-as-a-data-provider-to-automatically-fill-forms/">example shown on Chris Heilmann&#8217;s blog</a>):
<ul>
<li>Full Name</li>
<li>Short Personal Description</li>
<li>Location</li>
<li>Web site URL</li>
<li>Time Zone</li>
<li>Favorite Colors (used on their profile)</li>
</ul>
</li>
<li>Retrieve an <strong>avatar</strong> if they&#8217;ve registered for the Gravatar web service (<a href="http://www.zachleat.com/web/2009/01/08/scare-your-visitors-with-this-javascript-gravatar-plugin/">See my earlier post discussing this</a>).</li>
<li>Get their <a href="http://gdata-javascript-client.googlecode.com/svn/trunk/samples/calendar/simple_sample/simple_sample.html">upcoming calendar events</a> from a public Google Calendar. (Perhaps not as useful for autocompleting forms, but interesting)</li>
<li>Find their <a href="http://www.flickr.com/services/api/flickr.people.findByEmail.html">UID on Flickr</a>, which gives you <a href="http://www.flickr.com/services/api/flickr.people.getInfo.html">a source</a> for:
<ul>
<li>Full Name</li>
<li>Location</li>
<li>Flickr Avatar</li>
</ul>
</li>
</ul>
<p>If you know any of their social networking usernames, you can:</p>
<ul>
<li><a href="http://developer.yahoo.com/mybloglog/V1/member_find_byservice.html">find their MyBlogLog profile</a>, if they&#8217;ve linked the service to their account (<a href="http://mybloglog.yahooapis.com/v1/user/service/twitter/zachleat?AppId=YahooDemo&#038;format=xml">Sample query, I added my twitter</a>).  Now we have:
<ul>
<li>MyBlogLog Screen Name and ID, from which you get their <a href="http://developer.yahoo.com/mybloglog/V1/member_find_byid.html">MyBlogLog profile</a>:
<ul>
<li>Nickname</li>
<li>Picture</li>
<li>Age</li>
<li>Sex</li>
<li>Location</li>
<li>A list of tags they use to describe themselves.</li>
</ul>
</li>
<li>MyBlogLog Avatar</li>
</ul>
</li>
</ul>
<p>Those are only some of the proof of concept API&#8217;s that I&#8217;ve listed here.  The interesting piece of this, is that once you have a small piece of information, it <strong>opens up the door to other searches</strong>.</p>
<p>One can only imagine how many leaves are in this tree.  For example:</p>
<ul>
<li>Facebook&#8217;s <a href="http://wiki.developers.facebook.com/index.php/Users.getInfo">Users.getInfo</a> (<a href="http://wiki.developers.facebook.com/index.php/JavaScript_Client_Library">in JavaScript</a>)</li>
<li>Yahoo&#8217;s Social Tools, get an <a href="http://developer.yahoo.com/social/rest_api_guide/introspective-guid-resource.html">end user&#8217;s GUID</a> and go to town on <a href="http://developer.yahoo.com/social/rest_api_guide/social_dir_api.html">their profile</a>.
<li>Google Contacts, I didn&#8217;t even start to look through <a href="http://code.google.com/apis/contacts/">their API&#8217;s</a>.</li>
</ul>
<p>Before you start jumping the privacy fence to a self induced heart attack, remember that <strong>all this information has been volunteered</strong> by each individual participating in each of these services.  Remember, with great power comes great responsibility.</p>
<p>What do you think?  Scary or useful?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/01/10/registration-forms-suck-lets-mitigate-suckiness/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Scare Your Visitors with this JavaScript Gravatar Plugin</title>
		<link>http://www.zachleat.com/web/2009/01/08/scare-your-visitors-with-this-javascript-gravatar-plugin/</link>
		<comments>http://www.zachleat.com/web/2009/01/08/scare-your-visitors-with-this-javascript-gravatar-plugin/#comments</comments>
		<pubDate>Fri, 09 Jan 2009 03:47:43 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Gravatar]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=157</guid>
		<description><![CDATA[Here's a use case.  An unregistered visitor visits your blog, and decides that your <strong>content is so good that it merits a comment</strong>!  Congratulations, you've fooled them!  But since they're leaving a comment, why not show them a preview of their gravatar?]]></description>
			<content:encoded><![CDATA[<h2><a href="/javascript/gravatar/index.html">See the Demo</a></h2>
<h2><a href="/javascript/gravatar/jquery.gravatar.js">Download the Source Code</a></h2>
<p><br/><br />
<br/></p>
<p><img src="http://www.zachleat.com/web/wp-content/uploads/2009/01/blog-comment.png" alt="Tournology Blog Comment Form" title="blog-comment" width="484" height="266" class="size-full wp-image-158" /></p>
<p>Here&#8217;s a use case.  An unregistered visitor visits your blog, and decides that your <strong>content is so good that it merits a comment</strong>!  Congratulations, you&#8217;ve fooled them!  Now you can <a href="http://www.centernetworks.com/twply-twitter-replies-auction">twply their account details for $1200 on Sitepoint</a>!  Just kidding.  But generally, when you visit a blog&#8217;s commenting section (such as the <a href="http://www.tournology.com/blog/">Tournology Blog</a> shown above), you&#8217;ll see a simple form to authenticate you&#8217;re not a spammer, generally including (among other things) an e-mail address field.</p>
<p><br/><br />
<br/></p>
<p><img src="http://www.zachleat.com/web/wp-content/uploads/2009/01/blog-comment-after.png" alt="Tournology Blog Comment Form With Gravatar" title="blog-comment-after" width="484" height="266" class="size-full wp-image-160" /></p>
<p>Well, since they&#8217;re typing their e-mail address, wouldn&#8217;t it be cool if we could <strong>show them their gravatar</strong> right there, inline with the blog comment form?  Well, that&#8217;s now possible with my new <strong><a href="http://www.zachleat.com/javascript/gravatar/jquery.gravatar.js">JavaScript Gravatar Plugin</a></strong>!  It doesn&#8217;t have any server side language dependencies.</p>
<p><br/><br />
<br/></p>
<p><img src="http://www.zachleat.com/web/wp-content/uploads/2009/01/gravatar-signup.png" alt="Gravatar Signup Page" title="gravatar-signup" width="483" height="265" class="size-full wp-image-162" /></p>
<p>Hell, <a href="http://en.gravatar.com/">gravatar.com</a> could even use this to <strong>improve the user experience of registering your e-mail account</strong>.  Right now it does a full page refresh and doesn&#8217;t even show you a preview!</p>
<p><br/></p>
<h2><a href="/javascript/gravatar/index.html">See the Demo</a></h2>
<h2><a href="/javascript/gravatar/jquery.gravatar.js">Download the Source Code</a></h2>
<p><br/></p>
<h2>Licensing</h2>
<p>
Licensed under the <a href="http://sam.zoy.org/wtfpl/">WTFPL</a>, as highly recommended by <a href="http://foohack.com/">Isaac Schleuter</a> (<a href="/web/2007/04/05/google-using-yui-grids-css/">see discussion</a>).
</p>
<p><br/></p>
<h2>JavaScript Dependencies:</h2>
<ul>
<li>Requires <a href="http://jquery.com">jQuery</a> (Feel free to port and post a link!)</li>
<li>Requires <a href="http://pajhome.org.uk/crypt/md5/md5.js">md5.js</a></li>
</ul>
<p><br/></p>
<h2>Example Usage:</h2>
<p>Easiest form, onblur of email text input field:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#emailTextField'</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">blur</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">after</span><span style="color: #009900;">&#40;</span>$.<span style="color: #660066;">gravatar</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Showing all options, again onblur of email text input field.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#email'</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">blur</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">append</span><span style="color: #009900;">&#40;</span>$.<span style="color: #660066;">gravatar</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #006600; font-style: italic;">// integer size: between 1 and 512, default 80 (in pixels)</span>
        size<span style="color: #339933;">:</span> <span style="color: #CC0000;">200</span><span style="color: #339933;">,</span>
        <span style="color: #006600; font-style: italic;">// maximum rating (in order of raunchiness, least to most): g (default), pg, r, x</span>
        rating<span style="color: #339933;">:</span> <span style="color: #3366CC;">'pg'</span><span style="color: #339933;">,</span>
        <span style="color: #006600; font-style: italic;">// url to define a default image (can also be one of: identicon, monsterid, wavatar)</span>
        image<span style="color: #339933;">:</span> <span style="color: #3366CC;">'identicon'</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2009/01/08/scare-your-visitors-with-this-javascript-gravatar-plugin/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>DOMContentLoaded Inconsistencies (in Browsers and JavaScript Libraries)</title>
		<link>http://www.zachleat.com/web/2008/12/04/domcontentloaded-inconsistencies/</link>
		<comments>http://www.zachleat.com/web/2008/12/04/domcontentloaded-inconsistencies/#comments</comments>
		<pubDate>Fri, 05 Dec 2008 04:54:24 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web Browsers]]></category>
		<category><![CDATA[linkedin]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=153</guid>
		<description><![CDATA[We all know the problem, but we may not all call it the same thing: DOMContentLoaded.  Every popular JavaScript library has its own name for the DOMContentLoaded event, and they're all implemented differently.  This, of course, partly due to the fact that web browsers are also inconsistent in their implementations.  Here's a run-down of those inconsistencies.]]></description>
			<content:encoded><![CDATA[<p><strong>Quick Summary</strong></p>
<ul>
<li><em>Prototype and Dojo are the only major JavaScript frameworks that correctly time the DOMContentLoaded inside of an iframe in Internet Explorer.  MooTools comes close and both YUI and jQuery both exhibit incorrect behavior.</em></li>
<li><em>Usually, browsers that have a native DOMContentLoaded event will fire it after both JavaScript and CSS (external script, link tags) have loaded.  But Opera fires prior to CSS link tags loading.</em></li>
</ul>
<p>We all know the problem, but we may not all call it the same thing.  Every popular JavaScript library has its own name for the DOMContentLoaded event.</p>
<table>
<thead>
<tr>
<th>JavaScript Library</th>
<th>Event Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>YUI</td>
<td><a href="http://developer.yahoo.com/yui/docs/YAHOO.util.Event.html#method_onDOMReady">DOMReady</a></td>
</tr>
<tr>
<td>jQuery</td>
<td><a href="http://docs.jquery.com/Events/ready">ready</a></td>
</tr>
<tr>
<td>MooTools</td>
<td><a href="http://mootools.net/docs/Utilities/DomReady">domready</a></td>
</tr>
<tr>
<td>Prototype</td>
<td><a href="http://www.prototypejs.org/api/document/observe">dom:loaded</a></td>
</tr>
<tr>
<td>Dojo</td>
<td><a href="http://api.dojotoolkit.org/jsdoc/dojo/1.2/dojo.addOnLoad">addOnLoad</a></td>
</tr>
</tbody>
</table>
<p>But the naming scheme isn&#8217;t the only part about this event that&#8217;s inconsistent.  There are a few hacks strewn around the net that have been bastardized (read: modified to the will of library authors) into each individual framework.  These have been posted time and time again, but for post completeness are the following:</p>
<table>
<thead>
<tr>
<th>IE DOMContentLoaded Hack</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code><a href="http://javascript.nwbox.com/IEContentLoaded/">doScroll</a></code> by Diego Perini</td>
<td>Uses a <code>doScroll</code> method call, which will throw an error if the <code>ondocumentready</code> event hasn&#8217;t fired on the <strong>primary document</strong> (take note of the usage of the word primary).  Once <code>doScroll</code> doesn&#8217;t throw an error, it is assumed the DOM has loaded.</td>
</tr>
<tr>
<td><code><a href="http://msdn.microsoft.com/en-us/library/ms536957(VS.85).aspx">onreadystatechange</a></code> and <code><a href="http://msdn.microsoft.com/en-us/library/ms534359.aspx">readyState</a></code></td>
<td><code>onreadystatechange</code> <em>&#8220;fires when the state of the object has changed,&#8221;</em> and changes the <code>readyState</code> property of the object through the following states (not all apply to every type of element): <code>uninitialized</code>, <code>loading</code>, <code>loaded</code>, <code>interactive</code>, and <code>complete</code>.  (source: MSDN) Usually set on the document object, or a script element (as used in the Script Defer method described next.</td>
</tr>
<tr>
<td><a href="http://dean.edwards.name/weblog/2005/09/busted/">Script Defer</a> by Dean Edwards</td>
<td>document.write&#8217;s a script tag with a <code>defer</code> attribute.  Defer will cause the browser to delay execution of the script until the DOM has successfully loaded (using onreadystatechange on the script tag until its readyState is &#8220;complete&#8221;).  Without defer, the browser would execute any script tag immediately.</td>
</tr>
<tr>
<td><a href="http://dean.edwards.name/weblog/2005/09/busted2/">HTC Behavior</a> by Dean Edwards</td>
<td>Much less popular approach using proprietary HTC Behavior files.  Generally avoided due to the addition of an extra HTTP request to the page in order to download the external .htc file.  As a side note, if using this approach, the <code><a href="http://msdn.microsoft.com/en-us/library/ms531021.aspx">"oncontentready"</a></code> event will work better than the <a href="http://msdn.microsoft.com/en-us/library/ms531024.aspx">&#8220;ondocumentready&#8221;</a> event used by Mr. Edwards.</td>
</tr>
<tr>
<td>Ghetto Method</td>
<td>Of course, the easiest way to do it is to put a script tag right above your ending <code>&lt;/body&gt;</code> tag that triggers the event manually.  This really only works if you have full control of the content, and isn&#8217;t really a library solution.  Worth noting though.</td>
</tr>
</tbody>
</table>
<p><a href='http://zachleat.com/Projects/domcontentloaded/'><img src="http://www.zachleat.com/web/wp-content/uploads/2008/12/domcontentloaded.png" alt="Benchmark for Library DOMContentLoaded Implementations" title="domcontentloaded" width="500" height="224" class="aligncenter size-full wp-image-154" /><br/><br />
<em>Benchmark for Library DOMContentLoaded Implementations</em></a></p>
<p>I created a benchmark trying to answer the simple question: when does the DOMContentLoaded event fire?  Each implementation has different effects, especially in iframes and with stylesheets.</p>
<h1>What Works</h1>
<p>The Internet Explorer hacks presented above are reliable when used on a standalone document (not inside of an iframe).</p>
<p>Mozilla Firefox, Safari, Chrome, and Opera all contain a native DOMContentLoaded event that each framework uses to consistently fire at the correct time.  So, it isn&#8217;t even worth summarizing the results for tests in every browser with a native DOMContentLoaded event, except Opera.  Opera took a different design approach with their DOMContentLoaded event (certainly not wrong, just different), which we&#8217;ll analyze below.</p>
<h1>Internet Explorer inside an Iframe</h1>
<p><em>All libraries below did no branching based on IE versions, all used the same method for IE6, IE7, or IE8.  I performed no tests in IE8, however.</em></p>
<table>
<thead>
<tr>
<th rowspan="2">JavaScript Library</th>
<th rowspan="2">Method</th>
<th colspan="4">Waited for:</th>
</tr>
<tr>
<th>&lt;body&gt; &lt;script&gt;</th>
<th>&lt;head&gt; &lt;script&gt;</th>
<th>&lt;link&gt; CSS</th>
<th>&lt;img&gt;</th>
</tr>
</thead>
<tbody>
<tr>
<td>YUI 2.6.0</td>
<td>doScroll, setTimeout</td>
<td colspan="4">Incorrect: Fires almost immediately (~20ms)</td>
</tr>
<tr>
<td>jQuery 1.2.6</td>
<td>window onload</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td>Prototype 1.6.0.3</td>
<td>Script Defer</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td>MooTools 1.2.1</td>
<td>doScroll and set innerHTML, setTimeout</td>
<td>*</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td>Dojo 1.2.0</td>
<td>Script Defer</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td><a href="http://javascript.nwbox.com/IEContentLoaded/">IEContentLoaded</a></td>
<td>doScroll, document.onreadystatechange</td>
<td colspan="4">Incorrect: JavaScript error.</td>
</tr>
<tr>
<td><a href="http://www.thefutureoftheweb.com/blog/adddomloadevent">addDOMLoadEvent</a></td>
<td>Script Defer</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
</tbody>
</table>
<p>* <em>For some reason, not only did the MooTools library not wait for the body script to trigger DOMContentLoaded, the body script never executed at all.</em></p>
<p>The <strong>most important takeaway</strong> from this blog post are the successful methods of faking DOMContentLoaded in Internet Explorer.  The obvious <strong>library winners here are Prototype and Dojo</strong>, with the addDOMLoadEvent script also exhibiting correct behavior.  MooTools is a close runner up, and I would be interested to find out why it didn&#8217;t execute the body script (that&#8217;s left for another day, or perhaps a generous commenter).</p>
<h1>Opera 9.6</h1>
<table>
<thead>
<tr>
<th rowspan="2">JavaScript Library</th>
<th rowspan="2">Method</th>
<th colspan="4">Waited for:</th>
</tr>
<tr>
<th>&lt;body&gt; &lt;script&gt;</th>
<th>&lt;head&gt; &lt;script&gt;</th>
<th>&lt;link&gt; CSS</th>
<th>&lt;img&gt;</th>
</tr>
</thead>
<tbody>
<tr>
<td>YUI 2.6.0</td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td>jQuery 1.2.6</td>
<td>Native DOMContentLoaded + Code to wait for Stylesheets</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td>Prototype 1.6.0.3</td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td>MooTools 1.2.1</td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Dojo 1.2.0</td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="http://javascript.nwbox.com/IEContentLoaded/">IEContentLoaded</a></td>
<td>N/A to Opera</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td><a href="http://www.thefutureoftheweb.com/blog/adddomloadevent">addDOMLoadEvent</a></td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>As you can see above, <strong>Opera typically will fire DOMContentLoaded prior to stylesheets loading</strong> successfully (ignoring the jQuery specific code to provide consistency cross-browser)</p>
<p><em>Thanks to <a href="http://www.adamkoch.com/">Adam Koch</a> for first pointing me in the direction of jQuery in an iframe ignoring DOMContentLoaded in IE.</em></p>
<p><strong>Update:</strong> There is an open ticket for <a href="http://sourceforge.net/tracker/index.php?func=detail&#038;aid=2008289&#038;group_id=165715&#038;atid=836476">YUI on Sourceforge</a>, and I&#8217;ve opened a ticket for <a href="http://dev.jquery.com/ticket/3693">jQuery on their Trac site</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2008/12/04/domcontentloaded-inconsistencies/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Extra Credit on Graded Browser Support with Zend Framework</title>
		<link>http://www.zachleat.com/web/2008/11/09/extra-credit-on-graded-browser-support-with-zend-framework/</link>
		<comments>http://www.zachleat.com/web/2008/11/09/extra-credit-on-graded-browser-support-with-zend-framework/#comments</comments>
		<pubDate>Sun, 09 Nov 2008 20:46:22 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[GradedBrowserSupport]]></category>
		<category><![CDATA[Tournology]]></category>
		<category><![CDATA[ZendFramework]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=152</guid>
		<description><![CDATA[Over at Tournology, I&#8217;ve written a blog post about enhancing Graded Browser Support to provide a better experience rewarding visitors using cutting edge web browsers.  Check it out if you&#8217;re interested in Zend Framework or Yahoo&#8217;s Graded Browser Support strategy.
]]></description>
			<content:encoded><![CDATA[<p>Over at <a href="http://www.tournology.com/">Tournology</a>, I&#8217;ve written <strong><a href="http://www.tournology.com/blog/2008/11/extra-credit-graded-browser-support/">a blog post about enhancing Graded Browser Support</a></strong> to provide a better experience rewarding visitors using cutting edge web browsers.  Check it out if you&#8217;re interested in Zend Framework or Yahoo&#8217;s Graded Browser Support strategy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2008/11/09/extra-credit-on-graded-browser-support-with-zend-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery Bug: IE reports incorrect $.browser.version</title>
		<link>http://www.zachleat.com/web/2008/10/19/jquery-bug-ie-reports-incorrect-browserversion/</link>
		<comments>http://www.zachleat.com/web/2008/10/19/jquery-bug-ie-reports-incorrect-browserversion/#comments</comments>
		<pubDate>Sun, 19 Oct 2008 06:18:34 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Other]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=150</guid>
		<description><![CDATA[I&#8217;ve witnessed installations of IE where the navigator.userAgent reported both MSIE 6.0 and MSIE 7.0 in the same string, when Internet Explorer 7 is the one that&#8217;s really installed.  Turns out, this is problematic for jQuery version 1.2.6, as it parses the double version userAgent as Internet Explorer 6, which may cause problems with [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve witnessed installations of IE where the navigator.userAgent reported both MSIE 6.0 and MSIE 7.0 in the same string, when Internet Explorer 7 is the one that&#8217;s really installed.  Turns out, this is problematic for jQuery version 1.2.6, as it parses the double version userAgent as Internet Explorer 6, which may cause problems with your code if you&#8217;re using $.browser.version.</p>
<p>You can monitor the <a href="http://dev.jquery.com/ticket/3169">jQuery bug</a> in the bug tracker, or see the original research performed by <a href="http://jamazon.co.uk/web/2008/03/14/jquerybrowserversion-doesnt-recognise-ie7/">Jamie Thompson</a>.  Here&#8217;s a better workaround that merges two different approaches used on Jamie&#8217;s page, which fixes $.browser.version instead of using $.browser.msie6.  This is to be considered temporary until the next (fixed) version of jQuery comes out.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">jQuery.<span style="color: #660066;">browser</span>.<span style="color: #660066;">version</span> <span style="color: #339933;">=</span> jQuery.<span style="color: #660066;">browser</span>.<span style="color: #660066;">msie</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #009966; font-style: italic;">/msie 7\.0/i</span>.<span style="color: #660066;">test</span><span style="color: #009900;">&#40;</span>navigator.<span style="color: #660066;">userAgent</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span>
	<span style="color: #3366CC;">&quot;7.0&quot;</span> <span style="color: #339933;">:</span>
	jQuery.<span style="color: #660066;">browser</span>.<span style="color: #660066;">version</span><span style="color: #339933;">;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2008/10/19/jquery-bug-ie-reports-incorrect-browserversion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dear IE6: Please Cache my Images.</title>
		<link>http://www.zachleat.com/web/2008/10/18/dear-ie6-please-cache-my-images/</link>
		<comments>http://www.zachleat.com/web/2008/10/18/dear-ie6-please-cache-my-images/#comments</comments>
		<pubDate>Sun, 19 Oct 2008 05:47:44 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Other]]></category>
		<category><![CDATA[linkedin]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=149</guid>
		<description><![CDATA[A few months ago, I took on a new role at Union Pacific Railroad as the lead architect for an internal project: a Union Pacific UI Library used in our IT department on all new web-based projects.  Based on jQuery, it is similar to a project like jQuery UI, but it has a few [...]]]></description>
			<content:encoded><![CDATA[<p>A few months ago, I took on a new role at <a href="http://www.unionpacific.jobs/careers/explore/prof/index.shtml">Union Pacific Railroad</a> as the lead architect for an internal project: a Union Pacific UI Library used in our IT department on all new web-based projects.  Based on <a href="http://jquery.com/">jQuery</a>, it is similar to a project like <a href="http://ui.jquery.com/">jQuery UI</a>, but it has a few more components and they&#8217;re branded to our color scheme and programmed to our usability requirements.</p>
<p>The project has allowed me to expand my knowledge of browser quirks, improving my frontend-fu with every closed support ticket.  What does that mean for you?  More blogs posts.  Learn from my mistakes (and from those I&#8217;ve inherited).</p>
<p>This week presented an interesting, albeit decreasingly relevant scenario, where a customer was seeing performance problems when loading a simple web page in Internet Explorer 6.  The only hint to the root cause was a claim that he witnessed &#8220;400 items remaining&#8221; in his status bar.  Naturally, this took awhile, but at least we had somewhere to start: Apache access logs.</p>
<p>Consider the following (jQuery) code to <strong>add three new images</strong> to the page using JavaScript:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html&gt;
    &lt;head&gt;
		&lt;script type=&quot;text/javascript&quot; src=&quot;jquery-1.2.6.min.js&quot;&gt;&lt;/script&gt;
		&lt;style type=&quot;text/css&quot;&gt;
		img.bacon { width: 100px; height: 67px; background-image: url(bacon.png); }
		&lt;/style&gt;
   &lt;/head&gt;
    &lt;body&gt;
        &lt;script type=&quot;text/javascript&quot;&gt;
		jQuery(function() {
			jQuery('body').append('&lt;img src=&quot;spacer.png&quot; class=&quot;bacon&quot;/&gt;');
			jQuery('body').append('&lt;img src=&quot;spacer.png&quot; class=&quot;bacon&quot;/&gt;');
			jQuery('body').append('&lt;img src=&quot;spacer.png&quot; class=&quot;bacon&quot;/&gt;');
		});
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p>Note how each image being added dynamically has a <strong>background-image</strong> as well.</p>
<p>In a <strong>normal</strong> web browser (read: Internet Explorer 7+, Firefox *), this would result in the following Apache <code>access.log</code> (with an empty browser cache) with only <strong>4 HTTP requests</strong> (ignoring favicon.ico, which is irrelevant to this study):</p>
<blockquote><p>
127.0.0.1 &#8211; - [18/Oct/2008:22:59:09 -0500] &#8220;GET /ie6cache/ HTTP/1.1&#8243; 200 657<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:59:09 -0500] &#8220;GET /ie6cache/jquery-1.2.6.min.js HTTP/1.1&#8243; 200 55774<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:59:09 -0500] &#8220;GET /ie6cache/spacer.png HTTP/1.1&#8243; 200 207<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:59:09 -0500] &#8220;GET /ie6cache/bacon.png HTTP/1.1&#8243; 200 5416
</p></blockquote>
<p>In Internet Explorer 6, however, this is the resulting Apache <code>access.log</code> (empty browser cache) with <strong>8 HTTP requests</strong>:</p>
<blockquote><p>
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/ HTTP/1.1&#8243; 200 657<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/jquery-1.2.6.min.js HTTP/1.1&#8243; 200 55774<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/spacer.png HTTP/1.1&#8243; 200 207<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/spacer.png HTTP/1.1&#8243; 200 207<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/bacon.png HTTP/1.1&#8243; 200 5416<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/bacon.png HTTP/1.1&#8243; 200 5416<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/spacer.png HTTP/1.1&#8243; 200 207<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/bacon.png HTTP/1.1&#8243; 200 5416
</p></blockquote>
<p>When a web browser parses your markup and sees three image tags with identical src attributes, it makes only one HTTP request to the server for that image, and the rest of the images are loaded from the local web browser cache (no more HTTP requests are made).  This is standard behavior for all modern web browsers.  But in IE6, as you can see from the above log, made 3 requests to the server for both <code>spacer.png</code> and <code>bacon.png</code>.  Why?</p>
<p>Turns out there are two independent issues at play here:</p>
<ol>
<li>The classic <em><a href="http://www.mister-pixel.com/#Content__state=is_that_simple">IE6 background-image flicker</a></em> problem.  This has been documented extensively, and the problem is that IE6 bypasses its local web browser cache for any image requests made for CSS background-images inserted on the page dynamically.  The good news for this one is that the fix is a simple one.

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>jQuery.<span style="color: #660066;">browser</span>.<span style="color: #660066;">msie</span> <span style="color: #339933;">&amp;&amp;</span> parseInt<span style="color: #009900;">&#40;</span>jQuery.<span style="color: #660066;">browser</span>.<span style="color: #660066;">version</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #CC0000;">6</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
    document.<span style="color: #660066;">execCommand</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;BackgroundImageCache&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">catch</span><span style="color: #009900;">&#40;</span>err<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Note the simple check for IE 6 execution only.  This is optional, but keep in mind that this problem is not present in IE7+.  During your testing, also keep in mind that Mister Pixel reports (and I can confirm) that once you run this command, this setting <strong>will persist in your browser</strong>, even if you empty your cache and remove the code from your scripts.  You&#8217;ll need to close your browser window to reset the setting to default.</p>
<p><em>See also <a href="http://dean.edwards.name/my/flicker.html">Dean Edwards&#8217;</a> and <a href="http://www.hedgerwow.com/360/bugs/dom-fix-ie6-background-image-flicker.html">Hedger Wang&#8217;s</a> studies on this issue for more information.</em>  But this is really only half the problem.  This will fix the duplicate bacon.png HTTP requests, but we&#8217;ll still see 3 spacer.png HTTP requests in our logs.
</li>
<li>The other issue is a separate but equal problem with IE6 caching.  When inserting images with identical <code>src</code> attributes, IE6 will always go to the server (which means an extra HTTP request) for a new image.  This is a <a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;319546">documented <em>feature</em> in IE6</a>, and the fix they have listed on their page isn&#8217;t ideal.  The best solution here is to <strong>eliminate the need for <code>spacer.png</code></strong> altogether.  I can put these bacon background&#8217;s on a div tag just as easily, emphasizing pragmatism over semantics in this case (it&#8217;s a small sacrifice, you&#8217;ll live).  If you have an <code>&lt;img&gt;</code> tag with a source you actually need, why not move it to the background image on a div tag?  Unfortunately here, the takeaway is that <strong>your logic may need to be restructured</strong> to workaround this issue.
<p>See also <a href="http://www.bazon.net/mishoo/articles.epl?art_id=958">Mihai Bazon&#8217;s study</a> for more information, but do keep in mind that grouping this issue with the background flicker problem is an incorrect categorization.  They are two separate issues and the fixes represented on that page don&#8217;t really fix the issue at all.  Implementing server side caching as a &#8220;fix&#8221; is like using a bandaid for a tourniquet. You don&#8217;t want an HTTP request to go to the server <strong>at all</strong>, I don&#8217;t care if the response is a 200 OK or a 304 Not Modified.  No HTTP request is always going to be faster than a server side cached response.
</li>
</ol>
<p>These issues will present themselves more frequently if you have the &#8220;Every visit to the page&#8221; caching option enabled in your Internet Tools in Internet Explorer.  Good luck.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2008/10/18/dear-ie6-please-cache-my-images/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Relative URLs including the Domain</title>
		<link>http://www.zachleat.com/web/2008/10/16/relative-urls-including-the-domain/</link>
		<comments>http://www.zachleat.com/web/2008/10/16/relative-urls-including-the-domain/#comments</comments>
		<pubDate>Thu, 16 Oct 2008 06:45:24 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Web Browsers]]></category>
		<category><![CDATA[linkedin]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=148</guid>
		<description><![CDATA[Just a neat little trick I saw while browsing the source code of Google Calendar.  In some of their CSS files, they link to background-images using URLs that include everything but the protocol, which is something I hadn't seen before.]]></description>
			<content:encoded><![CDATA[<p>Just a neat little trick I saw while browsing the source code of Google Calendar.  In some of their CSS files, they link to background-images using URLs that include everything but the protocol, which is something I hadn&#8217;t seen before.</p>
<p>The most common usage of a relative URL is linked from the root (note the slash at the beginning), like so:</p>
<p><img src="/web/wp-content/themes/hemingway/images/title.png"/><br />
&lt;img src=&#8221;<strong>/web/wp-content/themes/hemingway/images/title.png</strong>&#8220;/&gt;</p>
<p>You can also use <code>../</code> to navigate up a directory in your path, but that&#8217;s boring.  The interesting question is: what if I wanted to load content from a separate domain, while at the same time transparently using the protocol used on my page?</p>
<p>Do what Google Calendar does and use the following style:<br />
<img src="//calendar.google.com/googlecalendar/images/calendar_sm2_en.gif"/><br />
&lt;img src=&#8221;<strong>//calendar.google.com/googlecalendar/images/calendar_sm2_en.gif</strong>&#8220;/&gt;</p>
<p>Note the lack of <code>http:</code> or <code>https:</code> from the URL.  If this page <a href="https://www.zachleat.com/web/2008/10/16/relative-urls-including-the-domain/">were hosted on https</a> (we don&#8217;t pay for certificates around here, so you&#8217;ll have to put up with the security warning), the last image source will load from https as well at no additional development cost.</p>
<p>This seems like it would be especially useful if you were using the YDN Performance tip to <a href="http://developer.yahoo.com/performance/rules.html#split">Split Components Across Domains</a>.  Remember, we&#8217;re not just talking images. This involves how the browser resolves URLs, so could be used inside href tags, css urls (as Google Calendar did), etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/2008/10/16/relative-urls-including-the-domain/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
