Foo Hack » Code Beauty Isaac Schlueter on Web Development Tue, 03 Nov 2015 06:34:16 +0000 en CSS vs Tables: You’re Doing It Wrong Tue, 03 Feb 2009 07:40:22 +0000 Isaac ...Read More]]> Definitions first.


A specified set of columns and rows with cells that automatically and fairly smartly expand to fit their contents; cells can span rows or columns; the table as a whole can be treated as one block, and cells can contain tables. A table is a metaphor for visually laying out 2-dimensional content.


cascading style sheets; not floating divs, not any specific markup, but just the concept of the visual display of markup specified by a series of rules that are kept separate from the markup they operate on, generally in an external linked file or a style tag in the head of the document.

Talking Past Each Other

CSS is (for various reasons cited elsewhere ad nauseam), in most cases, the more optimal technological approach. That’s not to say that the existing state of the CSS language is perfect. In fact, even the most vocal CSS advocates regularly assert that there are deep problems with the existing spec and browser support.

Tables are (for various reasons cited elsewhere ad nauseam), in most cases, a more optimal metaphor than any of its rivals. There’s nothing inherently wonderful about the tags themselves. In fact, even the most vocal table advocates regularly assert that the markup is ugly.

Therein lies the crux of the problem. CSS is a great technological approach, and tables are a great metaphor. The question then usually becomes, Should I mark up my content using <div> tags or <table> tags?, which really means, Is the separation of style from content more or less important than using the optimal layout metaphor? The debate goes a little like this:


This layout metaphor is better, so you should use these tags. All you idealists are unrealistic! (Also, if you think markup matters, you believe in fairies. It so doesn’t!)


Metaphor shmetaphor! You don’t care about the sanctity of data or code quality. Think of the maintenance! (Also, if you can’t do it with divs, you’re stupid. It’s so easy!)

The Right Answer, it would seem, is to use the table metaphor with the CSS technology. In the ideal world, you’d always mark up your content using the tags that would communicate your meaning most clearly to your intended user agents. Then you’d tell user agents how to treat those tags visually. To describe this visual display, you should be able to use the table metaphor, or the float metaphor, or absolute and relative positioning, or anything else, but that should not be done by your markup.

Getting Real

In the real world, it’s not so nice. The CSS specification has a set of display values designed to mimic the table tags, but they aren’t well supported, and anyway, it’s an imperfect imitation of a hack that was not really intended to be used the way we all ended up using it.

In other words, CSS is not an ideal example of what CSS aims at, and the table/tr/td tags are not an ideal implementation of the table/grid metaphor. CSS tables, though they are clever and in some cases quite useful, take it from bad to worse.

The state of the CSS art is not at a point where you can realistically expect to make any significant stylistic changes to your pages without altering the markup. If you need to move the navigation bar from the right to the left, or re-skin the page with dropshadows instead of rounded corners, or convert your gradients from 2-tone to 3-tone, or make your boxes vertically centered instead of top-aligned, you’re probably going to have to change your markup, at least a little.

In theory, it’s possible. I know a handful of my colleagues will vehemently disagree and point at countless approaches to enable virtually any kind of reskinning using only CSS changes. (I’ve used Leslie Sommer’s CSS Mojo technique to great success in the past; we used it for pretty much everything on Yahoo! Buzz.) But let me tell you, from years of experience building production sites with CSS, most of the time, in reality it just doesn’t work that way.

And why should it? What kind of crazy lunatic writes all their HTML by hand in text files, anyhow? Clearly you have some kind of back-end engine spitting it out from templates, so you just change the template, and voilà!, the markup is changed everywhere.

A Very Blue Bike Shed

Working at Yahoo, I’ve met some webdevs with truly incredible CSS ability, who crank out live code under real deadlines to exacting standards. They use CSS, and not tables, and they Get Shit Done. There are a lot of them, more than I can list here, but Nate Koechley, Matt Sweeney, Hedger Wang, and Leslie Sommer all deserve a special mention. I came to Yahoo knowing CSS pretty well, but I became an expert largely as a result of working in such a highly skilled community of developers.

Also due to my time at Yahoo, I’ve seen some absolutely crazy debates about markup and coding standards on the devel-frontend mailing list. I mean, you think this little flare-up in the blogosphere is anything? You got no idea, buddy. Seriously. And these are coworkers who (for the most part) really like and respect one another.

You wanna know a secret? It makes no difference.

Language is as language does. If everyone uses the <table> tag for markup, guess what happens: <table> is now a semantically meaningless (or at least, semantically vague) tag, and any user agents that might care about navigating tabular data have to deal with that fact. It becomes just another <div>, for all intents and purposes, but a little less flexible, and with a default styling that makes it handy for layout.

The passion for the rants comes from the fact that it is meaningless! Of course it’s a fertile ground for bikeshedism!

That’s right: It doesn’t matter.

Use whatever tags work for you. I don’t care. You’ll still be a good person.

I can tell you from experience that a deep knowledge of CSS is essential for serious front-end development. (Most so-called DHTML is actually just manipulating CSS with Javascript, and the Javascript is pretty light.) CSS can do some things that table tags can’t, so you ought to learn it. The reverse is also true, so you should know how to use tables, too.

Write code that you can maintain, that is flexible enough to let you change it without sacrificing the stability of your product. Test it in the user agents that you expect to support. Stop debating the color of this bikeshed.

If there’s ever a good reason to go back and change your tables to divs, or vice versa, you can do that. Hell, plan for that, because whether you use CSS for layout or not, you’re going to need to touch your markup sometimes. It is much much harder to build a product people want than it is to build a product that works in Browser X.

Belorussian translation provided by fatcow

The Haiku OOO Email Mon, 03 Nov 2008 17:00:35 +0000 Isaac ...Read More]]> When I started at Yahoo on the Games team, there was a custom that resonated deeply with me, which was started by Dean Yu.

All “work from home” emails or “out of office” emails had to be sent in the form of a haiku. This rule was not enforced, but it’s the kind of thing that one person does, and then a few others pick up. Once someone starts doing it, they rarely stop.

Here are some examples:

Sick on an airplane.
Second carry-on: virus.
Infect passengers.
Sadly, not writing itself.
Avoid distractions.
Roommate needs his car.
Internet works in new place.
May as well use it!
Nothing in iCal:
Must take advantage of this.
Work in pajamas.
Still not feeling well
Resting and working from home
Please ping or call me
Have suffered relapse
To this weekend's brief illness
So I work from home
Sneezing mightily
Wish not to infect colleagues
Thus working from home

A couplet for my recent vacation:

Been a busy year.
No vacations since ’06
Burnt out: Do not want.

Visit with old friends.
New England trees in autumn.

Having worked on a bunch of teams, I’ve taken this custom with me as much as possible, to the Brand Universe team, and the Buzz team, and most recently the YAP team. There’s no proselytizing involved. I just send a haiku I’m working from home. Some people think it’s fun, and play a round of “speaking in poetry” via email. Some people adopt the custom, and it sticks. Others, for whatever reason, never get involved.

I’m not sure why some seem to instinctively carry it on, and others instead prefer just the subject of “wfh” or “ooo” with no message body. I’ve been told that there are other teams at Yahoo and elsewhere that this custom has spread. In Games, it’s all but gone, now that Dean has moved on.

Like the Twitter of the Edo Period, haiku (then called haikai) used terse imagery to elevate the normal and mundane to the deep and meaningful.

Most people learn in grade school that a haiku is 3 lines, with syllables numbering 5/7/5. While this is the typical standard, it’s not just about fitting into the right number of syllables.

The goal of haiku is to find powerful expression in a small intense dose, to elicit an “AH HA!” experience by virtue of succinctly expressing meaning via simple language and powerful imagery.

Limitation—whether 5/7/5 or 140 characters—is part of the equation. Because the limits are so draconian, the writer is forced to be clear. Squeezing ideas into uncomfortably small packages shaves off the excess. When the excess is removed, enlightenment remains.

Like Twitter, haiku can be terribly inane and useless. That is bad haiku. Truth be told, most WFH emails basically are expressing a single sentiment, and the form adds little to the composition. It’s just fun.

Good programming is like good poetry. The best programmers I’ve known are obsessively minimalist in their code, and do tremendously powerful things with simple logic and short functions. The same can be said for all levels of design: a simple business model, a straightforward user flow, a clean visual treatment.

Less is more. Like the kendō master who practices calligraphy, or the actor who studies yoga, the pursuit of excellence in one area can balance and ready the mind for one’s primary activity.

The next time you have to send an email to your team telling them that you’ll be out of the office for some reason, put it in the form of a haiku. Don’t explain it or call attention to it. It will be your gift. Watch how it is received.

In case you’ve never hit them organically: 404 401 403 410

Going Fast, Frankenstein, and Refactoring Mon, 21 Jan 2008 17:00:48 +0000 Isaac already planning a fairly major refactoring effort to take care of a lot of code rot that has crept into the designs. That's right. We haven't released anything, and there's already enough bloat to justify spending at least 2 weeks cleaning it up. ...Read More]]> Very soon now, the project that has consumed my days for the last 6 months will go into public beta. It’s too early to pop the champagne, and that’s not what this post is about. However, the newness of this project is worth pointing out for the following reason: We’re already planning a fairly major refactoring effort to take care of a lot of code rot that has crept into the designs.

That’s right. We haven’t released anything, and there’s already enough bloat to justify spending at least 2 weeks cleaning it up.

Of course, due to the pressures of market, and the morale effects of delaying the release, we’re buttoning up what we have now as much as possible, and planning to work on the refactor once the beta is out there. It may actually help a lot, since the gigantic firehose of traffic that Yahoo! points at sites has a way of helping even the most egotistical of developers realize that their clever baby needs some serious surgery.

This post is going somewhere, I swear, but I can already tell it’s going to take me a while to get there. Go get some coffee and a snack and come back. I’ll wait.

Build Fast

In my opinion, the core of good software development methodology comes down to two basic questions that should be asked daily:

  1. What portion of your time is spent focused on the task of creating software?
    (That includes planning, discussion, and thinking as well as coding, provided that these non-coding activities are focused and aimed at creating software.)
  2. Does it work today?
    (If you don’t know, then you are full of Fail. Get on that right away.)

I call this the Go Fast method. The goal is to efficiently create software with minimum long-term cost and maximum long-term benefit, without driving away your best talent. (Have I got the attention of the business and product people in the audience? Good. Please stay for the rest of the show.)

I know that someone out there is bound to point out the obvious parallels between my “go fast” methodology and Agile, and maybe they’re right. To the extent that Agile accepts these premises as important, it is correct. But I’m claiming that everything else stands or falls based on how it affects these questions. Stand-ups, planning meetings, org charts, IDEs, frameworks; they’re all only as good as their effect on the principles of speed and stability in development.

If you’re developing software properly, you should be creating software that does something as soon as possible, and keep it up as much of the time as you can. Until there’s something to look at, you’re just spinning your wheels. Nowhere is this more true than on the web. Photoshop comps don’t break in different browsers. Product presentation decks don’t “feel klunky” when pieces load out of order. Grand visions promise to solve all your problems and make you biscuits for breakfast, but they don’t deliver.

You make software for a living? So make software, already. You wanna build a website? What’s stopping you? You don’t have designs yet? Build the parts that you do have. Always be releasing, even if your actual release date is months away.

Build the core, and grow the other pieces up around it. Every minute spent waiting, instead of actually building something, is worse than wasted. When you live in the code day by day, it becomes a part of you. You learn how the pieces work, and the knowledge is automatic. When you get too far from it, it becomes foreign, like driving a car for the first time.

The agilistas call this “shippable code.” In my opinion, that’s a horrible term. The vast majority of code that I’ve seen released into the wild was not even close to what I’d call “shippable,” but it got shipped just the same. Most of the time, the prototypes leading up to the release were significantly worse. Some agilistas are quick to point out that “shippable” doesn’t always really mean “that you would actually ship it.” Sorry, but drivable means that you can drive it, and drinkable means that you can drink it, and flyable means that you can fly it, so if “shippable” doesn’t mean “you can ship it,” then they picked a bad term.

I suspect the ambiguity is intentional on some level. I think the claim that “Agile makes software faster” is a myth. Agile methodologies, used in moderation by a well-balanced team of dedicated and talented individuals, do tend to result in higher quality software, greater management visibility, and a happier bunch of people than any alternative, but that means that the overall development time can be significantly longer. And if you’re not on a well-balanced team of dedicated and talented individuals, then no methodology is going to save that sinking ship, so dust off the CV and bail out ASAP. But I digress, and besides, you already know that I think Agile sucks.

I prefer to call it a running prototype, or an integration environment, or anything else that’s more, well, accurate. “Shippable code” tells overeager managers that they can just press “stop” at any point and ship what they’ve got. Nice dream land, hot shot, but it doesn’t actually work quite like that. Nevertheless, a good integration development environment, where everyone’s code gets placed and which is subjected to regular updates and testing—that’s important, almost as important as CVS and a decent build script, and for a lot of the same reasons. If the team’s code isn’t conversing regularly, then the team may as well not be, either. The best way to prevent blockages is to prevent assumptions; the best way to prevent assumptions is to check them every single day. So: Does it work today?

Completion feels good. Getting something that works feels good. That’s why we got into this business. Because, despite all the pain and frustration and work that goes into developing software, The High here is about as good as it gets.

You don’t get that waiting. You don’t get that talking. You get that when you are immersed in building something.

From a team dynamic perspective, I can’t even find words to express how it makes people gel when we each do our little pieces, and plug them in, and see a site come up with data and styles and behavior and images and everything. It’s a pretty marvelous event that makes everyone even more eager to get to work. If you’re a web developer, don’t wait for your designer or back-end engineer to give you what you need. Make an unstyled page with dummy data, if you have to, but make something on day 1 if possible. Then make a list of what you need. When everyone can see their effect on the product, it’s amazing how fast they tend to deliver.

Going fast and pushing to milestones also forces everyone on the team to prioritize. There may be plenty of features that might be nice to implement, but if speed is a priority, then it forces you all to work on the things that really need to be implemented. By raising red flags whenever something doesn’t work, the whole project stays in sync most of the time, and assumptions never get too far out of whack. But, of course, that’s not the whole story.

Gene Wilder as Victor FrankensteinSoftware development is a lot like building Frankenstien’s monster. You start out with a pile of useless ugly pieces, and try to turn it into something beautiful. Along the way, it’s a monstrosity, and tends to get uglier as you tack new bits onto it. Then it kills people.

In Mary Shelly’s classic, everyone Victor loves is killed by the eloquent and sensitive creature, who was turned evil by his creator’s neglect and hatred. If software could walk and talk, how many developers would still be alive today?

Slow Down

Don’t build Frankenstein’s monster, or at least, don’t figure you’re “mostly done” once it walks and talks, as the strict waterfall process proposes. Going fast is important, and necessary. You can’t fix pure ideas very easily, because it’s hard to see what’s wrong with them. Write the code. But know that it’s going to have to be rewritten, possibly several times. Plan for it, and keep it in the back of your mind.

The hazard of moving quickly is that we tend to go with the easy choice, rather than the good choice. Adding one more method onto the class I’ve already got is easier than creating a whole new class; nevermind that it doesn’t really “fit” with what this type of object is supposed to be doing. Do that once, and it’s probably a lot simpler and clearer than any alternative. Do that 50 times, and you end up with a theological problem, or something else equally pungent.

This will happen. Every time. If you don’t have some downright embarrassing shit-tastic WTF-worthy code lurking in your project—I mean, the kind of thing where you see a bug report go to your coworker, and you say to him, Oh, I’ll take that one, I know that feature, but really, you’re saying Please don’t look at that code, or at least, if you do, please don’t judge me—then you probably weren’t going fast enough. The remarkable thing isn’t that this team has produced a product that “already” needs a cleanup; the remarkable thing is that we all seem to recognize that we need to clean things up, before it’s blown up in any serious way yet. That’s why I’m thankful to be on the team that I am. I’ve heard it said that the difference between a good programmer and a bad programmer is that a good programmer feels pain when he looks at ugly code he’s written, while a bad programmer thinks everything he’s done is great.

I used to be proud of every bit of code I’d written, like a two-year-old who just learned how to use the potty. Then I grew up a little bit, and realized that my shit stinks, and hoped no one would ever see it. I’ve grown up a little more, and realized that everyone shits, so there’s nothing to be ashamed of. I try to work towards a point where my actually shit doesn’t stink at all, but I’m not all that hopeful about that. The fecality of this line of metaphor, while a bit disgusting, is meant to highlight an important point.

You want to create code that is nice to be around? Do your best to build quality in from the start. The more you learn, the better you’ll be at it, especially if you manage to code yourself into some truly awful maintenance nightmares, where you can’t walk away and can’t blame anyone else. But no matter how good you get, it’s still gonna stink most of the time. Everyone writes bad code. So fix it.


Wikipedia says:

Refactoring neither fixes bugs nor adds new functionality. Rather it improves the understandability of the code or changes its internal structure and design, and removes dead code, to make it easier for human maintenance in the future.

To relate to the twin principles of software development, “Go fast” and “Does it work?”, refactoring is not important early on. Surely, doing things as close as possible to The Right Way is usually a big help. But The Right Way almost always flies in the face of the “Go Fast” maxim.

I’ve been privy to a few refactoring projects, I think I can safely say that almost every single one was an utter disaster. Without naming names, here’s how a few turned out:

  1. Lead engineer spent 3 months internally redesigning a feature with the intent of making it more extensible in the future. Released. Numerous bugs and problems. When I left the company, it was still unstable. FAIL
  2. The product has grown into an amalgam of junk, and no one knows how to maintain all the disparate pieces. Can’t add features easily. Needs to be re-architected. [[numerous planning meetings]] OK, management says we have 2 months, so let’s just add another layer on it, change how it looks, and call it a day. Result was even more disorganized and difficult to extend. FAIL
  3. #2, again, with new people driving it, who insisted that the last ones were all wrong. Same result. DOUBLE FAIL
  4. Repeat, again. TRIPLE SUPER DUPER FAIL
  5. Last, but oh, so certainly not least, there were all the refactorings that didn’t even make it to a real execution. The times when the development team was so fed up that they pushed to change things, and were told repeatedly that they could get to that just as soon as the next project got done—there was always a “next project.” It works now, what’s the matter with it? To the best of my knowledge, of three teams where I saw this pattern, (a) one company no longer exists, (b) another company lost all their best talent, and (c) in the third case, the team dissolved and everyone moved onto other projects (it was at Yahoo!, so it’s not like they were going to go under.) For failing before they’d even gotten started, these refactoring projects are QUADRUPLE UBER KAMEHAMEHA FAIL!!!

I strongly doubt that any of these cases were rare. In fact, I think they’re the norm.

It’s easy to cite bad management, and in a few of the above cases, management was to blame. They put a high premium on getting new features, without recognizing the hidden costs down the road of dealing with the increasing instability. However, the fact that I’ve come to realize is that most developers don’t really understand maintainability, and thus, tend to completely miss the point of what the purpose of refactoring should be. As a result, their attempts at refactoring end up being worse than failures, because they are interpreted as success.

I did get to see one significant refactoring project that I’d consider a success. It was done in an under-the-radar sort of way, simply because it was the only way to add new features to a product that had grown frightfully unwieldy. Also, I’ve seen and done a lot of small scale refactorings that were executed well and increased the quality of the product as a result. (These, as the Wikipedia article mentions, are usually referred to as simply “cleaning up” the code base.)

Refactoring can only be justified in the “Go Fast” methodology on the condition that it makes a more stable product, thus enabling developers to more efficiently create working software. Elegance is not an end in itself. The end goal is a working product, and code is the enemy. The vast majority of software development is about modifying an existing product. The short-term memory of a human is limited and fleeting. The less information that must be held in mind to understand a given section of code, the more quickly code can be modified, the lower the likelihood of introducing bugs with any given change. So, there is, ultimately, only one purpose that Refactoring should serve:

Be more obvious.

Love Your Monster

Inside cover of the original 1918 Frankenstein by Mary Shelly.Victor was so consumed by his desire to create something new that he ended up rushing the job and not thinking ahead. When his creature opened its eyes, he feared it, and fled, and tried to hide from his sin. Shunned from the world, the creature asked Victor to make him a companion. When his request was denied, he proceeded to destroy everything Victor loved.

The moral of the story: Don’t ignore the ugliness you create. It will find you.

Refactoring should make the code simpler. Complexity is the demon that we fight in writing code. It is the enemy. It opens the doors to bugs; it increases the difficulty in fixing problems and adding features; it raises the learning curve for new developers. Sadly, a lot of refactoring seems to make code more complex rather than less.

In my opinion, there are a few guidelines that work well when changing around existing code. These guidelines apply equally well when creating new code, but since it’s harder to see the whole picture in that scenario, mistakes and shortcuts are more forgivable.

  • There should be as few layers as possible, and no fewer.
  • There should be as few objects as possible, and no fewer.
  • Each object should be as small as possible, and no smaller.
  • Each object should know as little as it needs to, and no less.
  • Each piece should have a job, and should stick to it.
  • Comments should be mostly unnecessary.

Refactoring isn’t about using the coolest object oriented tricks that you just learned. It’s not about making the code “more abstract.” Abstraction is a necessary evil, in my opinion, not a feature. Like Victor, it’s easy to get wrapped up in testing out new discoveries. Most of us got into this job because we like playing with new puzzles, and that’s a great thing. But one of the most satisfying puzzles is to reduce the complexity of an implementation without reducing the problems that it can solve.

I’m a big fan of “comment-driven development”. That is, write out the pseudo-code in comment form first, stubbing out the functions that need to be implemented. It helps to separate the design and implementation phases, since it can be hard to do both simultaneously. As implementation kinks are getting worked out, the design might change slightly, but it helps to have the comments there as a guide to what I was originally thinking. Once a module moves into a more stable place, the comments are a liability. At best, they’re clutter; at worse, misleading.

I like using those comments to clean up the code as well. The process goes like this:

  1. Read through the code, starting at the entry point, and opening each file as it’s referenced.
  2. If a section of code has a shit-ton of comments, then it needs work. If it’s clean, just make sure it makes sense.
  3. Make sure the comments match what the code is doing.
  4. Remove any incorrect comments (comments that are lying.)
  5. If the code isn’t understandable without the comments, then dig in and clean it up. Rename methods, sort things better, etc.
  6. Remove any and all implementation-related comments. Those are dangerous.
  7. Repeat until the file is almost comment free, and understandable.

I’m not so certain on the common refactoring claim that it should not change any existing functionality. Sometimes, this is of vital importance. However, there are plenty of times where the feature set of a bit of code simply needs to be trimmed or revised. For public-facing APIs and products, either the functionality should not be changed, or interfaces should be publicly deprecated long before they are actually removed.

For internal code, or APIs that are only used by a small number of consumers, my favorite approach is to just change it, and then see what breaks. This should never be done in a way that affects customers, of course, but in a development environment, it’s quite appropriate to just change the back-end, and then update the front-end once it’s fixed. Defensive coding is a good practice, but overly defensive coding, where errors are not surfaced at all, can hide problems that may turn up later in unexpected ways.

Don’t bother refactoring something you just wrote. You’ll only make it worse. You have to wait until you don’t remember how it works before you look at it again, or else you won’t be able to appreciate the difficult bits. If you don’t have time for that, then make someone else do it, and tell them to be as harsh as possible.


As they say, No matter what the problem is, it’s always a people problem. The first and most important step in any refactoring effort is to detach our egos from our code. This is even more of an issue if something you wrote is being refactored by someone else, or worse, if you are refactoring someone else’s code.

I’ve worked hard to develop a pretty good understanding of software development. I’ve found that the technology side is easy—on the human side, I still have a lot to learn, and probably always will. Like a lot of geeks, I didn’t really get into the whole “social” thing in a serious way until I was almost an adult, and even today, I tend to focus on The Project and keep my distance from the rest of the world. So, I suppose I don’t know the best way to handle this part of the problem.

TBL’s classic recommendation to be loose in what you accept, and strict in what you send seems to apply well to this case. On a healthy team, everyone is committed to a successful product, and leaves their egos at home when they come to work. Code is passed around and everyone seeks as much input as possible. On a dysfunctional team, everyone’s sense of self-worth is tied up in the appraisal of their work by others—which has the twin effect of making them overly sensitive to criticism, and overly critical of their teammates.

It’s natural to put up resistance to the prospect of your code being modified. After all, you wrote it that way for a reason. Sit down with the other developer, and try to hash out the best approach. If arbitrary decisions have to be made, explain that the best approach is to make them consistently. Don’t focus on the problems in their code, but rather on the need for consistency and abstraction throughout the product.

If someone won’t listen to reason, frankly, the only solution I’ve ever found is to either leave or wait for them to. Hopefully they’re a contractor or something, so you can just wait, and do your best to isolate and minimize the damage as much as possible in the meantime. If not, then the issue should be escalated, if only because it’s polite to tell your manager that their ship is in danger of sinking.

Oh, right, that book…

Refactoring, by Martin FowlerI read Refactoring about 5 years ago, but I’ve been meaning to pick it up again, since I’ve gotten a fair amount of real-world development experience since then, and have seen my share of dismal failures. But this isn’t supposed to be a book review, so I won’t review it in any detail. It’s a good read, though, and I highly recommend it, even though it is mostly in Java, and seemed (to me at least) to simply highlight a lot of design problems inherent in the Java language that lead inevitably to bloated over-sized code. But that’s a post for another day.

Cross Browser Support for inline-block Styling Mon, 19 Nov 2007 17:06:33 +0000 Isaac one of the best insane inventor webdevs I know. The pieces have been out there for some time, it seems, but I hadn't ever seen this spelled out as simply and elegantly as he did it. ...Read More]]> I learned a new CSS trick from one of the best insane inventor webdevs I know. The pieces have been out there for some time, it seems, but I hadn’t ever seen this spelled out as simply and elegantly as he did it.

Inline-block layout solves a lot of problems. It lets you do some cool stuff previously thought impossible with CSS. It makes vertical alignment work properly. And sadly, it’s supported pretty badly.

Mozilla doesn’t support inline-block at all, but they have -moz-inline-stack which is about the same. Fair enough, since no one else understands -moz-inline-block, you can just do this:


If you put inline-block after -moz-inline-stack, then Moz will start using the “right” one when it supports it.

IE supports inline-block, but only for elements that are natively inline. So, if you really want to use inline-block, you’re restricted to spans and strongs and ems, when a list or paragraph would perhaps make more semantic sense (and also degrade more nicely for non-CSS users.)

However, if you trigger hasLayout on a block element, and then set it to display:inline, it magically becomes an inline-block in IE! By using the *property hack (which I love so well), you can hide the display:inline from all non-IE browsers effortlessly.

Here’s the code, in all its brief loveliness:


From there, it pays to learn a thing or two about the vertical-align property. It lets you do lovely things like this.


Inline block elements can be vertically centered like display:table-cell, but they wrap when they get to the end of their parent. Also, it’s supported across browsers using this hack, whereas display:table-cell is not supported in IE.

This technique allows for some very interesting layout approaches that would have required a lot of very tricky use of floats previously.


If an element is inside of an inline block, and lies outside the line box, then it won’t be clickable in Mozilla. Give the child element position:relative to correct the problem.

Elements treated this way will have hasLayout set in MSIE. This is a weird and esoteric aspect of MSIE’s CSS engine that has potentially unforeseen consequences. Beware.

If an IMG element is directly inside an inline block element in Mozilla, it will stretch to the full width of that element. Wrap all IMG tags in a block-level container element to avoid the problem.

Since inline block elements wrap and flow like inline content, that means that they also respect white space like words on a page would. That is, if there is *any* whitespace between two inline-block elements, then a single space will be added between two inline-block elements. If this causes a problem, you can either remove the whitespace or comment it out like so:


All in all, the caveats are pretty easy to work around, and the benefits allow for some really cool stuff that would be almost impossible or very difficult otherwise.

The 2 Faces of vertical-align

In a classic CSS blunder, vertical-align can mean 2 extremely different things, depending on whether an element is display:inline-block or display:table-cell.


Align the element’s contents according to the element’s vertical-align property. IE, if the cell’s vertical-align is set to “middle”, then vertically center the element’s contents. The height and position of the element itself is determined by the containing display:table element.


Align the element according to the element’s vertical-align property. IE, if the inline-block’s vertical-align is set to “middle”, then the element is vertically centered in the line-block. The height and position of the element’s contents are determined by the standard block-level flow rules.

While I personally believe that this was a stupendously bad and confusing approach to take, I believe that the reasoning comes from backwards compatibility. Inline blocks emulate the behavior of the IMG tag, and the vertical-align CSS property thus mimics the old valign attribute. Table cells emulate the behavior of the TD tag, and the vertical-align CSS property thus mimics the behavior of the valign attribute on TDs. In other words, in this way, CSS faithfully reproduces the sloppy errors of HTML. It would have been better to use two different properties to achieve this effect; after all, vertical-align:baseline hardly makes sense for table cells. Perhaps the inline-block type of vertical alignment would have been better called “line-position” or some such, since it is less like a vertical version of the text-align property.

But, you write code with the language you have, not the language you wish you had, and CSS is what it is, at least for the foreseeable future.

Recently, I had to achieve an effect that was extremely tricky by standard methods, but extremely easy using tables. I decided to test out a display:table approach, and then try to hack it into place for IE, since it is the only browser that does not support this approach.

The result uses a fairly large number of DIVs, but still fewer than the straight table approach, and without the semantic rubble of tables. The dialog is vertically and horizontally centered, but if you resize the viewport too small, the dialog will not be hidden permanently, due to the “collapse to fit” nature of the table display style. Doing this will an inline-block would have been quite a bit more difficult.

For IE, I used the 50/50 hack. Create a position:absolute element at top:50%. Then, create a position:relative child at top:-50%. The negative top rule on the position:relative element will be misinterpreted, and result in a vertically centered box. The downside is that IE gets a scrollbar if the viewport is less than twice the height of the dialog. But, that’s a pretty acceptable down side, in my opinion.

Sadly, unlike with display:inline-block, it doesn’t look like there’s any real consistency to support display:table across browsers. (Except, of course, using table tags.) You basically just have to hack something for IE that achieves the same effect, and which approach you use varies on the effect you’re going for. In this case, I exploited an IE positioning bug to achieve vertical centering, but other situations would require different approaches. If you’re doing complex layouts using display:table, which in a perfect world would indeed be a great way to do it, you’re going to have a lot of work cut out for you hacking away at IE.

Let’s pray that IE 8 supports display:table!