<?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>Code Nomad</title>
	<atom:link href="http://jasonkarns.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://jasonkarns.com/blog</link>
	<description>Tales of a Transient Programmer</description>
	<lastBuildDate>Sat, 19 Jun 2010 15:37:02 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>IE6, MooTools, and MultiBox: A Tale of Woe</title>
		<link>http://jasonkarns.com/blog/2010/06/04/ie6-mootools-and-multibox-a-tale-of-woe/</link>
		<comments>http://jasonkarns.com/blog/2010/06/04/ie6-mootools-and-multibox-a-tale-of-woe/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 16:00:39 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[mootools]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[ie6]]></category>
		<category><![CDATA[multibox]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=125</guid>
		<description><![CDATA[On a recent project, I traveled to the depths of hell and came out alive. Here’s how it went down…
The initial task wasn’t all that unique or difficult. We were to add a few videos (most hosted on YouTube, with a couple self-hosted) that would open in a lightbox-style popup when the thumbnails were clicked. [...]]]></description>
			<content:encoded><![CDATA[<p>On a recent project, I traveled to the depths of hell and came out alive. Here’s how it went down…</p>
<p>The initial task wasn’t all that unique or difficult. We were to add a few videos (most hosted on YouTube, with a couple self-hosted) that would open in a lightbox-style popup when the thumbnails were clicked. MooTools was already being used on the project, so we selected MultiBox by <a href="http://www.phatfusion.net">phatfusion</a> as the popup of choice. I won’t go into the reason(s) for selecting MultiBox. The more I work with it, the less I like it; but that’s for another post. So, we have MooTools as the JavaScript framework and MultiBox as the plugin.</p>
<h2>Base Functionality</h2>
<p>Keeping progressive enhancement techniques in mind, we set the destination URL of the thumbnails to be the video page on YouTube. This gives crawlers the ability to find the true video destination, as well as user’s without JavaScript the ability to find the video. Now, I realize that YouTube doesn’t even work without JavaScript, but that’s their problem. (On a sidenote, it’s really sad that they use JavaScript to inject the Flash video player, when the <a href="http://code.google.com/p/swfobject/wiki/documentation">SWFObject static publishing method</a> would work just fine).</p>
<p>So the first problem we run into is that, by default, the MultiBox media type of <var>youtube</var> expects the link URL to point directly to the video and not to the video page on YouTube (one reason to ditch MultiBox). Note the difference in URLs below. The video identifier is the same in both (<var>eCzEkiIucUk</var>) but rather than passing it as a parameter to the ‘watch’ page, we can pass it as the slug to /v.</p>
<p>Video page on YouTube: <a href="http://www.youtube.com/watch?v=eCzEkiIucUk">http://www.youtube.com/watch?v=eCzEkiIucUk</a><br />
Actual video on YouTube: <a href="http://www.youtube.com/v/eCzEkiIucUk">http://www.youtube.com/v/eCzEkiIucUk</a></p>
<p>To deal with this, I wrote a quick script that executes <code>ondomready</code>. It parses the <var>v</var> parameter value out of the querystring and rewrites the URL to point directly to the video. This way, when MultiBox opens and inspects the URL to load, the video itself is opened in the MultiBox popup rather than the entire YouTube page.</p>
<h2>Roadblock #1 : MultiBox ‘types’</h2>
<p>At this point, everything is working as expected until the client requests that we provide a customized fallback message for users without Flash. This is a perfectly reasonable request. Ideally the fallback content would be a transcript of the video and perhaps some still images from the video. Maybe even a link to the raw H.264 video. Of course, in this case we are requested to simply provide a ‘Please install Flash’ message. Unfortunately, MultiBox doesn’t have a way to provide custom fallback content for its <var>youtube</var> type. (Yet another reason to ditch MultiBox.)</p>
<p>Rather than using the <var>youtube</var> type and its out-of-the-box functionality, we’ll switch over to the <var>element</var> type. This type allows you to target an element in the dom and the targeted element (and children) is cloned into the MultiBox popup. For this to work, we’ll provide our own <code>object</code> element, complete with cross-browser nesting of objects (<a href="http://code.google.com/p/swfobject/wiki/documentation">see SWFObject static publishing</a>) and our own custom no-flash fallback content. Each video thumbnail will now have the actual video markup next to it in the source, hidden via CSS. The thumbnail is marked up to link to the video page on youtube (for JS-off users). On page load, the links are rewritten to point to the fragment identifier of the video object in the page (e.g. <code>href="#video1"</code>). This way, when MultiBox is activated using the ‘<var>element</var>’ type, it will grab the <code>object</code> element with <code>id="video1"</code> and clone its contents into the popup.</p>
<h2>Roadblock #2: MooTools ‘clone()’</h2>
<p>With the exception of IE6, everything works as expected across browsers both with and without JavaScript. However, it fails in IE6 (of course). Upon inspection of the cloned <code>object</code> elements after they are inserted into the popups, we notice that they no longer contain the <code>param</code> children they’re supposed to. The original <code>object</code> elements still contain their <code>param</code> children, but the clones do not. Internally, MultiBox uses the MooTools <code>clone()</code> method on the base Element class so I put together a quick test page to verify that MooTools’ <code>clone()</code> method works properly in IE6 on <code>object</code> elements. It failed the test, and I <a href="https://mootools.lighthouseapp.com/projects/2706-mootools/tickets/855">filed a bug</a> against MooTools.</p>
<p>The workaround for the MooTools <code>clone()</code> bug is to use the old-school <code>innerHTML</code> property ourselves rather than allowing MooTools to do proper DOM manipulation in the background. So I open up MultiBox and find the routine whereby it uses <code>clone()</code> and add a quick hack. I check if the browser is IE6 and if so, use <code>innerHTML</code> to copy the <code>object</code> element (and all its children) into the popup.</p>
<h2>Roadblock #3: IE6 ‘flashvars’</h2>
<p>So now we have the object being correctly cloned into the popup when a user clicks the video thumbnail. An then I get another ticket. All the YouTube videos are playing, but the self-hosted video is not. Why is the video not playing? This particular video is played using a SWF player which takes the FLV filename to play via the <code>flashvars</code> param. I notice that the FLV file isn’t being requested in IE6. But we just fixed the <code>param</code> bug and the children are all there! Or are they really? After some more debugging and googling, I find that IE6 resets the value of the <code>flashvars</code> param when its <code>innerHTML</code> is modified.</p>
<p>You’re not suprised, are you?</p>
<p>After some more searching, I find <a href="http://siderite.blogspot.com/2007/10/flashvars-empty-after-internet-explorer.html">a great blog post</a> that describes the solution. Rather than passing the different variables to the flash player using the <code>flashvars</code> param, we’ll just add them to the SWF quersystring. So this:</p>
<p><code> </code></p>
<pre>&lt;object … &gt;
  &lt;param name="movie" value="player.swf" /&gt;
  &lt;param name="flashvars" value="path=video1.flv" /&gt;
  …
&lt;/object&gt;</pre>
<p>becomes this:</p>
<pre>&lt;object … &gt;
  &lt;param name="movie" value="player.swf?path=video1.flv" /&gt;
  …
&lt;/object&gt;</pre>
<p>Since we’re using SWFObject’s static publishing method, there are 2 <code>object</code> elements. One intended for IE, and another one, intended for everyone else. The proper <code>object</code> (for Firefox, Chrome, et. al.) is nested within the IE <code>object</code> and hidden via Conditional Comments. Since this whole <code>flashvars</code> mess is only a problem for IE6, we only need to modify the outer <code>object</code> element.</p>
<h2>Roadblock #4: MultiBox’s flvplayer</h2>
<p>Just when you thought we were out of the woods, we have one last issue. Now that we have the video objects with proper fallbacks, and the elements being cloned properly, and the config file information passed correctly, we <em>still</em> don’t have a functioning video in IE. Since we modified the outer IE object element, thanks to the previous issue, we’ve broken the video in all versions of IE. What’s the problem this time? It turns out that the flvplayer.swf that comes packaged with the phatfusion MultiBox doesn’t stream the video properly when the FLV filename is passed via querystring. Solution? Ditch phatfusion’s flvplayer and use another! (I recommend <a href="http://www.longtailvideo.com/players/">any of the JW players</a> if your situation fits the non-commercial bill)</p>
<h2>When the bugs align…</h2>
<p>So at the end of this ordeal, I had three more reasons to avoid phatfusion’s MultiBox widget, I had filed yet another bug against MooTools, and I had conquered yet another bug in IE6. And it all piled up because of a tiny bug in a particular flvplayer; that was caused by the solution to a specific bug in IE6; which was only a problem because of a bug in a particular version of MooTools; which was only a problem because of a poorly designed API in MultiBox; which was encountered because the client wanted to display a download button for Flash; mostly for users who aren’t even able to install Flash if they wanted to. Don’t you just love web development?</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2010/06/04/ie6-mootools-and-multibox-a-tale-of-woe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cross Browser Inline-Block</title>
		<link>http://jasonkarns.com/blog/2010/05/23/cross-browser-inline-block/</link>
		<comments>http://jasonkarns.com/blog/2010/05/23/cross-browser-inline-block/#comments</comments>
		<pubDate>Mon, 24 May 2010 03:53:18 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[css]]></category>
		<category><![CDATA[inline-block]]></category>
		<category><![CDATA[layout]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=111</guid>
		<description><![CDATA[How many times have you used float:left to make a bunch of elements align horizontally? Usually this technique is used on lists (of both the ul and ol persuasion) and generally works just fine under a few preconditions. The first precondition is that you are comfortable using some form of a clearfix hack. Either you [...]]]></description>
			<content:encoded><![CDATA[<p>How many times have you used float:left to make a bunch of elements align horizontally? Usually this technique is used on lists (of both the <code>ul</code> and <code>ol</code> persuasion) and generally works just fine under a few preconditions. The first precondition is that you are comfortable using some form of a clearfix hack. Either you apply <code>overflow:hidden</code> to the container, or you add a meaningless empty div with <code>clear:both</code>, or you apply some magic with the <code>:after</code> pseudo-class. While this isn’t a deal breaker, it is annoying.</p>
<p>The second precondition is that all floated elements are of the same (fixed) height. Of course, your original mockups with dummy data and <em>lorem ipsum</em> text all use the same element just repeated across the page, right? And then the client provides actual content (hopefully), and you find that some items have a really long title, or a super-tall product image. And what happens? The floats &#8217;snag&#8217; items and you end up with this:</p>
<p align="center"><a href="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/float.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="float" border="0" alt="float" src="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/float_thumb.png" width="465" height="335" /></a> <a href="http://jsfiddle.net/4pvyg/7/">see fiddle</a></p>
<p>If the previous screenshot is what you going for, or both previous preconditions hold in your case, you may stop reading right now. Otherwise, read on and you’ll learn how to create this instead:</p>
<p align="center"><a href="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/final.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="final" border="0" alt="final" src="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/final_thumb.png" width="465" height="273" /></a> <a href="http://jsfiddle.net/4pvyg/16/">see fiddle</a></p>
<p>First, I must give credit where credit is due. The technique I’m about to describe (and improve upon) was <a href="http://blog.mozilla.com/webdev/2009/02/20/cross-browser-inline-block/">covered by Ryan Doherty</a> over at the Mozilla Webdev blog. I suggest you read his post first because I’m going to breeze through his foundation and jump into my improvements.</p>
<h3>Foundation</h3>
<p>Here is the HTML will be working with:</p>
<pre class="html">&lt;ul&gt;
    &lt;li&gt;
        &lt;h3&gt;Product 1&lt;/h3&gt;
        &lt;p&gt;Some product description.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;h3&gt;Product 2&lt;/h3&gt;
        &lt;p&gt;Some product description.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;h3&gt;Product 3&lt;/h3&gt;
        &lt;p&gt;Some really, super, long product description.&lt;/p&gt;
    &lt;/li&gt;
    ...
&lt;/ul&gt;</pre>
<p>And some aesthetic styles not relevant to the inline-block layout:</p>
<pre class="css">ul {
    list-style:none;
    width:440px;
}
li {
    border:1px solid #888;
    -moz-border-radius:3px;
    width:75px;
    text-align:center;
    margin:5px;
}
h3 {
    font-size:14px;
    font-weight:bold;
    margin:.25em;
}
p {
    margin:.25em;
}</pre>
<h3>Compliant Browsers</h3>
<p>The first step is to try an use the proper CSS property: <code>display:inline-block</code>. This property gives an inline element, block-like properties. Such as the ability to have <code>width</code> and <code>margin</code>. With just this property, <a href="http://www.quirksmode.org/css/display.html">we have support</a> in Firefox 3+, Safari 3+, Chrome 1+, Opera 9+, and IE8+. Not too shabby.</p>
<pre class="css">li {
    display:inline-block;
}</pre>
<p><a href="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/valign.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="valign" border="0" alt="valign" src="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/valign_thumb.png" width="481" height="273" /></a> </p>
<h3>Fixing the Rest: Firefox 2</h3>
<p>Aside from IE 6 and 7, only Firefox 2 fails to support inline-block. To get support in Firefox 2, simply add the mozilla-specific property <code>display:-moz-inline-stack</code> prior to the <code>display:inline-block</code> declaration. Non-Gecko browsers will ignore the -moz rule. Firefox 3+ supports inline-block so it will override the -moz-inline-stack rule. Using the -moz-inline-stack rule for Firefox 2 also necessitates a <code>div</code> be wrapped around the inline-block element’s contents. Given Firefox 2’s latest market share numbers (most give it under 1% overall), I would generally concede that messing with -moz-inline-stack and an inner-wrapping <code>div</code> is unnecessary. For this reason, I have removed the -moz-inline-stack rule from my Inline-Block gist on GitHub, however, you can <a href="http://jsfiddle.net/4pvyg/15/">see it in action</a> at jsfiddle. Feel free to add it back in yourself if Firefox 2 support is necessary.</p>
<h3>Fixing the Rest: IE 6/7</h3>
<p>IE 6 and 7 both support inline-block natively but with a caveat; they only support it on elements that are inherently inline. Thus, block elements like <code>div</code> and list-item elements like <code>li</code> won’t apply inline-block. However, IE 6/7 has the concept of ‘layout’. (see <a href="http://www.satzansatz.de/cssd/onhavinglayout.html">On Having Layout</a>). IE treats elements with layout triggered exactly the way inline-block elements are supposed to work; that is, block-level elements that are displayed inline. So for IE6/7 we reset the display to inline, and trigger hasLayout with <code>zoom:1</code>.</p>
<p>* Note: You can apply the IE 6/7 rules in any manner you wish. Conditional Comments paired with IE-only stylesheets is generally the preferred method. However, I have gone with the *hack in this case to make these utility classes copy/paste-able.</p>
<pre class="css">li {
    display:inline-block;
    *zoom:1;
    *display:inline;
}</pre>
<p>The final touch is to set <code>vertical-align:top</code> to make the boxes line up across the top:</p>
<pre class="css">li {
    display:inline-block;
    *zoom:1;
    *display:inline;
    vertical-align:top;
}</pre>
<p><a href="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/final_3.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="final" border="0" alt="final" src="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/final_thumb_3.png" width="465" height="273" /></a> </p>
<h3>Room for Improvement</h3>
<p>So now we have our elements aligned horizontally without using floats. We have one last problem which is where I will improve on Ryan’s method. In the screenshot below I have changed the <code>li</code> margin to <code>margin:5px 0;</code> We would expect the left and right borders of each box to touch, no?</p>
<p><a href="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/whitespace.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="whitespace" border="0" alt="whitespace" src="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/whitespace_thumb.png" width="441" height="273" /></a> </p>
<p>The problem is due to the fact that whitespace surrounding inline elements is displayed. Of course, this makes perfect sense. Imagine if the whitespace between words in a sentence weren’t displayed! The trick is to take advantage of <code>letter-spacing</code> and <code>word-spacing</code> to counter the whitespace between our inline-block elements. (This is unnecessary in IE6/7 which already ignores the whitespace between boxes because the elements have <code>hasLayout</code> triggered and are not technically inline-block.)</p>
<h3>Six of One…</h3>
<p>My first attempt was to apply a negative word-spacing to the container. Word-spacing is inherited, so we must reset it to normal on our inline-block elements themselves so as to not affect their children. With word-spacing set to -1em, we have eliminated the offending whitespace in Firefox and Opera.</p>
<p align="center"><a href="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/nowhitespace.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="nowhitespace" border="0" alt="nowhitespace" src="http://jasonkarns.com/blog/images/CrossBrowserInlineBlock_8DCF/nowhitespace_thumb.png" width="425" height="273" /></a> <a href="http://jsfiddle.net/4pvyg/12/">see fiddle</a></p>
<h3>…Half a Dozen of the Other</h3>
<p>In order to fix WebKit (Safari, Chrome) we must also apply negative letter-spacing. Interestingly, applying <em>only</em> letter-spacing actually fixes both WebKet and Firefox which means that either letter-spacing or word-spacing will work for Firefox. However, in order to appease Opera, we will apply both. <a href="http://jsfiddle.net/4pvyg/13/">see fiddle</a></p>
<h3>All Together Now</h3>
<p>I have pared down the necessary rules to a set of utility classes named ib-container and ib-block, as seen below. You can also find them <a href="http://gist.github.com/247649">in a gist</a> on GitHub and <a href="http://jsfiddle.net/4pvyg/16/">as a fiddle</a> on jsFiddle.</p>
<pre class="css">.ib-block {
    vertical-align:top;
    display:inline-block;
    *zoom:1; /* IE6/7 */
    *display:inline; /* IE6/7 */
}
.ib-container {
    letter-spacing:-.25em;
    word-spacing:-1em;
}
.ib-container .ib-block {
    letter-spacing:normal;
    word-spacing:normal;
}</pre>
<h3>Other Variations</h3>
<p>They can be used on list items as seen in this example or any other set of sibling elements:</p>
<pre class="html">&lt;div class=&quot;ib-container&quot;&gt;
    &lt;div class=&quot;ib-block&quot;&gt;…&lt;/div&gt;
    &lt;div class=&quot;ib-block&quot;&gt;…&lt;/div&gt;
    &lt;div class=&quot;ib-block&quot;&gt;…&lt;/div&gt;
&lt;/div&gt;</pre>
<p>They can be used without the ib-container class if the whitespace between ib-block elements is not an issue for you: </p>
<pre class="html">&lt;ul&gt;
    &lt;li class=&quot;ib-block&quot;&gt;…&lt;/li&gt;
    &lt;li class=&quot;ib-block&quot;&gt;…&lt;/li&gt;
    &lt;li class=&quot;ib-block&quot;&gt;…&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>They can be nested so an ib-block element becomes an ib-container for other ib-block elements: </p>
<pre class="html">&lt;ul class=&quot;ib-container&quot;&gt;
    &lt;li class=&quot;ib-block ib-container&quot;&gt;
        &lt;div class=&quot;ib-block&quot;&gt;…&lt;/div&gt;
        &lt;div class=&quot;ib-block&quot;&gt;…&lt;/div&gt;
    &lt;/li&gt;
    &lt;li class=&quot;ib-block ib-container&quot;&gt;
        &lt;div class=&quot;ib-block&quot;&gt;…&lt;/div&gt;
        &lt;div class=&quot;ib-block&quot;&gt;…&lt;/div&gt;
    &lt;/li&gt;
    &lt;li class=&quot;ib-block&quot;&gt;…&lt;/li&gt;
&lt;/ul&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2010/05/23/cross-browser-inline-block/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Google Analytics Tagging with HTML5 data-* Attributes</title>
		<link>http://jasonkarns.com/blog/2010/03/10/google-analytics-tagging/</link>
		<comments>http://jasonkarns.com/blog/2010/03/10/google-analytics-tagging/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 05:55:45 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[mootools]]></category>
		<category><![CDATA[google-analytics]]></category>
		<category><![CDATA[html5]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=99</guid>
		<description><![CDATA[Imagine if you will, a page with a significant amount of dynamic page elements. For instance, a slide-out panel containing a number of ‘panes’ containing topical information on various ‘factors’. Let’s assume that once this slide-out is open, we wish the user to be able to jump from factor to factor (similar to a slideshow) [...]]]></description>
			<content:encoded><![CDATA[<p>Imagine if you will, a page with a significant amount of dynamic page elements. For instance, a slide-out panel containing a number of ‘panes’ containing topical information on various ‘factors’. Let’s assume that once this slide-out is open, we wish the user to be able to jump from factor to factor (similar to a slideshow) using buttons along the bottom of each factor. Let’s go even deeper and say that within each factor, we have a collection of close-up images. Again, the user should be able to navigate the close-ups via next/previous buttons similar to a slideshow. In addition to the next/previous buttons, along the top edge of the ‘close-ups’ section are progress indicator dots that highlight according to which close-up is active (and link directly to individual close-ups).&#160; Given that this functionality should work without JavaScript, all of these UI controls are marked up as links. And we have quite a few of them—to wit, <var>x*(x-1)</var> factor links (for <var>x</var> factors) plus <var>x*y</var> (direct links to close ups per factor) plus <var>x*(2y)</var> (next/prev links for each <var>y</var> close-up for each factor). So, let’s say we have 3 factors and 3 close-ups per factor. We now have 33 links! And now the task is to tag each of these links with unique labels that will be sent back to Google Analytics upon each click event. I’ve broken down a brief subset of the analytics tags for each of the three types of links below.</p>
<h3>Tag Templates</h3>
<p>Tagging template for the factor navigation along the bottom of each [x] factor:</p>
<pre>/page_name/factor_[x]/factor_1_icon
/page_name/factor_[x]/factor_2_icon
/page_name/factor_[x]/factor_3_icon</pre>
<p>Tagging template for the prev/next buttons on each [y] close-up on each [x] factor:</p>
<pre>/page_name/factor_[x]/closeup_[y]/next_arrow
/page_name/factor_[x]/closeup_[y]/prev_arrow</pre>
<p>Tagging template for the close-up direct links (also used as progress indicator) on each each [x] factor:</p>
<pre>/page_name/factor_[x]/closeup_dot_1
/page_name/factor_[x]/closeup_dot_2
/page_name/factor_[x]/closeup_dot_3</pre>
<h3>Approach</h3>
<p>As with anything, I try to keep my code DRY. Considering that these tags will likely end up as magic strings in some form or another, I’d like to reduce the maintenance overhead of these tags as new factors or close-ups are added or removed. The tags themselves convey the hierarchy of the structure in which they are contained. So let’s map the tagging hierarchy onto the structural hierarchy. This tagging information could be embedded in the <code>id</code> or <code>class</code> attributes of an element, though I think that would be coupling two separate needs (JS behavior/CSS styling + Analytics) onto the same data. This information could also conceivably go into the <code>title</code> attribute, though this attribute is meant for human (read: end-user) consumption. Nothing seems to fit, so let’s try out an <a href="http://dev.w3.org/html5/spec/dom.html#embedding-custom-non-visible-data">HTML5 data-* attribute</a>: <code>data-ga</code>.</p>
<p>First, the /page_name segment should map to the page:</p>
<pre class="html">&lt;body data-ga=&quot;/page_name&quot;&gt;</pre>
<p>Each ‘factor_[x]’ segment should map to its own factor pane:</p>
<pre class="html">&lt;ul class=&quot;factors&quot;&gt;
  &lt;li data-ga=&quot;/factor_1&quot; /&gt;
  &lt;li data-ga=&quot;/factor_2&quot; /&gt;
  &lt;li data-ga=&quot;/factor_3&quot; /&gt;
&lt;/ul&gt;</pre>
<p>Each ‘closeup_[y]’ segment should mapt to its own close-up pane:</p>
<pre class="html">&lt;ul class=&quot;closeups&quot;&gt;
  &lt;li data-ga=&quot;/closeup_1&quot; /&gt;
  &lt;li data-ga=&quot;/closeup_2&quot; /&gt;
  &lt;li data-ga=&quot;/closeup_3&quot; /&gt;
&lt;/ul&gt;</pre>
<p>And each link or button gets its own respective value. Keep in mind, multiple <code>data-ga</code> values will be ‘scoped’ by their ancestors’ <code>data-ga</code> values:</p>
<pre class="html">&lt;a href=&quot;#factor-1&quot; data-ga=&quot;/factor_1_icon&quot; /&gt;
&lt;a href=&quot;#factor-1-closeup-1&quot; data-ga=&quot;/closeup_dot_1&quot; /&gt;
&lt;a href=&quot;#factor-1-closeup-2&quot; data-ga=&quot;/next_arrow&quot; /&gt;
&lt;a href=&quot;#factor-1-closeup-3&quot; data-ga=&quot;/prev_arrow&quot; /&gt;</pre>
<p>Now, whenever a link is clicked, we simply concatenate the data-ga values from each ancestor! The method below should have the context of <code>this</code> as an anchor element with a <code>data-ga</code> attribute. Generally, it would be in the click handler of any element matching the selector: <code>&quot;a[data-ga]&quot;</code>. Once <code>ga</code> is concatenated, it can be used as the tag for a Google Analytics API call (<code>_trackPageview</code> or <code>_trackEvent</code>).</p>
<pre class="javascript">$(&quot;a[data-ga]&quot;).click(function(event){
  var ga = $(this).parents('[data-ga]').andSelf()
           .map(function(){return $(this).attr('data-ga');});
  ga = $.makeArray(ga).join('');
  _pageTracker._trackPageview(ga);
});</pre>
<h3>Demo</h3>
<p><iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/eY4cq/1/embedded/"></iframe></p>
<h3>A few additional notes</h3>
<h4>Performance</h4>
<p>It would be much better to calculate the ga-tag for every link on the page during page load and cache the result in the data store of the element. As written, the ancestor traversal is executed on every click, and would result in the same return value each time. However, as a special case when I was first implementing this, there were some widgets that altered the hierarchy of the page, thus it was necessary to only perform the concatenation at event-time rather than load-time.</p>
<p>As an additional performance boost, I added a class of <code>ga-scope</code> to each ancestor element that contained a <code>data-ga</code> attribute. This allowed me to use a class selector in the <code>.parents()</code> filter. This will only yield a performance boost in browsers that support a native implementation for querying by class name, thus allowing the selector engine (MooTools or jQuery) to avoid stopping to inspect every single ancestor on its way up the tree.</p>
<h4>MooTools</h4>
<p>I originally implemented this with MooTools. During the implementation I discovered a <a href="https://mootools.lighthouseapp.com/projects/2706-mootools/tickets/649">bug</a> in the MooTools selector parser where the attribute selector doesn’t properly find attributes with hyphens. So, I created a custom pseudo-selector as a workaround:</p>
<pre class="javascript">Selectors.Pseudo.data_ga = function(){
  return Boolean($(this).get('data-ga'));
};</pre>
<pre class="javascript">$$('a:data_ga').addEvent('click', function(event){
  var ga_code = this.getParents('.ga-scope')
                .get('data-ga').reverse().join('')
                + this.get('data-ga');
});</pre>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2010/03/10/google-analytics-tagging/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OpenID: Redirects and Delegation</title>
		<link>http://jasonkarns.com/blog/2010/03/06/openid-redirects-and-delegation/</link>
		<comments>http://jasonkarns.com/blog/2010/03/06/openid-redirects-and-delegation/#comments</comments>
		<pubDate>Sat, 06 Mar 2010 22:59:31 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[openid]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=71</guid>
		<description><![CDATA[The Introduction
I&#8217;m a big fan of OpenID. I like the fact that my online (public) identity is associated with a URL that I own. This affords quite a few benefits, such as associating my public profile at various networks with one another. Even better, OpenID supports the delegation of identifiers to OpenID Providers. This allows [...]]]></description>
			<content:encoded><![CDATA[<h2>The Introduction</h2>
<p>I&#8217;m a big fan of <a href="http://openid.net/">OpenID</a>. I like the fact that my online (public) identity is associated with a URL that I own. This affords quite a few benefits, such as associating my public profile at various networks with one another. Even better, OpenID supports the delegation of identifiers to OpenID Providers. This allows the owner of a domain to use the domain as an OpenID without operating his own OpenID server. He simply delegates the provider responsibilities to an existing provider by adding some HTML <code>link</code> references at the top of his OpenID URL. But before I get too far ahead of myself, a bit of history.</p>
<h2>The History</h2>
<p>The Global Name Registry was delegated the .name top-level domain by ICANN in 2001. [<a href="http://en.wikipedia.org/wiki/Global_Name_Registry">Wikipedia</a>] The intention was to set aside a specific top-level domain for individuals to register as their own domain. These domains may be registered on the second level (john.name) and the third level (john.doe.name). Generally, the second level domains are shared among the registrants of the third-level. (Aside: I find it rather surprising that the assortment of ancestry sites don&#8217;t take advantage of this for linking in family trees) In 2007 the GNR spun-off a small start-up formed as a partnership with <a href="http://janrain.com/">JanRain</a>&#8217;s OpenID provider, <a href="https://www.myopenid.com/">myOpenID</a>. This partnership created FreeYourID.com. The goal of FreeYourID was to make it dead simple for users to both register their own .name domain and use it as an OpenID. FreeYourID provided a couple great features. The domain registration was transparent to the end user, making it very friendly to non-techies. A .name email address was created (john@doe.name). FreeYourID provided a few URL forwarding options for those with existing domains. They had a decent default landing page that aggregated various social network profiles (YouTube, Flickr, Blogs). They even supported <a href="http://microformats.org/">microformats</a> with <a href="http://microformats.org/wiki/XFN">XFN</a>! And via the partnership with myOpenID, the .name domain was automatically setup as an OpenID.</p>
<h2>The Situation</h2>
<p>So in 2007 I registered <a href="http://jason.karns.name">jason.karns.name</a> from FreeYourID.com. A myOpenID account was created behind the scenes which handled the OpenID login. So as an end user I would attempt OpenID log-in at a relying party, which would navigate to <a href="http://jason.karns.name">jason.karns.name</a> and encounter the OpenID delegation snippets. This would foward over to myOpenID (tied to the shim account) where I would authenticate and be redirected back to the original service having been authenticated as <a href="http://jason.karns.name">jason.karns.name</a>. I used this service for 2 years as OpenID was beginning to gather steam. I used <a href="http://jason.karns.name">jason.karns.name</a> as my primary web address (which was forwarded to other sites). I collected a few social network links on FreeYourID&#8217;s social network page (which provided a great resource for XFN crawlers). But most importantly, I used my OpenID as my primary (in some cases, <em>only</em>) authentication method at quite a few online services.</p>
<h2>The Problem</h2>
<p>At the beginning of 2009, the .name domain was transferred to VeriSign. This spelled the beginning of the end for FreeYourID. Toward the end of the year, FreeYourID announced it was shutting down and would be transferring all services over to <a href="http://domaindiscount24.net">DomainDiscount24</a>. Prior to the transfer, I purchased <a href="http://jasonkarns.com">jasonkarns.com</a>. Once my .name was transferred, I setup an HTTP 301 redirect from <a href="http://jason.karns.name">jason.karns.name</a> to <a href="http://jasonkarns.com">jasonkarns.com</a>. The landing page of <a href="http://jasonkarns.com">jasonkarns.com</a> contained the same OpenID delegation snippets as <a href="http://jason.karns.name">jason.karns.name</a> so I assumed everything would continue to work. I was wrong. This setup prevented me from logging in at every service that used OpenID.</p>
<h2>The Discovery</h2>
<p>Through some digging and a bit of guidance by <a href="http://willnorris.com/2008/12/challenges-in-changing-my-openid">this post</a> (thanks Will), I <a href="http://openid.net/specs/openid-authentication-2_0.html#normalization">discovered</a> that an OpenID relying part must follow all redirects and the final destination URL is used as the OpenID Identifier rather than the original URL. So in my case, I would attempt to login with <a href="http://jason.karns.name">jason.karns.name</a> which redirected to <a href="http://jasonkarns.com">jasonkarns.com</a>, which was then delegated to myOpenID. I would authenticate normally at myOpenID because the delegation snippets specify which account to use at the provider. However, when redirected back to the relying party, my authentication token reported my ID as <a href="http://jasonkarns.com">jasonkarns.com</a>. As there was no existing account registered for <a href="http://jasonkarns.com">jasonkarns.com</a>, most relying parties would initiate their &#8216;new user&#8217; flow. Others just error-ed out.</p>
<h2>The Fix</h2>
<p>So now I realize what the root problem is, but I&#8217;m not sure how to fix it. I definitely have to get my OpenID working again so I must serve the OpenID delegation code from <a href="http://jason.karns.name">jason.karns.name</a> directly. However, I also want to continue using <a href="http://jasonkarns.com">jasonkarns.com</a> as the primary online destination for people looking for me.</p>
<ol>
<li>Configure DomainDirect24 to stop the HTTP 301 redirect to <a href="http://jasonkarns.com">jasonkarns.com</a></li>
<li>Create a landing page for <a href="http://jason.karns.name">jason.karns.name</a> which contains the OpenID delegation code</li>
<li>Use the old-school <a href="http://www.w3schools.com/tags/att_meta_http_equiv.asp">meta-refresh</a> to handle the redirect from <a href="http://jason.karns.name">jason.karns.name</a> to <a href="http://jasonkarns.com">jasonkarns.com</a>. OpenID Relying Parties won&#8217;t follow the meta-refresh because they are only interested in the delegation code.</li>
<li>Setup a frameset to load <a href="http://jasonkarns.com">jasonkarns.com</a> from within jason.karns.name. This is only for user-agents that don&#8217;t or won&#8217;t follow the the meta-refresh. This way end users still end up with the same content.</li>
</ol>
<h2>The Result</h2>
<pre class="html">
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"&gt;
&lt;html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'&gt;
 &lt;head&gt;
 &lt;title&gt;jason.karns.name&lt;/title&gt;
 &lt;meta http-equiv='Content-type' content='text/html; charset=utf-8' /&gt;
 &lt;!-- OpenID server and delegate --&gt;
 &lt;link rel="openid.server openid2.provider" href="http://www.myopenid.com/server" /&gt;
 &lt;link rel="openid.delegate openid2.local_id" href="http://jason.karns.name" /&gt;
 &lt;meta http-equiv="X-XRDS-Location" content="http://www.myopenid.com/xrds?username=jason.karns.name" /&gt;
 &lt;!--Redirect has been requested --&gt;
 &lt;meta http-equiv='refresh' content='0;url=http://jasonkarns.com' /&gt;
 &lt;/head&gt;
 &lt;!-- Frame Redirection for human content readers --&gt;
 &lt;frameset rows='100%,*' style='border:0;'&gt;
 &lt;frame src='http://jasonkarns.com' frameborder='0' /&gt;
 &lt;frame frameborder='0' noresize='noresize' /&gt;
 &lt;/frameset&gt;
&lt;/html&gt;
</pre>
<h2>The Future</h2>
<p>While this isn&#8217;t the opimal solution, it works for now. I rather like the idea of potentially having 2 separate OpenIDs (though they are both delegated to the same myOpenID account). However, I don&#8217;t like the meta-refresh redirect. At one point there was a discussion going on for the OpenID spec around giving 303 (See Other) redirects special behavior—as oppposed to 301 (Moved Permanently), 302 (Found) and 307 (Temporary Redirect). Although at this point, I don&#8217;t hold much hope. My only other choice of action is to follow <a href="http://willnorris.com/2008/12/challenges-in-changing-my-openid">Will Norris&#8217; method</a> and use server-side HTTP Request sniffing and respond accordingly (OpenID delegation for suspected Relying Parties, 301 Redirect for everyone else).</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2010/03/06/openid-redirects-and-delegation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript Best Practices</title>
		<link>http://jasonkarns.com/blog/2010/02/25/javascript-best-practices/</link>
		<comments>http://jasonkarns.com/blog/2010/02/25/javascript-best-practices/#comments</comments>
		<pubDate>Fri, 26 Feb 2010 02:49:47 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=57</guid>
		<description><![CDATA[@ikeif recently tweeted a request for some JavaScript best practices. Rather than simply reply to him, I thought I’d post them here and beat him to the blog-post-punch. I’m not going to expand much on any of these, although any discussion that arises will likely spawn its own post. These are in no particular order [...]]]></description>
			<content:encoded><![CDATA[<p>@<a href="https://twitter.com/ikeif">ikeif</a> recently <a href="https://twitter.com/ikeif/status/9637495634">tweeted</a> a request for some JavaScript best practices. Rather than simply reply to him, I thought I’d post them here and beat him to the blog-post-punch. I’m not going to expand much on any of these, although any discussion that arises will likely spawn its own post. These are in no particular order and are really nothing more than a brain-dump. I’ve numbered them for easy reference in the comments.</p>
<ol>
<li>Avoid global variables. When you must use a ‘global’, use your own namespace.</li>
<li>Avoid cluttering the global namespace with functions. Assign your ‘global’ functions to a single namespace (see above).</li>
<li>Discover the JavaScript framework/library that speaks to you and stick with it. Don’t load jQuery and Prototype on the same project. Yes, I know you can run many libraries in noConflict mode now, but think of the additional overhead you are placing on your users. All for some snazzy plugin? Port it!</li>
<li>Use <a href="http://www.jslint.com/">JSLint</a>. I assume you validate your HTML? Use JSLint to validate your JavaScript. If your code is JSLint safe, you can avoid a few browser idiosyncrasies (hasOwnProperty() anyone?). As a bonus, JS-Lint safe code is also <a href="http://javascript.crockford.com/jsmin.html">JSMin</a> safe so you can minify your scripts without worrying if the minification will affect functionality.</li>
<li>A side effect of using the JSLint validator in <a href="http://www.aptana.com/">Aptana</a>, my IDE of choice for front-end development, is my use of JSLint’s special `/*global */` comment. JSLint will flag any global variables unless they are explicitly listed as dependencies in this comment. This means at the top of all of my scripts, one can easily spot any required dependencies (specific MooTools modules for instance).</li>
<li>Use feature detection not browser sniffing.</li>
<li>Write unobtrusive scripts instead of inline event handlers.</li>
<li>Keep your styles in your CSS! Although most libraries make it easy to manipulate element styles, it’s much better to keep your styling where it belongs- in your CSS. Mixing the two violates separation of concerns and makes your code less maintainable. Instead, add and remove classes as necessary in your scripts.</li>
<li>Make sure your UI elements support proper interaction when JS is disabled. If a link opens a lightbox, set the href to point to the lightbox content so no-JS users can still access the content. Links with `href=”#”` kill kittens.</li>
<li>Any UI elements that *only* support JavaScript interaction (and think carefully about this) should be created by JavaScript. Don’t litter your HTML will dummy elements that are only there for JS events. Your script should create and inject them.</li>
<li>If at all possible, don’t modify libraries or plugins directly. This makes future upgrades a nightmare. It is much better to extend the plugin/library without modifying the original.</li>
<li>Your .js files should be served with HTTP `Content-Type: application/javascript`. BUT the `type` attribute in your HTML `script` element must be `text/javascript` or else Internet Explorer will crap itself.</li>
<li>Language=”JavaScript” was deprecated, like, a zillion years ago. Stop using it.</li>
<li>Don’t pre-optimize your code by using fancy looping structures. It is much better to have readable code. Once your app is running, then you can go back and profile it to eliminate bottlenecks. There is no point in pre-optimizing your scripts when the overhead of your background image is 10x slower.</li>
<li>Don’t return false from an event listener when all you really want is event.preventDefault(). Maybe someone else wants to listen for that click event, too, mmmkay?</li>
<li>Stop using document.write</li>
</ol>
<p>Okay, that’s my list. I may add more later. Disagree with any of these? What best practices or anti-patterns do you have?</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2010/02/25/javascript-best-practices/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>CSS Reset</title>
		<link>http://jasonkarns.com/blog/2010/02/15/css-reset/</link>
		<comments>http://jasonkarns.com/blog/2010/02/15/css-reset/#comments</comments>
		<pubDate>Tue, 16 Feb 2010 04:34:17 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[css]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=54</guid>
		<description><![CDATA[Why start with a blank slate? After years of web development and hundreds of sites, starting from scratch on each project really turns into a buzz kill. Nobody wants to spend time rehashing the same issues from site to site. So many of us have turned to CSS Resets. As we all know, CSS Resets [...]]]></description>
			<content:encoded><![CDATA[<p>Why start with a blank slate? After years of web development and hundreds of sites, starting from scratch on each project really turns into a buzz kill. Nobody wants to spend time rehashing the same issues from site to site. So many of us have turned to CSS Resets. As we all know, CSS Resets are designed to fix cross-browser inconsistencies by rebasing all or most default styles to a common state. I’ve always had a problem with these resets. Many of the styles in these resets are never used (how often do you use <code>q</code>, <code>ins</code>, <code>del</code>, and <code>table</code> anymore, really?). Other styles are completely overridden. I would wager that by the end of a long project, one could probably remove the CSS Reset without affecting the design (save maybe the margin/padding rules). <span class="vcard"><a class="fn url" href="http://snook.ca/">Jonathan Snook</a></span> <a href="http://snook.ca/archives/html_and_css/no_css_reset/">feels the same way</a>. For these reasons, I’ve generally used the universal margin/padding reset:</p>
<pre class="css">* {margin:0; padding:0;}</pre>
<p>There is quite a lot of contention around the subject both for and against as well as the reasoned <a href="http://meiert.com/en/blog/20080419/reset-style-sheets-are-bad/">centrist</a>.</p>
<p>So, rather than continue to rail against their futility, performance penalty, or outright boorishness, I thought I’d actually use a CSS reset a few times and report my findings.</p>
<h2>Decision Time!</h2>
<p><a href="http://meyerweb.com/eric/tools/css/reset/index.html">CSS Reset</a> by <span class="vcard"><a class="fn url" href="http://meyerweb.com/">Eric Meyer</a></span> or <a href="http://developer.yahoo.com/yui/reset/">YUI Reset</a>? Well, after watching <a href="http://vimeo.com/7530607">this video</a> (you should, too), my decision was firmly in the Meyer camp.</p>
<h2>First Reactions</h2>
<p>Who uses Firebug? Okay, sorry, who <strong>doesn’t</strong> use Firebug? If you don’t, you should, and if you do, you likely won’t like Meyer’s reset without it first being modified. Ladies and gentlemen of the jury, Exhibit A:</p>
<p><a href="http://jasonkarns.com/blog/images/CSSReset_14B48/reset.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="reset" border="0" alt="reset" src="http://jasonkarns.com/blog/images/CSSReset_14B48/reset_thumb.png" width="454" height="912" /></a> </p>
<p>Due to the first rule in the reset, the font-size property is applied to (nearly) every element. However, <code>font-size</code> is also an inherited property. Which means nearly every element inherits its value from its parent, while simultaneously being reset itself by the same rule it inherited! The first rule of nearly every stylesheet of mine usually includes a set of font properties (<code>font-family</code>, <code>font-size</code>, and <code>line-height</code>). With these properties already being set, there is no reason to have them in my CSS Reset, so let’s remove the offending rule and relieve some of Firebug pressure.</p>
<p><a href="http://jasonkarns.com/blog/images/CSSReset_14B48/reset3.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="reset3" border="0" alt="reset3" src="http://jasonkarns.com/blog/images/CSSReset_14B48/reset3_thumb.png" width="454" height="231" /></a> </p>
<p>Whew, that’s better.</p>
<h2>Don’t Lose Your Focus!</h2>
<p>The most offending rule in Eric’s reset is his outline rule:</p>
<pre class="css">:focus { outline: none; }</pre>
<p>Sure, he adds a comment to remind users to be sure to specify proper outlines for keyboard users. But you and I can both count on one hand the number of times a proper outline is reinstated for the <code>:focus</code> pseudo-class. Besides, I subscribe to the belief that frameworks and tools should make it easy to fall into the <a href="http://www.codinghorror.com/blog/2007/08/falling-into-the-pit-of-success.html">pit of success</a> rather than making it harder to do things the <em>right</em> way. Luckily, <span class="vcard"><a class="fn url" href="http://www.splintered.co.uk/">Patrick H. Lauke</a></span> has <em><a href="http://24ways.org/2009/dont-lose-your-focus">outlined</a></em> (sorry, I couldn’t help it) a method to remove the outline during its less-useful moments, while retaining the outline as necessary for keyboard navigation. In brief, simply:</p>
<pre class="css">a:hover, a:active { outline: none; }</pre>
<p>This will hide the ugly outline during the click action on a link as well as during the time the page loads (so long as the user doesn’t move their mouse). I think this fits nicely in the 80/20 category.</p>
<h2>And Now?</h2>
<p>So where does that leave us? I’m not sure. I’m still not entirely convinced of the utility of a CSS Reset. However, I believe my two minor modifications do bring Meyer’s Reset a bit further into the &#8216;’useful’ category without being a pain or downright harmful. My version of the reset is hosted at <a href="http://github.com/">GitHub,</a> so if you don’t like it, go fork it!</p>
<p><a title="http://github.com/jasonkarns/css-reset" href="http://github.com/jasonkarns/css-reset">http://github.com/jasonkarns/css-reset</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2010/02/15/css-reset/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Roy.G.Biv alpha</title>
		<link>http://jasonkarns.com/blog/2009/11/17/roy-g-biv-alpha/</link>
		<comments>http://jasonkarns.com/blog/2009/11/17/roy-g-biv-alpha/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 02:45:50 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[css]]></category>
		<category><![CDATA[rgba]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=47</guid>
		<description><![CDATA[I was recently on a project that called for a translucent background color over a an image similar to this:
 http://www.flickr.com/photos/yeowatzup/ / CC BY 2.0
Of course, being the conscientious web developers we are, we want to be as semantic as possible with our markup. This means that text should be marked up as text and [...]]]></description>
			<content:encoded><![CDATA[<p>I was recently on a project that called for a translucent background color over a an image similar to this:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="rgba" src="http://jasonkarns.com/blog/images/Roy.G.Bivalpha_1339B/rgba_thumb.jpg" border="0" alt="rgba" width="491" height="198" /> <a rel="cc:attributionURL" href="http://www.flickr.com/photos/yeowatzup/">http://www.flickr.com/photos/yeowatzup/</a> / <a rel="license" href="http://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a></p>
<p>Of course, being the conscientious web developers we are, we want to be as semantic as possible with our markup. This means that text should be marked up as text and not flattened into the image, forever to remain hidden from the world of web spiders, search engines, assistive technologies, and mash-up artists. We give the text a background color to keep the text readable over the background image but we still want the background image to be slightly visible through the text area. Before RGBa, we would resort to a 1 x 1px translucent PNG but this adds additional overhead (both with the extra HTTP request, the maintenance of the image should the color change, and a PNG fix for IE6). Another option would be the CSS opacity property. Unfortunately, the opacity property applies to an element and all of its descendants. This means the text itself would become translucent as well, something we would like to avoid if possible. So, let’s use some RGBa!</p>
<p>First, add the standard RGB background color so the text block will still be legible in browsers that don’t support RGBa:</p>
<pre class="css">  div {
    background: rgb(100, 100, 183);
  }</pre>
<p>Now we can enhance this for conforming browsers:</p>
<pre class="css">  div {
    background: rgba(100, 100, 183, .75);
  }</pre>
<p>We now have support in Firefox 3+, Webkit (Safari 3+, Chrome 1+). What about that other browser? To add support for IE6-IE7, we need to use IE&#8217;s proprietary filter property. As this is a proprietary property, it should be included via an IE-only stylesheet referenced using <a href="http://www.quirksmode.org/css/condcom.html">Conditional Comments</a>.</p>
<pre class="css">  div {
    background:transparent;
    filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#BF6464B7,endColorStr=#BF6464B7);
    zoom: 1;
  }</pre>
<p>A bit of an explanation is in order. First we set the background to transparent which overrides the solid color rgb declaration. Next we apply IE’s proprietary filter. Notice we set the startColorStr and the endColorStr to the same values. These values are not your standard HEX values. Instead of 0xRRGGBB, the first 2 digits are the alpha transparency. Converting our 75% into HEX (.75 * 255 –&gt; 191.25 –&gt; 0xBF). Lastly, we apply the zoom property to <a href="http://www.satzansatz.de/cssd/onhavinglayout.html">trigger hasLayout</a> on the element. This is required for the filter to take effect.</p>
<p>Keen observers will note that the filter property is not supported in IE8 standards mode. As IE8 now properly follows the CSS grammar, we must add the vendor prefix and quote the value. The hasLayout trigger is no longer needed.</p>
<pre class="css">  div {
    background:transparent;
    -ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#BF6464B7,endColorstr=#BF6464B7)";
  }</pre>
<p>Combined, we have our main CSS:</p>
<pre class="css">  div {
    background: rgb(100, 100, 183);
    background: rgba(100, 100, 183, .75);
  }</pre>
<p>and IE&#8217;s CSS:</p>
<pre class="css">  div {
    background:transparent;
    filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#BF6464B7,endColorStr=#BF6464B7);
    -ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#BF6464B7,endColorstr=#BF6464B7)";
    zoom: 1;
  }</pre>
<p>We have now achieved cross-browser, CSS-only (no PNGs needed), alpha transparency!</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2009/11/17/roy-g-biv-alpha/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>jQuery.Firebug: A call for feedback.</title>
		<link>http://jasonkarns.com/blog/2009/02/11/jqueryfirebug-a-call-for-feedback/</link>
		<comments>http://jasonkarns.com/blog/2009/02/11/jqueryfirebug-a-call-for-feedback/#comments</comments>
		<pubDate>Wed, 11 Feb 2009 20:17:49 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[firebug]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[debugging]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=33</guid>
		<description><![CDATA[As a result of some of the discussion following from my post on my new jQuery plugin, jQuery.Firebug I&#8217;m soliciting feedback for its desired behavior. Example:

$('.setA').log();
$('.setB').log("some", "information");
$('.setC').log("title attribute is: ", ".attr('title')");

Some explanation. The log method follows the same rules as the Firebug console.log method. It can take 0 or more arguments that are concatenated into [...]]]></description>
			<content:encoded><![CDATA[<p>As a result of some of the discussion following from my post on my new jQuery plugin, <a href="http://jasonkarns.com/blog/2009/01/06/announcing-jqueryfirebug/">jQuery.Firebug</a> I&#8217;m soliciting feedback for its desired behavior. Example:</p>
<pre class="javascript">
$('.setA').log();
$('.setB').log("some", "information");
$('.setC').log("title attribute is: ", ".attr('title')");
</pre>
<p>Some explanation. The log method follows the same rules as the <a href="http://getfirebug.com/console.html">Firebug console.log</a> method. It can take 0 or more arguments that are concatenated into a space-separated string when finally printed to the console. For some jQuery-specific behavior, I have added a little wrinkle as shown with the log statement following SetC. If an argument to the log method:</p>
<ol>
<li>is a string</li>
<li>begins with a period (dot)</li>
<li>is a valid jQuery method</li>
</ol>
<p>then the jQuery method specified is executed on the jQuery selection and the <em>result</em> is printed to the console. In the example above, if the title attribute on the first element of <var>SetC</var> is <code>'example title'</code> then the final log message would be <code>"title attribute is: example title"</code>.</p>
<p>Further, my the plugin will feature an additional option (off by default) that will explicitly print each element in the jQuery selection wrapped in a <code>console.group</code>. In the example above, say <var>SetC</var> contains 2 <code>&lt;span&gt;</code> elements. If the option were turned on, the output would be similar to the output of the following:</p>
<pre class="javascript">
console.log("title attribute is: example title");
console.group($(".setC"));
console.log($(".setC").get(0));
console.log($(".setC").get(1));
console.groupEnd();
</pre>
<p>So, back to the problem at hand. My issue, is when and where to print the jQuery selection itself. The different options are:</p>
<ol>
<li>only print the jQuery selection when there are no arguments to the log method</li>
<li>only print the jQuery selection when there are no arguments to the log method but also print the jQuery selection in place of any string argument  equalling <code>"this"</code> (similar to my jQuery method replacement demonstrated above with <code>.attr("title")</code>)</li>
<li>always prepend the jQuery selection to the arguments (so the jQuery selection is printed before the rest of the arguments)</li>
<li>always append the jQuery selection to the arguments (so the jQuery selection is printed after the rest of the arguments)</li>
</ol>
<p>I&#8217;m leaning towards either #3 or #4 but am open to feedback. Please comment with your suggestions. Keep in mind that all four above choices will still result in just one log message per <code>log()</code> call. Turning on the &#8216;<code>explicit</code>&#8216; option is the only thing that will result in more console messages than <code>log()</code> calls. Also, keep in mind that printing the jQuery selection itself to the console will allow deep inspection. For instance, clicking on the jQuery selection in Firebug shows what elements are selected, etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2009/02/11/jqueryfirebug-a-call-for-feedback/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>You&#8217;ve Got Mail!</title>
		<link>http://jasonkarns.com/blog/2009/02/06/youve-got-mail/</link>
		<comments>http://jasonkarns.com/blog/2009/02/06/youve-got-mail/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 20:43:06 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[userstyles]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[stylish]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=28</guid>
		<description><![CDATA[I&#8217;m a big fan of Gmail and Google Reader. I generally leave these tabs (along with Google Calendar) open all day long. To minimize the amount of visual space these long-lived tabs consume in the tab bar, I use the great FaviconizeTab extension. However, with these tabs minified, you lose the ability to be notified [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a big fan of Gmail and Google Reader. I generally leave these tabs (along with Google Calendar) open all day long. To minimize the amount of visual space these long-lived tabs consume in the tab bar, I use the great <a href="https://addons.mozilla.org/en-US/firefox/addon/3780">FaviconizeTab</a> extension. However, with these tabs minified, you lose the ability to be notified visually (via the title text) of new mail or new posts. A simple solution that I found years ago was to write a simple user style to change the background color of the tab whenever a new item arrives. It&#8217;s a great simple solution that doesn&#8217;t require any new programs or extensions. For those of you who use the <a href="https://addons.mozilla.org/en-US/firefox/addon/2108">Stylish</a> extension, I&#8217;ve finally gotten around to posting this style to <a href="http://userstyles.org/">userstyles.org</a> so installation is dead-simple. This style also works well with the <a href="https://addons.mozilla.org/en-US/firefox/addon/8121">Badges on Favicon</a> extension which actually displays the number of unread items via small &#8216;badge&#8217; on the tab. Go ahead and <a href="http://userstyles.org/styles/14571">grab the style</a> now! I&#8217;ve posted a <a href="http://userstyles.org/styles/14572">Firefox 1.5 &#8211; 2.0 compatible version</a> as well. (But seriously, if you&#8217;re not using Firefox 3, <a href="http://www.mozilla.com/en-US/firefox/">upgrade now</a>!)</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2009/02/06/youve-got-mail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gmail S/Mime Icons</title>
		<link>http://jasonkarns.com/blog/2009/01/30/gmail-smime-icons/</link>
		<comments>http://jasonkarns.com/blog/2009/01/30/gmail-smime-icons/#comments</comments>
		<pubDate>Fri, 30 Jan 2009 20:13:38 +0000</pubDate>
		<dc:creator>jasonkarns</dc:creator>
				<category><![CDATA[userstyles]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[smime]]></category>
		<category><![CDATA[stylish]]></category>

		<guid isPermaLink="false">http://jasonkarns.com/blog/?p=20</guid>
		<description><![CDATA[I&#8217;m a big fan of Gmail and I&#8217;m a big fan of S/MIME for securing your email. Unfortunately, the current state of S/MIME on web-based email is currently quite sad.  There is a Firefox extension which allows you to send signed/encrypted messages from Gmail by Richard Jones and Sean Leonard. (called Gmail S/MIME, surprisingly [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a big fan of Gmail and I&#8217;m a big fan of S/MIME for securing your email. Unfortunately, the current state of S/MIME on web-based email is currently quite sad.  There is a Firefox extension which allows you to send signed/encrypted messages from Gmail by Richard Jones and Sean Leonard. (called <a href="https://addons.mozilla.org/en-US/firefox/addon/592">Gmail S/MIME</a>, surprisingly enough) However, Gmail does not provide any visual indicator to differentiate between unsigned/unencrypted messages and signed/encrypted messages.  I found a great <a href="http://userstyles.org/styles/3958">user style</a> by <a href="http://userstyles.org/users/74">Moktoipas</a> (updated for compatibility with the recent Gmail changes) which replaces the default Gmail attachment icon (paperclip) with icons that represent the standard attachment file types (.doc, .txt, .gif, etc). Lo and behold, <a href="http://userstyles.org/users/357">lownoise</a> took this idea and created <a href="http://userstyles.org/styles/464">two</a> <a href="http://userstyles.org/styles/465">userstyles</a> to provide the same icon support for signed and encrypted messages. Signed messages sport a certificate icon and encrypted messages sport a padlock icon. However, these userstyles haven&#8217;t been updated to cope with Gmail&#8217;s newest changes. I have taken it upon myself to make the required changes and post the new style for everyone&#8217;s use. I can&#8217;t claim too much credit, however, as the changes required were only a couple lines of code, which I simply copied from Moktoipas&#8217; styles. In addition, I merged the two styles &ndash; one for signed messages and one for encrypted messages &ndash; into one style.  While this style is extra beneficial for users of the Gmail S/MIME extension, it does not require it.  Further, the style is packaged as both a <a href="https://addons.mozilla.org/en-US/firefox/addon/2108">Stylish</a> userstyle and a <a href="https://addons.mozilla.org/en-US/firefox/addon/748">Greasemonkey</a> userscript so users of either extension can get their style on. <a href="http://userstyles.org/styles/14323">Grab the style</a> from <a href="http://userstyles.org">userstyles.org</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jasonkarns.com/blog/2009/01/30/gmail-smime-icons/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
