Partly because I haven’t been writing much CSS these days, and partly because it’s been just over a year since the last redesign, I felt like this site needed a face lift.
I’ve been getting more and more excited about the impending freedom of the @font-face CSS declaration. The prospect using any true-type or open-type font in a web page without resorting to flash or images is incredible. If you’re viewing this site in Safari 4 or the latest beta releases of Firefox, Opera, and MSIE, you’ll have a much improved experience.
The body text is set in Bodoni SvtyTwo OS, chosen for its beautiful italics (not an oblique, but a true italic), dramatic hinting, and straightforward lines. I chose the OS over the regular Bodoni SvtyTwo because of the more stylish “lower case” numerals: 1234567890.
: I decided to go with Hoefler Text instead of Bodoni. Bodoni looks nice, but without the stronger hinting, it was hard to read on some monitors, especially for folks who are crazy enough to browse the web on Windows. Hoefler Text has a lot of what I liked about Bodoni, and was a strong contender, but it’s not free-as-in-speech. However, it is free-as-in-MP3, so I’ll use it until Hoefler & Frere-Jones send me a C&D. I also widened the column a bit to accommodate the wider typeface.
The headings are set in Qlassik Medium, by Dimitri Castrigue. It has just enough fun to make it stand out, but not so much as to be ridiculous.
Code snippets are set in the famous Bitstream Vera Sans Mono. I’d initially planned to set all things monotype in my favorite coding font, Century Schoolbook Mono. Once you get used to coding with serifs, nothing else feels right. Unfortunately, it doesn’t include bold and italic versions. While the OS will “fake” bold and italics with fonts that it has installed, it won’t play ball when asked to manipulate dynamic fonts linked from a CSS file. I put CentSchBook Mono first, so if you have it (which you should!), it’ll work. Otherwise, you’ll get Bitstream.
If you don’t have a browser that understands dynamic fonts, you can grab them from http://foohack.com/tpl/fonts/.
I really wanted to stretch my CSS abilities a bit, and also apply some of the principles of typographic design that I’d been learning about lately. The single-column is about 66 characters wide in the target font, and feels about “right” for readability.
Despite my best intentions, a lot of feature creep had somehow taken over, prompting the last revamp. In this version, I put back some features that I’d removed, and removed some things I’d left in.
The vertical measure is set at 30px, with a font-size of 20px. While that’s a bit large, I’ve always favored erring on the side of “too big”, and the Bodoni just felt too cramped at 16/24.
I’ve also taken a lesson from the print world, and set all my bullets and other adornments off into the margins, such that the text is kept strictly flush left. The only element that I couldn’t figure out how to do this with is the
<q> element when it starts a paragraph. In that case, it should have a text-indent somewhere around -0.5ex, but I couldn’t manage to do that without borking quotes that start somewhere in the middle of the paragraph.
Since all the major browsers support resizing fonts that are set in pixels, and “zooming” is now preferred over simple font resizing, I went ahead and set everything in pixels so that the math would be easier. There’s really no benefit to so-called “fluid” layouts that are set in ex or em measurements. Plus, browsers that support dynamic fonts seem to have a really hard time with ex/em measurements, since the layout is rendered before the font has downloaded. I do hope that gets fixed at some point, but doing layout in pixels was a welcome return to basics.
The luxury of a personal site: I didn’t test even once in MSIE, and I don’t plan to.
Also, since a lot of the style is in the typography, anyone with a browser older than 6 months isn’t going to see my beautiful styles. But they’ll see their own default font settings, I suppose, and that’s probably fine.
What do you think?
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 , which really means,
<div> tags or
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.
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.
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.
So, it started out as just a few font changes. I’d been growing less and less pleased with Trebuchet MS, and had found a few cases where it broke the militant line-height rules I’d set for this site. In general, I felt that it was too crowded, and the gray hash textured background was (in my opinion) a contrived and artless approach.
I’m not a very understanding end-user when it comes to this site. The Foo Hack design team got fed up with my complaints, and decided to give in and make some changes.
Feature creep is a bitch when you have a deadline. For personal projects, there is no deadline, and so a bit of feature creep is fun, within reason. That’s a big part of the reason why I have so many back-burner projects that are almost finished; just as I near the finish line, I decide that it needs a little more, or another project gets more interesting for a while. So, on to what changed.
I was a computer geek first, but when my dad replaced our DOS home computer with a Windows 3.1 box, I fell in love with fonts. I can waste an afternoon surfing the web downloading fonts that I’ll probably rarely (if ever) use. Web design is about 90% typography, and it is an art that blends strict perfectionism and fluid acceptance in a beautiful way.
For the main body text, I wanted something subtle and easy on the eyes. Something that would let the writing speak in the voice that I intend, without getting in the way. For the “small” items of diminished importance (asides and things in
<small> tags) I wanted a serif font with a very thin ex measurement, so that the text could “feel” smaller without altering the line-height. For the headings, I wanted a rounder, more open font that could evoke a sense of boldness without being too heavy. Subheadings and meta items (the date, “comment” link, etc.) should use the same font, but with less letter space and a subtler color.
For the body text, I decided to go with Helvetica, the classier old-world cousin of Arial. I was initially pleased with the results.
Cliché though it may be, Times New Roman was the perfect choice for the diminished items. It’s very light, yet still fairly readable, and when italicized, it practically disappears. I was already using it for that reason, but since I don’t love TNR all that much, I was willing to entertain other possibilities.
If Helvetica is so great, why do I see Arial?
A problem came up when I noticed that the line-height was getting messed up whenever a TNR inline element would wrap to the next line. I figured out the problem.
Let’s say you have font A and font B. You create a block-level element using font A. Then, you have an inline element using font B, which wraps to the next line.
If A and B don’t put their letters on exactly the same point in the line-block, then the line-height will adjust up or down, as the next line is set by the position of the letters in B instead of the position of letters in A. Since the B element isn’t a block-level element, it won’t create a whole new block, and will have the effect of adding or removing a few pixels from the overall height of the A element.
To correct this problem, and still have 2 fonts sharing the same block-level element, you need to find two fonts that have exactly the same vertical letter placement on the line block.
I’m not exaggerating when I say that I created a test page and exhaustively tested every combination of serif and sans-serif fonts on my Mac. It took about a week. There was only one combination that worked.
Arial and Times New Roman.
Ah, compromise, my old nemesis. You strike again. Not willing to give up the line-height strictness, I gave in and decided to use Arial instead of Helvetica. On the bright side, Windows users were mostly going to see Arial anyway, and they’re both tried and true web-safe fonts. And, at typical screen resolutions, it’s hard to tell the difference anyway. But still, it’s a bit of a sore point.
Gotham, Large and Small
Gotham, the masterpiece homage to urban signage by Hoefler & Frere-Jones, is quite possibly the best font ever devised. It’s open and confident even when it’s not bold, balanced and practical. I went with this as the headings, and it also was the best candidate for the smaller informational bits. (After all, it seemed fitting to put navigational links in a font designed for signage.
The downside of such a perfect font is that it’s not free. It would be fantastic if Apple or Microsoft were to license Gotham for their respective operating systems, but I don’t see that happening any time soon. Those that don’t want to install Gotham will see Century Gothic (if it’s installed, most likely because they got it bundled with Microsoft Office), or something in the Lucida family.
Accentuate the Important, Diminish the Rest
I brought down the contrast a bit, and did away with the background graphic. Some color was sprinkled around to help create a meaningful mental model of each page. I got the idea for the categories above the titles from Rands in Repose, one of my favorite regular reads.
The default set of post meta info that Wordpress provides is far more than necessary. I got rid of everything that didn’t directly benefit the goals of conversing with the world through this blog.
It seems awkward that my comments should have a blue left border, and reader comments are unadorned. Simply using random colors wouldn’t do. So, I wrote a function that will hash a string into a color value. A simpler hash would have sufficed, but I wanted more control over the range of colors that it selects, and
rand() was a good fit. So, your comment will always have the same color (unless you use a different email address, of course) and all the colors will be in a particular mid-range of luminosity that is bold, but not overpowering.
I’ve already run into a few situations on this blog where I felt that threaded comments would have been helpful. However, the threaded forum-style comments would be complex and counterproductive. I grabbed a standard threaded-comment plugin, and tweaked it to replace the interface with a few hyperlinks. Since conversations are more naturally many-to-many, I’d like to implement something along the lines of what Dunstan Orchard used to have on his blog, but doing that the right way means a bit more investment, and this project was dangerously close to being back-burnered forever.
Note: This method has a few problems. Scrolling breaks on the iPhone, and the test page has some issues with tabbing through links. See my comment below. A new version will be posted soon. –i
Feel free to skip all this and go straight to the example.
In the application world, creating a modal is pretty straightforward. Here are some features that every modal window should have:
- Interaction with the contents of the parent window should be *impossible* until the modal is dealt with. Scroll-mouse should not scroll the background page, clicking should not click the background page, tabbing should not get you there, etc.
- When you dismiss the modal, the parent window should be *exactly* how you left it.
- The parent window should be dimmed, or there should be some other indicator that it is currently not available for interaction. This has the corollary effect of making the modal “pop” a bit more.
- In a web page, a modal should be constrained within the viewport. Opening a new window just to show a dialog box is ugly as a bucket of slugs.
- The modal should be placed consistently. If it is not movable, then it should be centered vertically and horizontally. This positioning should be consistent if the parent window is resized or moved.
- The modal should be smaller than the parent window. If the viewport is resized smaller than the modal, then scrollbars should appear that allow the user to see the rest of the modal.
The rule of thumb: The modal should be visible always and in every situation, the parent should be dimmed and preserved. Almost every modal dialog I could find online broke a few of these rules.
In some, the html and body elements have their overflow set to hidden when the modal is shown, so the current scroll position of those elements is lost. If you were looking through a list of items, and you brought up a modal dialog related to one of them, then you’re back to the start of the list when the modal is dismissed. Annoying.
In others, you CAN scroll the background, but the modal is set to respond to the onscroll event to try to stay in place. Some of the time, they use display:fixed to behave a little nicer in non-IE browsers. At worse, you get a jumpy seizure-inducing experience; at best, you accidentally scroll the background and lose your place without realizing it.
It’s a bit of an edge case, but you do have to handle cases where the modal might be taller/wider than the viewport. As a test, I tried resizing the viewport down on a bunch of modal approaches. Vertical centering often doesn’t do too well unless the contents are smaller than the viewport, so the top and bottom of the modal were cut off. Unacceptable.
It wasn’t terribly difficult to create one that obeyed these rules. Here’s the approach that I took.
- Build it with tables.
- Replace the tables with divs, and give them the appropriate display:table, display:table-cell CSS rules.
- Fret and hack to try to get it to work in IE, unsuccessfully.
- IM another yahoo who has a reputation for being a great webdev hacker.
- Adapt what he did to my needs.
For the non-IE browsers, it’s pretty straightforward. Take the scrollbars off of the HTML and BODY elements, and put them on #body instead. #modal is a sibling of #body, so when it is 100% height and width, it will cover it up. Then #modal will overlap the scrollbars of #body, without losing the scroll position. Also, that means there’s no need to do any trickery with a negative right margin to try (unsuccessfully, on the mac) to overlap the scrollbars.
Since .overlay element in the modal has a display:table, it will always expand to fit its contents. .overlay’s parent is overflow:auto, so if .overlay is too big, it’ll let you scroll to see the rest.
What this means is that you can’t cut off the top and bottom of the modal. It’ll be vertically centered if there’s room, and if not, it’ll be flush to the top and scrollable. Perfect.
For IE it gets trickier. Hedger’s example showed 2 great ideas, though. Basically, if you have 2 siblings that are display:inline-block, then, in IE at least, the line-block will expand to fit both of them. So, they both end up being vertically centered to the height of the taller child. If that taller element is width:0, then you essentially have an arbitrary line-height setter for the inline-block row. In this case, the height is set to 100%.
The other child will be whatever height it is based on its contents. If that happens to be taller than 100%, then the line-height will be taller than the viewport. At that point, the overflow:auto parent shows a scrollbar to let you see the rest. Identical behavior to the standards browsers!
The second problem arises with IE’s peculiarities when it comes to percentage heights. For whatever reason, if you have a position:absolute element, it doesn’t like to do height:100% unless some parent has a fixed height value, like 500px. 100% of 100% doesn’t compute, for some reason. Sadly, that means that the element that does the overlay wouldn’t be able to properly do its job in IE. So, instead of using a separate transparent layer with a background image, Hedger used the DXImageTransform.Microsoft.gradient filter on the modal container itself. However, since the gradient filter doesn’t actually prevent interaction with the background, I added a 1 pixel transparent gif as the background image.
I’d very much like to not use this transparent pixel. It feels a bit like a spacer gif to me. But, all in all, it’s a pretty small price to pay.
I didn’t bother to tackle the tab-order focus stuff in this little test page, since I wanted to just isolate the stylistic stuff to get it working across browsers. However, it would be good to put a focus handler on #body, and any time a #body element gets focus, focus the #modal instead. That way, once you tab off the modal dialog, you’d get right back onto it. In the spirit of being friendly to keyboard users, it would also be a good idea to keep track of the currently focused element when the modal opens, and go back to it once the dialog closes.
Here it is for your view-source pleasure.
Please please feel free use this modal. Life is too short to futz around trying to see the “cancel” button that is hiding off the screen so you can go back to reading your page.
Let me know if you can think of any enhancements or find any problems with it. Those of you in the US, I hope you had a great Thanksgiving.
I updated it to add support for focus and blur events. It works in Firefox, MSIE, and Safari. Opera on the Mac has some really strange behavior regarding focusing on links, and I decided that it just wasn’t salvageable. Safari requires a bit of hacking to get the focus stuff to work properly, but I think it’s acceptable.
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:
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!