No Mod Required

Archive for the 'tips-and-tricks' Category

Code I Like - Link Prefetching

I was reading John Resig's Browser Page Load Performance post earlier today and followed up from there on the concept of Link prefetching. Currently supported by Firefox 2+, Link prefetching is a browser based mechanism for fetching "future" content. Considering I wrote (and ultimately scrapped*) similar functionality for my gallery pages, I was obviously intrigued.

In its basic version it looks like this:

<link rel="prefetch" href="/images/big.jpeg">

With the href being the target content and the rel attribute triggering the prefetching mechanism. Pretty simple. I've already implemented it here on my gallery pages.

One thing I would like to see, and this is hinted at on the above linked Mozilla FAQ page, is prefetching performed automatically on anchor (<a>) tags with rel attribute set appropriately. In my mind that would be any anchor with a rel attribute of next, but the prefetch value would be fine as well. Personally, if that were supported I wouldn't have any (or very little) work to do to take advantage of this feature and in a general sense it would build on what people are already doing using prev, next and toc rel attributes on gallery links.

*it was scrapped because I hated the idea of forcing bandwidth usage on people with metered accounts. Since this is a browser based mechanism, it should be relatively painless for people in that situation to control whether or not content is prefetched.

Webmonkey Relaunches and I Flashback to the 90s

For real! I ran through all of the primordial webmonkey tutorials* when I was starting out building sites (10-11 years ago now!) and if the newly relaunched site is half as helpful it will be a great boon to the community. Great info and a friendly, funny attitude made it the place for me to learn about the web thing back in the last century. Honestly, I owe a lot to the usefulness of those early tutorials. Looking back on it I realize that Webmonkey, coupled with the community that sprang up around Dreamweaver at the time**, was a great forge upon which to build up my web chops.

We're Back! Webmonkey Relaunches, Rejoins Wired

The original web developer's resource has returned. Webmonkey has been completely redesigned, and we're ready to rock once more. Also, our entire content library is now hosted on a wiki, so every tutorial, reference page and code example is open for editing. Come on in and show us what you've got!

Webmonkey: the Web Developers Resource

*Some still exist: like Thau's JavaScript Tutorial, which is over ten years old now.

**I've been a Dreamweaver user since Version 1.2.

Google Doctype - First Pass? Very cool.

Google Doctype, as introduced by Mark Pilgrim:

The open web is the web built on open standards: HTML, JavaScript, CSS, and more. The open web is a beautiful soup of barely compatible clients and servers. It comprises billions of pages, millions of users, and thousands of browser-based applications. You can access the open web with open source and proprietary browsers, on open source and proprietary operating systems, on open source and proprietary hardware.

Google has built its business here, on the open web, and we want to help you build here too. To that end, we are happy to announce the formation of an encyclopedia for web developers, by web developers: Google Doctype.

Google Code Blog: Introducing Google Doctype

Personally, I'm excited by this development (both practically and philosophically) and will likely contribute wherever it makes sense for me to lend a hand. Looking at it quickly some of the HOWTO information is already very useful (the web security information especially) and it will only improve with time as more and more dedicated people get involved with the project.

Using overflow:auto to Clear Floated Content in CSS

For a long time, I used something like <div style="clear:both"></div> or its class equivalent to clear floated content in layouts. I knew, at some level, there were better solutions, but as these things go- I had deadlines to meet, had a working solution and there was never any inducement to look for a new one. Sure, there was a little extra markup, but it was so limited I could live with it.

Then in a comment on another post here ArkRep gift wrapped a better solution- one I vaguely knew about but had never explored. It looked a little something like this:

.clr {
clear:both;
}
.clr:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.clr {display: inline-block;}

Liking it, since it swapped the useless markup hack thingie for a single class, I took a modified version of his code and moved it into our baseline screen.css at work. I then passed along the addition to the rest of the team. One of them (hi Ryan*), started to do some research into the code above and as an adjunct of that research came across a solution to the problem that was so simple and so clean that it really annoyed me that I didn't know about it until last week. You can read about the solution in depth at the Sitepoint Blogs (3 years old!)

The simple and clean solution? Use overflow:auto on the containing div and it will, er, contain. Look at this simplified version:

Here's the relevant CSS:

#container #content {
	overflow:auto;
	border:1px solid gray;
}
#container #copy {
	width:140px;
	border:.1em solid #CFCFCF;
	float:left;
	border:1px solid green;
}
#container #sidebar {
        width:140px;
	overflow:auto;
	float:right;
	blorder:1px solid pink;
}
#container #content #sidebar #sidebar-0{
	float:left;
	border:1px solid orange;
	}
#container #content #sidebar #sidebar-1{
	float:right;
	border:1px solid purple;
	}
#container #content #sidebar #sidebar-0,
#container #content #sidebar #sidebar-1 {
	width: 65px;
}
#container #footer {
	border:1px solid black;
}

I wish there was more to write about, but it's really that simple. The biggest concern is that your math must work or else you'll get scrollbars. With other versions of clearing floats, you were allowed to be a little looser with the calculations- if your sidebar actually leaked (overflowed) into the gutter beyond the edge of your container it didn't actually matter since it would display correctly. With overflow:auto you don't have that luxury. Of course, who wants to be sloppy? :)

*link? Where should I link?

Twenty New Yahoo! Performance Breakthroughs

I don't know how many of these are "breakthroughs," but if you really are getting an A (and even if you're not), you might want to take a look at the following enhancements to squeeze the most out of your site's performance:

Looking at the list, many are already very familiar to me, but there are definitely a couple I'm interested in learning more about- more than a full bullet points in the above slideshare. Hopefully the teaser of "more detail coming soon" in the YDN blog post will come to pass sooner rather than later.

And no, I don't yet score an A, but I do get a 96 for the components I fully control, so I'm more than happy to look to other suggestions (like the ones below that I don't already practice) to get this place running a little quicker.

1. Flush the buffer early [server]
2. Use GET for AJAX requests [server]
3. Post-load components [content]
4. Preload components [content]
5. Reduce the number of DOM elements [content]
6. Split components across domains [content]
7. Minimize the number of iframes [content]
8. No 404s [content]
9. Reduce cookie size [cookie]
10. Use cookie-free domains for components [cookie]
11. Minimize DOM access [javascript]
12. Develop smart event handlers [javascript]
13. Choose over @import [css]
14. Avoid filters [css]
15. Optimize images [images]
16. Optimize CSS sprites [images]
17. Don't scale images in HTML [images]
18. Make favicon.ico small and cacheable [images]
19. Keep components under 25K [mobile]
20. Pack components into a multipart document [mobile]

More at the YDN blog:

Yahoo!'s Latest Performance Breakthroughs

Two Columns of Variable But Equal Height Using Simple CSS and a Couple of DIVs

If, like me, you cut your web development teeth during while CSS was still in its infancy, you likely put together a lot of sites that featured two (or more) columns decorated with bgcolors or background images that flowed together in lockstep, always retaining equivalent height. It was pretty standard and basically came along free with tables for layout.

Then? Along came CSS, the separation of style and content (don't forget behavior!) and the two columns living in perfect harmony became a casualty of the war against crufty code.

Which brings us to this post. I've played around with a similar technique before, but I'd never taken it to this, it's logical conclusion. This technique grew out of some conversation at work. I don't remember the specifics, but I remember I was looking at some unrelated piece of code on someone else's monitor. Walking back to my desk it reminded me of one thing or another and then the pieces started to tumble around in my head. It was a couple of hours later, on my drive home from work, when they clicked into place and I thought, "hey, I could fake that old technique!"

The basic idea goes a little something like this: just because a background color or gradient appears to be part of an element, that doesn't mean it needs to actually be applied directly to that HTML element. Instead, using some basic CSS and a repeating background image we can fake that two column look by positioning the two columns on top of the "columns" formed by the background image . As long as the containing DIV grows with either of the columns and the gap in the background image matches the background (or is transparent, wlloing the background to show through) the illusion is maintained.

It's like magic.

Here's the sample (which I only tested in FF2 and IE7):

Here's the CSS:

/*the two-column container*/
#container #two-columns {
	/*set that background image*/
	/*repeat it and center it*/
	background: url(images/bg.jpg) repeat-y center;
	height: auto;
	width: 500px;
	margin:auto;
	margin-bottom:20px;
}
#container #two-columns #column-2 {
	/*float it*/
	float:right;
	height: auto;
	width: 215px;
	padding:5px;
}
#container #two-columns #column-1 {
	height: auto;
	width: 215px;
	padding:5px;
}
/*clear the above float*/
#container .clr {
	clear:both;
}

and here's the HTML:

<div id="two-columns">
<div id="column-2">   A column in structural engineering is a vertical structural element that transmits, through compression, the weight of the structure above to other structural elements below. </div> 
<div id="column-1"> A column in structural engineering is a vertical structural element that transmits, through compression, the weight of the structure above to other structural elements below.  </div>
<div class="clr"></div>
</div>

I told you it was simple. If you're familiar with modern layout techniques the above should be commonplace. The interesting bit (to me at least) is the concept of pulling the "background" of the two columns off of the columns themselves and onto the containing DIV. This separation can be a powerful technique. I've used it before in a different context, but I think this example really illustrates how useful it can be. I'm already starting to see other possibilities for this pattern.

Expanding the toolbox is fun.

Of course, before I can actually use this technique where it's most needed by me, I have to come up with a scheme that works with both variable width and variable height. Tricky stuff. If I can pull that of, I'll install it right on my home page. As it stands now I'm using JavaScript to equalize the heights on the two news DIVs at the bottom.

Boo.

The good news is I've actually made some progress with the variable width/height version. Unfortunately, nothing is quite ready for prime time though so that'll have to be unveiled in another post. Keep your eyes peeled and your fingers crossed. I'll keep at it with the typing.

I just realized- JavaScript is my Perl

Twice this morning I did massive, repetitive, string manipulations with JavaScript.

One took a list of files, turned it into an array and then looped through creating .htaccess entries.

The other took an HTML table output by Excel and turned it into a Definition List. I then used FireBug to copy the innerHTML of the body and pasted it into a new document, ready to be manipulated in the application I'm building (with JavaScript of course :) ) If you're curious, here's the code for that one:

<script type="text/javascript">
window.onload = function() {
    var trs = document.getElementsByTagName("TR");
    var newString ="<dl>";

    for (i=0;i<trs.length;i++){
        var tds=trs[i].getElementsByTagName("TD");
        newString +="<dt id='"+tds[1].innerHTML+"'>"+tds[4].innerHTML+"</dt>";
        newString +="<dd>"+tds[5].innerHTML+"</dd>";
    }
    newString +="</dl>"
    document.body.innerHTML=newString;
    }
</script>

Anyway, I've done this sort of thing before and I realized that I'm using JavaScript for the sort of administrative scripting that other people would use Perl or Python for.

No, there's nothing more to this post than that.

:)

I just wanted to point it out since it struck me as interesting.

Does anyone else out there use JS for this sort of thing?

Or am I a complete weirdo?

Now Serving: Freshly Compressed Javascript

I finally got around to compressing this site's JavaScript file last night. I used /packer/ because I know that it supports conditional compilation. I'm a fan of conditional compilation.

It was funny because there were a couple of lines missing semi-colons that I must have looked at a thousand times before last night and just never noticed that they were nekkid like that. JSLint helped me out a lot with making sure the file was ready for packing.

Anyway, between gzipping and compressing it my JS file screams out to the browser at a tidy 2.67 KB (down from an unadulterated 9.41 KB.) There are probably functions in some libraries larger than that…

Go small or go home!

Setting Far Future Expires Headers For Images In Amazon S3

Summary:

Amazon S3 is a great option for (among other things) image hosting, YSlow is a great little tool for uncovering performance related issues with a site and using Bucket Explorer allows a person to easily upload files to the S3 service while setting custom headers. Using the tool to set far future expires headers facilitates caching which improves site performance.

Preface

I started using Amazon Simple Storage Service (Amazon S3) for image hosting this week to help cut down on my bandwidth costs. S3 is a great service offered by Amazon Web Services that allows developers to store and serve data using Amazon's infrastructure for literally pennies per GB of storage and transfer.

Why have I begun the move? Well, as I hoped, I've had excellent growth in site traffic since I relaunched last year. Great stuff, except for the fact that my bandwidth usage has begun to strain the limits of my current hosting plan. I serve a lot of images* so I can eat through GB pretty quickly. I considered switching hosts, but after 8 years with FutureQuest, and literally nothing to complain about in all that time I've come to the conclusion that I really love my web host and I'm just not going to switch.**

So, with switching off the table, I had to figure out something else to do. If you want numbers- my October 2007 bandwidth usage was up 712% over my bandwidth usage in October of 2006.

That and I want to keep growing.

So… what's a man to do?

Amazon S3 to the rescue

That's where S3 comes in. I looked at S3 for a few weeks before signing up and I came up with the following conclusions- the infrastructure can't be beat, it scales to the moon, I love the fact that I'll pay for just what I use and for what I use the pricing is just fantastic.

I could move my images over to Amazon, see another 700% increase in bandwidth usage over the next year and still be making out with some savings. Check out these numbers:

Storage
$0.15 per GB-Month of storage used

Data Transfer
$0.10 per GB - all data transfer in
$0.18 per GB - first 10 TB / month data transfer out
$0.16 per GB - next 40 TB / month data transfer out
$0.13 per GB - data transfer out / month over 50 TB

Requests
$0.01 per 1,000 PUT or LIST requests
$0.01 per 10,000 GET and all other requests

Looking at those numbers and looking at the incredible tools out there already to make using S3 as simple as using a traditional FTP client to move files onto the web, it became pretty clear that S3 was the solution to my problem. So I signed up and went about the process of setting up one of my sub domains (media.drunkenfist.com) to point to Amazon so that the transition, for at least the files already served off of that domain, would be seamless.

As an aside- setting up a sub domain to point to Amazon is really pretty easy. All I had to do was create a bucket (an S3 organizational structure somewhat analogous to a typical folder) named media.drunkenfist.com and then set up (through my host) a CNAME record that pointed requests for media.drunkenfist.com over to that bucket on the Amazon servers.

Something like this:

media.drunkenfist.com CNAME media.drunkenfist.com.s3.amazonaws.com

As long as the bucket name matches the host name exactly, it's really dead easy.

Anyway, back to the narrative.

Once the domain was pointed in the right direction and the files were being served from Amazon's servers, I tested it, was happy with the results and gave myself a little pat on the back for a job well done.

I relaxed a little bit and my attention started to turn to my plan for moving the rest of my images (those not already served off of media) over to the new hosting server. I've got to take the rest of the migration slowly because I don't want to jeopardize my image search traffic. I've got to make sure any changes I make to popular images won't break Google's snapshot of my site.

All in all, it's a typical side-project for me. A little thinking, a little research, a little planning and then, some furious late-night execution across a few different disciplines.

Good times :)

And then came Christmas, where the one flaw in my original implementation poked its head out from the pages of High Performance Web Sites: Essential Knowledge for Front-End Engineers

Confessions of a YSlow junkie

Maybe "junkie" is too strong a phrase :) I am interested in site performance, however, and the YSlow plugin for Firebug is a great tool for analyzing issues with the way pages are constructed and the manner in which site components are served.

Anyway, I got the High Performance Web Sites book for Christmas and while I was flipping through it I was struck by rule #3. In short #3 says to use a far future expires header for images in order to facilitate caching. Since all the images I was hosting over at Amazon were interface images (like my sprite***,) getting them to cache correctly was important business.

Thing is? Unlike the images served by my main web host****, the images over at Amazon weren't getting served with any expires headers at all.

Bummer.

I had used the Amazon S3 Firefox Organizer(S3Fox) Firefox Add-on to move my files over to Amazon originally and while it integrates with my browser of choice and is dead easy to use, it doesn't allow a user to set the expires header for files it creates on the Amazon server.

Oops.

The Solution

Some furious Googling led me to Bucket Explorer a handy little app that allows one to set custom headers for files being uploaded to the Amazon servers. Before finding that I had visions of writing my own uploader in PHP. Part of me thought that would be fun. The other part just wanted a nice, handy solution written by someone else since I've already got a million little side projects going on and adding a new one didn't seem like the most efficient idea.

Anyway, to add custom headers using Bucket Explorer:

  1. Fire up the program
  2. Enter your access key and secret key
  3. Navigate to the local folder in the left pane and the target bucket in the right pane
  4. Select the image (or images) in the local folder
  5. Right click and select "Upload with Custom Headers"
    select-dialog.jpg
  6. Click "Add" in the dialog that opens
    upload-with-custom-header.jpg
  7. And finally, enter your header information
    enter-header-information.jpg

    For more info on the expires header and the value to enter, check out the HTTP/1.1 Header Field Definitions provided by the w3c.

  8. Hit OK a bunch of times, and that's that. You've got far future expires set up and your return/multiple page visitors will be all the better for it.

As you can see, that's really pretty straightforward.

The software costs $29.99, but there's a 30 day trial if you want to check it out in advance. I'll definitely be ponying up my hard earned dollars as Bucket Explorer does pretty much everything I need an interface to S3 to do and feels faster/more stable than some of the other options I've looked at.

As a note, if you're interested in any of the topics covered in this post, I've got another performance related post to drop over the next couple of days and I'll be updating the blog with the S3 stuff as often as I encounter anything interesting, so check in from time to time to see what's new.

*Both here and in leeched form across the breadth of the "social web." I decorate many myspace (and Hi5 and Friendster and YouTube, etc. etc. ) pages.

I love seeing 15-20 year old kids taking my stuff to decorate their pages, by the way. It's the most honest validation of my work I could ever imagine.

**Especially since moving my main site, the four subdomains (comics., media., styles., and mobile.,), two alternate domains (roblarsen.org and robreact.com) and one redirected domain (itsalljustcomics.com) seems like an incredible pain in the ass. We're talking DNS, code, databases, passwords, paths, blah, blah, blah. I just can't see myself doing it without some sort of mythically powerful inducement. Maybe if I could host my own box somewhere or something. Anything short of that and it's just a nightmare.

***It's not quite as nice as Ask's, but it's still pretty good, I think.

I love that Ask sprite, by the way. That's some great attention to detail on their part and the execution of it is a dramatic lesson in how to construct a great Sprite image for serving a single interface image.

**** My main server is running Apache, so I have the following in my root .htaccess to set expires headers for images:

ExpiresActive On
ExpiresByType image/gif A2592000
ExpiresByType image/png A2592000
ExpiresByType image/jpeg A2592000

Why Did I Never Try this Before? CSS Font-Size : 0 Hides Input Button Text

Support: This technique is supported by IE 5.+, Firefox (and the rest of the Mozilla family) and Safari 3.0*. It is not supported by Opera** (any version), Netscape 6.2 and earlier or Camino.

Warning: I haven't thought this all the way through, so if you see any problems with this technique other than the above support caveats, then please let me know :) I'm really just writing this up because I just thought of doing it, I tried it and it worked…

The issue and solution: Occasionally I need to use an image, with text, for the background of an input button. It's rare, but occasionally it needs to happen. Thing about that is, I still want to have a regular value in there so that screen readers and people surfing without CSS at all can still figure out what the input says. I've usually encountered this issue on on fast-paced, get-em-out-the-door projects, so I've never had time to actually sit down and think about a solution. I've never actually come up with a solution that I liked for this. Negative text indent doesn't work, so I've always done random hacks to get it to work correctly. Recently I achieved it by shrinking it way down and coloring it the same size as the background.

Painful.

Today, for whatever reason, I took it one step further and set font-size:0;, hit F12 and saw, *GASP*, it worked. Browsercam verifies that it works for the above named browsers.

Here's a sample:

And here's the code for the above #go button.

#go {
	background: url(images/go.jpg);
	height: 25px;
	width: 41px;
	font-size: 0px;
        border:0;
}

This is one of those things that seems so obvious in hindsight. I just never thought to do it before today. hrm.

*Safari 1.2 and 2.0 ignore both the font-size AND the background image.
**Opera displays something like 6pt type.