Skip to: Navigation | Content | Sidebar | Footer

Full Archives

Too Far

March 31

You know the dogma has gone too far when...

Here's a code sample from someone who obviously misunderstands the fact that "it's okay to use tables for tabular data", and probably spent more time than was necessary coming up with the CSS to make this work:

<h3>My Schedule</h3>
<ul class="pseudotable">
     <span class="event">Event #1</span>
     <span class="location">(location)>/span>
     <strong>May 15, 2005</strong>
     <span class="event">Event #2</span>
     <span class="location">(location)</span>
     <strong>May 16, 2005</strong>

Too bad that someone was me. The CSS that made this work ended up looking like this:

.pseudotable li {
  padding-left: 66%;
  position: relative;
.pseudotable strong {
  width: 33%;
  display: block;
.pseudotable .event {
  display: block;
  width: 29%;
  position: absolute;
  left: 0;
.pseudotable .location {
  display: block;
  width: 53px;
  position: absolute;
  left: 33%;

A misguided waste of time, for sure. You'd think the class name "pseudotable" should have tipped me off that maybe I was going about it the wrong way... and I coded this only last month, too. Here's the much more sane data table I ended up with:

<h3>My Schedule</h3>
<table cellspacing="0">
     <td class="event">Event #1</td>
     <td class="location">(location)</td>
     <td><strong>May 15, 2005</strong></td>
     <td class="event">Event #2</td>
     <td class="location">(location)</td>
     <td><strong>May 16, 2005</strong></td>

About the same weight, markup-wise, but compare the resulting CSS:

table {
  border: none;
td {
  width: 33%;
td.location {
  width: 53px;

That's a few hours of my life I'll never see back. Gosh.

Update: as a few commenters have rightly pointed out, there's more that can and should be done with a data table like this one. You could go as far as something like the following if you're so inclined:

<h3>My Schedule</h3>
<table cellspacing="0" summary="Upcoming Events, their locations, and dates.">
     <th scope="col" class="event">Events</td>
     <th scope="col" class="location">Locations</td>
     <th scope="col" class="event">Dates</td>
     <td class="event">Event #1</td>
     <td class="location">(location)</td>
     <td><strong>May 15, 2005</strong></td>
     <td class="event">Event #2</td>
     <td class="location">(location)</td>
     <td><strong>May 16, 2005</strong></td>

And there are even more elements and attributes to explore, like col, colgroup, and caption.

Permalink › | 52 comments

Image Replacement. Again.

March 30

Since there are still lingering questions about image replacement, this is the state of CSS image replacement in early 2005.

In the past few weeks, I've had some conversations about image replacement techniques. A quick recap for those who may not be familiar: image replacement is the concept of taking a structural, text-based HTML element (an h1, for example) and substituting it with an image. Why do it? Better typography and more visual interest, as well as flexibility in the CSS to later change the images themselves. Why not do it? It's hackish, somewhat inaccessible, and the old 'non-web' argument applies to any instance where you're locking text up in an image.

Of course, a few years ago I was keeping a tally of all the various ways of doing it. And we all know about sIFR. So I don't have to summarize those here.

One of the more popular questions I've been answering regards which method I use. Since Douglas Bowman officially deprecated the original FIR (Fahrner Image Replacement) that he popularized a few years ago, it's been necessary to choose from the list of other techniques, of which there are many. Heck, a brand new technique just showed up the other day, even.

So which do I use? I'm still not going to say just yet. Let's talk about a few more things that influence the decision first.

Classic FIR had three problems: an extra span in the markup, some screenreaders would ignore the hidden text, and in a scenario where a user had CSS enabled, but for some reason had turned off images, they wouldn't see anything. As of this writing, all problems have been addressed in one technique or another, but there is still a decision to make between trade-offs, since no one technique does it all.

The Mike Rundle/Phark method and the Gilder/Levin method demonstrate this trade-off nicely. One elegantly and simply hides the text in an accessible way to everyone except those with images off and CSS on, the other solves that particular problem with plenty of ugly code.

So the temptation is to discount the images off/CSS on scenario as unlikely, and use the elegant solution. Except that it turns out there are quite a few instances where this scenario may be more widespread than it first appears. Dial-up users, of which well over half of all web users currently still are, have limited bandwidth. They may end up turning off images in their browser for the sake of quicker load times. Or even if they don't, all dial-up users are still at least temporarily affected by this problem during page load, and no text equivalent for the images can be annoying, to say the least.

Finally, it's possible that the user hasn't made the choice at all, but it's occurring anyway. Recently I was asked about a Windows accessibility setting that throws the entire OS into high contrast mode. A peculiar side effect was that in Internet Explorer, all background images were ignored while in this mode (although foreground images loaded fine.) And there are no doubt scenarios I'm not accounting for here, so yes it's likely that the images off/CSS on situation is affecting users.

And targeting no one particular method, what about Google? Let's face it, when you're able to place text in a page that won't be displayed to the viewer, through substitution or some other method, the potential for SEO spam is ripe. The same holds true across all image replacement techniques, sIFR, and hey, even alt text for that matter. We have to be prepared for the worst, but the chances of Google blocking legitimate sites that have been using these techniques for years—simply to punish SEO spammers—is slim. It's probable that they would block the elements themselves (instead of the entire page/site), or even more likely, that they would treat the hidden text the same as they would any other textual content, and filter it on its merits.

In any case, the methods we have are imperfect. The ideal fix is CSS3's generated content module, which allows something like this:

h1 {
  content: url(image.gif);

The W3C CSS working group is aware of the accessibility issues of current FIR variations, and last time I checked in they had properly accounted for fallbacks in situations like the images off/CSS on scenario.

But until such time as CSS3 is supported across enough browsers that we can use this method, we're stuck picking and choosing between imperfect methods. And getting around the basic accessibility problems, there are even more issues. Rundle/Phark breaks in Win/IE5 in certain situations, while Gilder/Levin basically disallows the use of transparent GIFs due to the fact that the text will peek through the transparent spots.

Aware of its shortcomings, I continue using the Rundle/Phark method. I don't necessarily think it's the best choice for all users, and I'd happily ditch it for a more robust method like the CSS3 generated content solution. Why not Gilder/Levin? To get it truly cross-browser compatible, you have to do this. Again, it's a matter of deciding between trade-offs.

Permalink › | 47 comments

Form Elements and ids

March 29

Finding a balance between label association, validation, and automatic form generation.

So we're all aware by now that the id attribute is supposed to occur exactly once on a page. You're not allowed to use more than a single instance of any given id; for that, you'd turn to a class. Multiple classes are no problem, but multiple ids are.

Now if you've done you're homework and you know how to properly apply a label, you've probably run into this:

Attribute definitions
for = idref [CS]

This attribute explicitly associates the label being defined with another control. When present, the value of this attribute must be the same as the value of the id attribute of some other control in the same document. When absent, the label being defined is associated with the element's contents.

This is from the spec and it basically means you should be specifying in your markup that any given label is attached to a specific form element using the for attribute.

There are a few implications from this that are just a little inconvenient. Most importantly, if you're doing it right, this means that every single input box on a page must have a unique id, for the sake of its label. If you've ever had a page that required multiple copies of the same or similar forms, you'll most likely have run into the validation issues this creates.

The natural tendency is simply to duplicate the forms. If you're running script which is automating the form creation, you'll have had to do something like echo "<input type=\"text\" id=\"" . $formControl . $i . "\" />";—where $i is an incrementing value in the loop. If not, you'd have to do it by hand.

Another issue this raises is that label elements may be associated with exactly one form control on each page. For cases where more than one element should share a common label, the only options are to over-do the labeling and selectively display: none; the undesired labels, or you could also turn to the fieldset and legend combo... neither of which are particularly graceful in their ability to be styled, based on current browser support.

Now, both problems feel more like a design problem than a code problem—in the first case, the benefits of having duplicates of the same form on a page are questionable from a user interaction perspective, and in the second case the desire to not explicitly label a form control seems somewhat user-unfriendly. But let's recognize that in certain cases, the best choice is an atypical operation. So what then? Extra work for you, that's what.

Luckily though, the first problem has a fix which is old news, but I've only recently discovered simply by reading the spec a little more thoroughly. Implicit association means that instead of this:

<label for="myName">Your Name:</label>
<input type="text" id="myName" />

You can simply do this:

<label>Your Name: <input type="text" /></label>

This solves the first issue nicely, but doesn't do anything about the second—again according to the spec, you're only allowed to include a single form element within the label. But at least it's a start.

Permalink › | 40 comments

Mobile Standards

March 26

A different kind of standard than what you might expect, and the joys of lock-in.

Two competing technologies vie for the domination of a fragmented market—sound familiar? It should, it has been a typical story of just about every emerging technology, be it PC or Mac, Blu-Ray or HD-DVD, or the one I was recently reminded of during my run-in with the mobile phone industry, CDMA and GSM.

After having a chance to tinker with various Treos at last week's SXSW conference, I decided I needed one. It started innocently enough; the first step was to get in touch with my existing service provider (Telus) and see what they could do for me. As it happens, the only PDA-style phones they offer are Blackberry models and a PocketPC variant. They mentioned they should be able to support it if I could find one, but no, they don't provide any means of getting my hands on a non-supported device. Any next steps were solely up to me.

Now, the thing to keep in mind here is that 3 year service contracts are standard in Canada. Advertising almost exclusively revolves around this three year target. There's your first sign of lock-in. You can get one- or two-year terms, but they make it worth your while not to. After the completion of my last three-year contract last summer, and given that I'd been with them since 2000, I didn't think too hard before renewing to replace my old hardware. Now I'm stuck with this provider until 2007, for better or for worse.

After putting my name on their official request list for Treo support, I went to see what I could find on my own. Canada does not have the number portability law that other countries do; though it's apparently up for legislation, nothing has passed yet. If you buy a phone, it's forever tied to the company you bought it from. Yet more lock-in.

The first thing to check was whether anyone local sells the phone. Yes, a few providers carry them. Next: are they portable? Yes, as it turns out—there is a hack floating around to unlock your Treo. Excellent. In fact, Treo manufacturer PalmOne sells an unlocked version right off their site for about a $70 premium, so score one for a bit of Googling. The final step was just to call my provider and make sure I could get my hands on a SIM card that would allow me to connect the unlocked phone to their network, and then I'd be home free.

SIM cards are small chips that you can swap between phones. When travelling outside of your normal service area (say, to a different country) you can simply walk into a local service provider and buy a temporary SIM card for the sake of a local number and lower rates. Sounds great? It is, except if you don't have the ability to use them.

CDMA, the standard that my local provider supports, doesn't make use of SIM cards. They're only available on GSM networks. So any options of switching a phone between a network are completely out of the hands of the consumer; on a CDMA network, you're at the mercy of the phone company.

Well, guess which unlocked version PalmOne sells? If you guessed GSM, come on down, I've got a brand new toaster oven for you. Naturally, the version of the phone that I can't actually do anything with is the one they happen to sell. Their advice for getting my hands on an unlocked CDMA phone was to get in touch with a local retailer; for some unspecified reason, they wouldn't be able to provide me with one.

There's a single retailer in town that carries CDMA-enabled Treos, and it is not the one to which I'm currently indentured. Guess how happy they were to unlock a phone for me? Another toaster oven if your answer was 'not at all'. Long story short, it would be a chilly day on the Nile before they'd sell me a phone without a contract.

Keep in mind through all this that I've told each company I've dealt with that I'm prepared to pay full price for the phone. I realize the industry works on subsidy in order to sell contracts, so I was willing to pay the extra in order to avoid signing another one. Which equates to extra cash in the pocket for whoever actually decides to sell me the phone, cash they otherwise would not be receiving since I have no intention of changing my service provider. But policy appears to be policy, and so I'm completely out of luck.

What I haven't learned from this is that service contracts suck—that I've known all along. What I have learned is that GSM appears to be the wisest choice of cellular networks for the consumer. Laws or no, there appears to be more inherent portability—at the very least, you can resort to hacking your way around anti-competitive practices thanks to the SIM card option. I have no such option on a CDMA network. There are other factors to keep in mind when choosing a network, but at least in this one aspect, GSM appears to be the superior choice.

Permalink › | 27 comments

Triple A

March 22

The Italian web developer community is abuzz—the css Zen Garden is not AAA compliant!

Since the beginning, the css Zen Garden has featured five links at the bottom of the site (or elsewhere, depending on which design was used to view it). Two of those links—508 and AAA—deal with accessibility, and lead to the results of validating of the site with Bobby.

Pages 36 and 37 of the Zen of CSS Design talk about this issue:

After the markup was written, a quick check from Bobby confirmed that it passed most major accessibility checkpoints. A few quick changes were needed before launch to fix the few glitches that Bobby noticed. A link labeled "AAA" was added to the footer of the Zen Garden to signify that accessibility had been taken care of.

Or had it? It turns out the Bobby is not final word when it comes to accessibility. If you familiarize yourself with the Web Content Accessibility Guidelines published by the W3C (see "Better Accessibility" earlier in this chapter) you'll soon realize there are guidelines that Bobby simply can't check. Checkpoint 2.1, for example, states that all information conveyed through color needs to be available to the viewer without color as well — software like Bobby has no way of distinguishing this, especially if the information and color are embedded in an image.

In fact, if you do some digging on the Bobby site, you'll also find this disclaimer:

Accessibility is ultimately a human endeavor. It is determined by whether or not a diverse group of people with a variety of abilities and disabilities can access information efficiently. Bobby is just one step in helping to make web pages more accessible, but cannot guarantee total accessibility.

So the Zen Garden's HTML theoretically passed all accessibility checkpoints related to markup but there are further checkpoints that go beyond HTML. A few of them even apply to CSS, and it became evident over time that some designs weren't taking these into account. And when you consider the accessibility implications of Fahrner Image Replacement... it's easy to see how the CSS can quickly cause problems that no automated checker can diagnose.

The lesson learned is that automated tools like Bobby may serve as a useful starting point for building accessible Web sites, but WCAG provides many more checkpoints that are equally as important, which it cannot check for you.

By way of explanation, more than excuse, what we find is that markup I wrote two years ago—with, I have no problem admitting, less understanding than I have today—now seems imperfect in today's context. We know more about accessibility, we know why the link is problematic, and we know that ultimately, true AAA-level accessibility is often unattainable.

So in today's context, as the Italians who have emailed me pointed out, the links aren't working. In many cases, css Zen Garden designs break AAA, AA, and who knows, maybe even A (depending on your level of interpretation.) Then again, some do not. But if it's all or nothing, why do the links persist?

Two reasons. First, as I've also detailed in the book, the point of being able to change structural items of the markup has long passed. Content changes (ie. anything not in angular brackets) are still somewhat possible, as is evidenced by the fact that I seem to have gotten away with adding a line announcing the existence of the book. Structural changes (ie. anything between < and >) are not.

There are 150+ official designs, and close to four hundred others (the latter hosted on servers not controlled by me.) Changing the structure potentially destroys some or many of these. This is a deal-breaker. We're stuck with having five links in that footer, for better or for worse.

The second reason is more philosophical. The links signify that efforts were made to pass accessibility tests. They call attention to the fact that the design work which is added to the site remains accessible, albeit in varying degrees. In essence, they are a wake-up call to those who might otherwise be completely unaware that accessibility and good design can co-exist. A simple link to a validator says more than a full paragraph could, and if not for some on-site recognition, then this point would likely be missed very often. Signifying that accessibility was intended is a major point of the site.

So the problem appears to me as one of simple nomenclature. How do we title these links? If AAA is not being met, would AA or simply A suffice? If there were a way to succinctly say that "this site was built with accessibility in mind; although the odd design here or there may not meet every requirement, overall it does pretty well" and cram it into 8 characters or less, I'd be happy to talk about it. So far I haven't come up with anything myself, perhaps someone else will.

Ultimately, this discussion is frustrating, not a new one, and feels largely irrelevant. AAA is a stale guideline that has been in need of a massive overhaul for years. True accessibility requires much more education and thought than what's found in the 14 guidelines of WCAG 1.0. Getting wrapped up in the specifics of what precisely constitutes AAA (or Triple-A if you insist) ignores the larger issue that the guidelines themselves need work. Let's be honest, anyone knowledgeable enough to take part in this particular conversation should be aware of that.

But that's an aside, not a shifting of the blame. If this is perceived as a genuine problem on this particular site, tell me what should be done. You now know my dilemma, so what's the fix?

And as a polite reminder to those members of the Italian web design community previously referenced: context is everything. During the recent SxSW conference (which was mentioned in the sidebar on the same contact form used to reach me) email response time dropped considerably. Add the second conference I attended less than a week afterward (also mentioned), and I'm sure how you'll understand why replying hasn't been a priority. So while I can't help but admire the devotion, the daily emails can be called off now. Much appreciated.

Permalink › | 55 comments

SxSW Panel Notes

March 17

A few follow-ups from the panels I was involved in at SxSW 2005.

Another great year of South by Southwest has come and gone. More great people, more great conversations, and more great barbecue.

"More Hi-Fi Design with CSS" was the first panel I was involved with. Christopher Schmitt, Molly Holzschlag, Dan Cederholm, Douglas Bowman and myself spent an hour talking about the sort of things you'd expect us to talk about. (It has been documented elsewhere, I should add.) Chris kicked the panel off with the introductions, and then turned it over to the rest of us.

Molly was a new addition to last year's similar lineup, and started things nicely with a foundation talk about the basics of structure and semantics, and how that sets the stage for our Hi Fi stylin'.

Dan continued with a look at what he calls "Bulletproof CSS", which consists of making sure your design continues to work under circumstances like missing images, missing CSS, and different font sizes.

My own portion of the presentation was a look at how CSS fits into the typical designer's workflow. Things like the disparity between code and GUI, browser bugs, and a few final pointers for design concepts to further study.

Doug then examined the technique he never got around to presenting at last year's SxSW, and concluded with a story from the Wired News redesign feedback a few years ago.

What was particularly interesting about the panel this year was what happened despite the lack of collaboration ahead of time. With only basic outlines of what each other was planning on discussing, there was some nice synergy happening between sub-points in all of our presentations.

Now, for what those of you who were there are likely hoping I'd get to—the slides I used. I need to load this link with a couple of disclaimers. The presentation was built for a controlled environment, so instead of tailoring it for the general web audience, it is much more effective within that controlled environment. The download is large because the files are large. It may be slow because it's meant to run on my computer. It won't render in anything but top-notch browsers. It's meant to be contained within a 1024x768 window, no shorter or wider. It's too slow in Firefox on a Powerbook, it had to be presented in Safari. (This may not hold true for a Pentium 4, but I have no way of knowing).

So, with that out of the way, here it is. There's also a 1.3MB ZIP file of the entire thing. Please link to this article, instead of directly to either the slideshow or the ZIP file—it's important to have the context of the disclaimers before viewing in any old web browser. (not to mention the bandwidth issue).

To move back and forth between slides, use Accesskeys z and x. Or, move the mouse down toward the bottom of the center of the window for a pop-up menu. I'll let you figure out what's going on there, the source tells all. I just want to send a big thanks to Jeremy Keith for building the initial script that I modified to pull this one together.

The second panel, "Web Design 2010", was more of a group conversation than a presentation. John Allsopp played the role of power moderator (eschewing the puny on-stage mics for a wireless that let him get down and gesticulate at the same level as the audience, demonstrating what Doug and Joe and I knew from our experience at WE04: he's one of the most entertaining speakers in the industry). The rest of the panel consisted of myself, Jon Hicks, Eris Free, and the omnipresent Mr. Bowman.

We tackled six questions, discussing amongst ourselves and the audience (and disagreeing with each other quite often too). Our pre-discussion for this panel was largely conducted on a WordPress weblog I set up for the purpose, which was opened to the audience for questions and is now open to everyone for reading and continued discussion. (The URI is now permanent, so link away).

In all, the two panels I participated in were just the tiniest slice of a fraction of the entire event. It was that good. Maybe I'll get a chance to write up the rest of the event. Maybe.

Permalink › | 13 comments


March 4

mod_rewriting your way to fame, fortune... and frustration.

A new feature I've added to the Zen Garden is a far nicer URI schema. I've moved from this:

to this:

Nice, right? Except it's not quite perfect yet.

For the sake of easy, short URIs for the book, I looked into mod_rewrite at the time, but never quite got it working. So I hacked this all together manually by adding redirects for each of the designs to an index.php file in their respective directories. Ugly, unmaintainable, and more work than necessary, but it worked.

Then Mathias Bynens asked if the new links could be applied to all designs. And since I had originally planned for this anyway, I went further into the mod_rewrite manual, which is completely incomprehensible to my puny brain, and managed to come up with something anyway. The affirmation from an anonymous helper monkey kept me at it, and finally I came up with this monstrosity:

RewriteEngine On
RewriteRule ^([0-9]{3,})(/?)(/&page=([0-9]*))?$

In plain English... oh geez, I don't even want to try. There's still a query string variable in there to indicate the current page of designs; I'd love to go with post data for that, but there's no way to retrofit a form in the ZG markup at this point without really breaking things. The important thing is, the variable is passed as I'd expect, which is good.

What's not so good is that while these three possible URI scenarios are covered:

This one is not:

Note the lack of a trailing slash. Follow the link and see what happens to the URI—ugh. I'm not sure how to fix that, and so I turn to you dear reader. Tell me how.

I already tried an initial rule before the previous one to add the slash back in, but this only netted me server errors:

RewriteRule ^([0-9]{3,})(/?)$	/$1/

So, what now? First answer that works gets a free copy of the book.

Update: Got it, thanks to Roger Johansson. See the comments for details.

Permalink › | 58 comments


March 3

A new solution just popped up that enables clearing of floats without the markup hacks of old. Great! Except there's a caveat: scrollbars.

First reported on this SitePoint blog entry, later followed up with a description and some test cases by Anne van Kesteren, a new method of clearing floats involves using overflow: auto; to expand the parent and contain all children, thus forcing it to contain even floated elements within.

While overflow: auto is working for us in this case when it comes to vertical overflow, unfortunately it also applies to horizontal overflow as well. Therefore, all child elements must be smaller than or equal to the width of the parent, otherwise ugliness occurs.

Some examples are in order. First, here's our basic setup:

We have two pargraphs side by side, contained within a parent div. We want the border of the div to surround both paragraphs; because they're floated, though, the border of the parent doesn't surround either and bunches up at the top as a solid grey bar.

There are now two methods to force the parent to expand and include the children; traditionally, you could have applied a float: left; to the parent and found some way to work around the resulting float. Or now with the new method, you don't have to worry about any re-positioning of the parent after all, because the overflow property doesn't affect it the way a float would:

(Note that due to positioning in these examples, the floated parent layout issues aren't apparent; it would take extra complexity to demonstrate that, but if you're at all familiar with floats it shouldn't be too much of a stretch to see how the floated parent would be problematic.)

What happens, though, if the child element is simply too large for the parent? This may be triggered in environments where dynamic content might see the addition of an image with particularly large dimensions, or by something silly like the italicized text problem in Win/IE.

  • Example 4float parent with extra-wide child.
  • Example 5overflow parent with extra-wide child.

Ah. And so we reach the crux of the matter. Neither solution is perfect, they both have the same problem with horizontal overflow. Each handles it in a different way. The overflow method doesn't require extra positioning aerobics to adapt to the position of a floated parent, but its method of handling overflow may be more problematic than the float method.

It's always great to have another tool in the arsenal, but remember that the Achilles' heel of this one is the horizontal scrollbars you may experience in your layout.

Permalink › | 28 comments