meyerweb.com

Skip to: site navigation/presentation
Skip to: Thoughts From Eric

Archive: 'Standards' Category

Wanted: Layout System

(This is part of the Feedback on ‘WaSP Community CSS3 Feedback 2008′ series.)

Not surprisingly, there was a lot of community feedback asking for better layout mechanisms.  Actually, people were asking for any decent layout mechanism at all, which CSS has historically lacked.  Floats mostly work, but they’re a hack and can be annoyingly fragile even when you ignore old-browser bugs.  Positioning works in limited cases, but does not handle web-oriented layout at all well.

Why do we use floats for layout, anyway?  clear.  That’s pretty much the whole answer.  The unique in-flow/out-of-flow nature of floats means they interact with each other and with the normal flow, which means they can be cleared, which makes them useful.  Because with clear, we can float layout blocks around and then push other non-floated blocks, like footers, below the floats.

Positioning, of course, permits total layout freedom in the sense that you can put a layout block anywhere with respect to its containing block.  The downfall is that absolutely positioned elements are entirely out of the normal flow, so they can’t stay out of each others’ way like floats do, and you can’t clear anything with respect to a positioned element.  If there had been a position-clear or its equivalent from the outset, we’d never have bothered with floats.

(And if we can just add position-clear to CSS, that would be completely awesome.  It’s been done with JavaScript and it will most likely be done again and better.  It wouldn’t even be that hard to implement, at least for 99.5% of cases.)

All this is why the old “only use tables for layout” argument keeps coming up over and over: strip away the overheated rhetoric and obvious link-baiting, and you find the core of a real need.  Because as powerful as CSS can be, table cells do certain things very easily that CSS makes very, very hard.  Cells stretch vertically, keeping equal heights as a matter of their intrinsic nature.  They stay out of each others’ way, while still being allowed to sit next to each other and use any sizing dimensions.  They tie their layout to their parent elements, and vice versa.

There are no equivalents in CSS.  There have been various very clever attempts to replicate bits and pieces of those capabilities using CSS.  What CSS does, it does very well: if you don’t need equal-height layout blocks, then no problem.  If you do, it’s a massive pain.  Clever techniques provide substitutes, but can’t replace what tables already do.

And please, let’s put the whole “display: table-cell will grant those abilities through CSS” to rest.  Saying that is just saying “use tables for layout” with different words.  Turning a bunch of divs or list items or whatever into table-role boxes is no better than just using table markup in the first place, and it’s arguably worse.  Using element names other than table and td to create layout tables, and then claiming it’s not using tables for layout, borders on self-deception.

Not to mention doing things that way means you’re doing your layout in a highly source-order-dependent fashion, which was one of the things about table layout we were trying to get away from in the first place.

So how do we get really powerful source-order-independent layout?  I wish I knew.  The Advanced Layout module has been sitting around for a while now, and even if you’re a fan of defining layout as ASCII art—which I find repels and appeals in equal measure, but that’s probably just me—there appears to be close to zero implementor interest.  So how do we get those abilities in a form that implementors will, y’know, implement?  I don’t know.  I don’t care.  We just need it, and have needed it for a good decade or so.  Without it, CSS is a styling language but not a layout language.  We’ve bent it into being something close to a layout language, which is nice but not really ideal.

Maybe CSS isn’t the place for this.  Maybe there needs to be a new layout language that can be defined and implemented without regard to the constraints of the existing CSS syntax rules, without worrying about backwards compatibility.  Maybe that way we can not only get strong layout but also arbitrary shapes, thus leaving behind the rectangular prison that’s defined the web for almost two decades.

I don’t have a concrete idea to propose here, because it’s not up to us any more.  A solution was worked out over the course of several years and then found wanting by the implementors.  Really, it’s up to the implementors to figure it out now.  I personally would like to just lock the browser teams from Microsoft, Mozilla, Opera, and Apple in a room and not let them out until they’ve defined something that works and they’ve all agreed to implement soonest.  I might even supply food and water.

And yes, I just advocated doing this outside the W3C process.  Why wouldn’t I?  The process has, in the last decade, not produced anything even remotely resembling an answer to this problem.  Time to try another path and see if it gets any closer to the goal.

No doubt someone’s going to spin this as “See, even noted standards zealot Eric Meyer now says CSS is flawed!”—only they’ll be wrong because this isn’t a now thing.  I’ve been saying this for years in interviews, in person, and in general.  Any time someone asks me what CSS is missing or should do better, the answer has always been a variant on “a strong layout system”.  I’ve been saying it for at least a decade.  So I’m not saying it now.  I’m saying it again.  And again and again and again and…

If I sound frustrated, it’s because I am, and have been for a good long while.  I’m not the only one.  It rankles to have CSS be, as Winston Churchill would have put it, the worst form of layout except for all the others that have been tried.

CSS3 Feedback: Layout

(This is part of the Feedback on ‘WaSP Community CSS3 Feedback 2008′ series.)

In this round, layout.  Not all of it, but the bits that struck me as either really useful or really, really way too long overdue.

Float containment yes, we need a property that does just that.  As long as we’re tied to floats for layout—and I plan to rant about that soon—there should be a clear, unambiguous, intentionally defined property that tells elements to wrap themselves around floated descendant elements.  overflow works in most cases but can fall down in unusual circumstances (I’ve seen scrollbars appear where none were actually needed) and anyway, it wasn’t intended to provide the wrapping effect in the first place.  That it does so is a happy side effect, but it’s still a side effect.  The rest of the float-wrapping techniques are even more convoluted.  “There are already ways to do that so we don’t need a property” is rather like saying “we can already do layout with tables so why do we need CSS layout?”.

Positioning by center yes, please.  The way to center an absolutely positioned element within its containing block is to set the top and left to 50% each and then define negative top and left margins that are half the positioned element’s height and width.  That’s just awful, and requires at least an explicit width, if not an explicit height.  When I did the structured timeline, here’s how I got the version numbers to center below the dots:

#timeline tbody td p {
	position: absolute;
	top: 50%;
	width: 2.1em;
	margin: -5px 0 0 -1em;
}

See that -1em left margin, and the 2.1em width?  Just to get the center of positioned elements’ boxes sit on top of a certain left offset (defined elsewhere in the CSS).  Ditto the negative top margin, to pull it upward just enough so that the elements’ boxes would have the point five pixels down from their tops line up with the vertical midpoint of their containing blocks.

I wanted to do something like this:

#timeline tbody td p {
	position: absolute;
	top: 50%;
	position-anchor: 50% 5px;
}

That would have said that the point in the center of the absolutely positioned element should be placed at the point in the containing block 21.7% down from the top and 44% of the way across from the left.  That would hang the positioned element’s center on that point, regardless of the size of the positioned element—note that I took out the width.  I could stop defining explicit sizes and just let the elements be the size they want to be to show their content.

The problem is that approach doesn’t fit at all well with the way positioning layout is defined.  Suppose I said this:

#timeline tbody td p {
	position: absolute;
	top: 50%; bottom: 0;
	left: 50%; right: 25%;
	position-anchor: 50% 5px;
}

Now what?  I’m not even sure myself.  Maybe define rename it to position-offset and define percentages to be relative to the height and width of the positioned element (not its containing block), so that it doesn’t interact directly with the offset properties like top and right?

All I want is a way to hang elements off of offset points, and not be restricted to the corners of the elements, and have the solution work even when the elements have automatic height and width, and not require extra markup to make it happen.  Oh, and a ponycar.

Box sizing what in the nine hells of Valeria is taking so long?  We needed that one ten years ago.  I no longer care if it’s done as its own property or as new keywords on height and width.  I just want it.  Someone will make it happen, with or without the WG or implementors—mark my words.

Same-height elements yes, a way to tie element heights (whether they’re siblings or not) together would be welcome, although I can see how specifying it in an implementable would be tricky; no, display: table-cell  is not the answer.  Soon I will rant about this.  Soon.

CSS3 Feedback: Selector Blocks

(This is part of the Feedback on ‘WaSP Community CSS3 Feedback 2008′ series.)

Out of all the selector feedback, selector blocks was the part that really caught my attention.  I also see the usefulness of a parent selector, but that one has come up many times before, and it’s always died at the doorstep of implementors, who point out that it’s far too difficult to implement without serious performance penalties and even risk of browser lockup.  See, for example, the comment left by David Hyatt on Shaun Inman’s post on the idea.  Similarly, I think constants (or macros or whatever they’re called) are a great idea and would be very helpful, especially if you’re coding up a Jason Special.  Both are loaded with use cases, so I don’t feel like I can add a lot; besides, constants are already in the WG charter, so there’s once more hope in the land.

So anyway, selector blocks.  To pick one recent example, while working on a project that should very soon see the light of day, I had a situation involving the following chunk of rules.

h1, h2, h3, h4, h5, h6, table {
   font: 1em Arial, "Helvetica Neue", Helvetica, sans-serif;}
h1 {font-size: 275%;}
h3:first-child {margin-top: 1em;}
p.tagline {margin: -0.25em 0 1.25em;
   font-size: 125%;
   color: #7B7960;}
h3 {margin: 1.5em 0 0.25em; font-size: 125%;}
h3:before {font-size: 75%; counter-increment: subhead;}
h4 {margin: 2.5em 0 0.75em;
   text-transform: uppercase; font-size: 125%;
   color: #928F59;}
p {margin: 0 0 1em;}
ul {padding-left: 1.5em;}
ul li {list-style: disc; margin: 0.5em 0;}

Nothing unusual about them, of course, unless you count my use of counters.  These rules had been written early on in development, and the design had evolved around that part of the document.  As more page components were added, I realized that I needed to scope all these rules to one section of the document: specifically, a div with a class of main.  So here’s what I had to do.

.main h1, .main h2, .main h3, .main h4, 
.main h5, .main h6, .main table {
   font: 1em Arial, "Helvetica Neue", Helvetica, sans-serif;}
.main h1 {font-size: 275%;}
.main h3:first-child {margin-top: 1em;}
.main p.tagline {margin: -0.25em 0 1.25em;
   font-size: 125%;
   color: #7B7960;}
.main h3 {margin: 1.5em 0 0.25em; font-size: 125%;}
.main h3:before {font-size: 75%; counter-increment: subhead;}
.main h4 {margin: 2.5em 0 0.75em;
   text-transform: uppercase; font-size: 125%;
   color: #928F59;}
.main p {margin: 0 0 1em;}
.main ul {padding-left: 1.5em;}
.main ul li {list-style: disc; margin: 0.5em 0;}

This, on the other hand, is what I really wanted to do:

.main {
   h1, h2, h3, h4, h5, h6, table {
      font: 1em Arial, "Helvetica Neue", Helvetica, sans-serif;}
   h1 {font-size: 275%;}
   h3:first-child {margin-top: 1em;}
   p.tagline {margin: -0.25em 0 1.25em;
      font-size: 125%;
      color: #7B7960;}
   h3 {margin: 1.5em 0 0.25em; font-size: 125%;}
   h3:before {font-size: 75%; counter-increment: subhead;}
   h4 {margin: 2.5em 0 0.75em;
      text-transform: uppercase; font-size: 125%;
      color: #928F59;}
   p {margin: 1em 0;}
   ul {padding-left: 1.5em;}
   ul li {list-style: disc; margin: 0.5em 0;}
}

Or, if necessary, to put the whole original chunk into its own style sheet and then do one of the following:

div.main {@import url(main-style.css);}

<div class="main" style="@import url(main-style.css);">

Interestingly, the latter is theoretically possible, thanks to the more advanced profiles in the CSS module “Syntax of CSS rules in HTML’s ‘style’ attribute“.  I’m not aware of the former having been seriously considered (despite my best efforts, once upon a time), though it’s always possible I missed something.

But either one of those approaches would be a last resort, in my opinion.  I’d much rather just wrap the whole chunk in .main { }, like I showed previously, and be done with it.  That capability would also simplify certain annoyingly repetitive patterns, like the very first of those rules.  I think it’s pretty obvious which of the following is easier to write and maintain:

body.home #content .entry h2, 
body.home #content .entry h3, 
body.home #content .entry h4, 
body.home #content .entry h5, 
body.home #content .entry h6 {...}

body.home #content .entry {
   h2, h3, h4, h5, h6 {...}
}

I mean, just look at the former, and imagine what one goes through to write it in the first place.  Copy, paste, paste, paste, paste, paste… maddening.  And that’s just for a small block of CSS like this one.  Imagine the tedium of doing this for a block of 50 rules, or 150.  (Also, this is the the same thing that was requested in the feedback as “Grouped Alternates“, albeit with a different syntax.)

One objection to this sort of pattern is that it increases dependence on descendant selectors, which are computationally inefficient.  But it doesn’t: I had to create a whole bunch of descendant selectors as it was, and did so far more clumsily.  And had I missed a command-V somewhere, I’d have had styles that applied outside their intended subtree.  Introducing a way to nest blocks like this doesn’t change anything except make it easier and more maintainable to do what we already do.  Honestly, it’s pretty much impossible to increase dependence on descendant selectors.  The best we can do now is make them less difficult to write.

I realize that the syntax I depict would cause backwards-compatibility problems, as in older browsers would not behave as intended when exposed to this sort of thing, but I’ve also stopped being concerned about that.  We can’t keep holding ourselves hostage to decisions made a decade or more back.  Provide the capability and authors will use it when they can.  Over time, its use will become more prevalent—kind of the same way authors adopted CSS in the first place.

I also realize that this case has been made time and again by many, many other people.  This isn’t even the first time I’ve made this case, though I think the other times were within the WG and therefore off the public record.  The fact that it keeps being made is a strong indicator that the need exists, and dismissing the idea because the same end effect can be achieved with existing selector syntax (as shown above) isn’t acceptable.  That’s like saying that complex selection effects can be achieved with JavaScript or XPath, so there’s no need for advanced CSS selectors.

So that’s my use case.  I actually have a bunch more, but they all follow the same basic pattern: the desire to group rules together into subsections of a document, or to otherwise simplify the writing of CSS.

Feedback on ‘WaSP Community CSS3 Feedback 2008′

Back before holiday season hit, Elika Etemad—better known as Fantasai—published WaSP Community CSS3 Feedback 2008.  I gave it a read and came away with a number of things I wanted to say.  So many things, in fact, that I’ll need to split them up into a series of posts.  This here post will serve as introduction and hub, with links to the follow-on entries added as they’re published.  All very Bray-ny, no?  (Go ahead, groan.  It only encourages me.)

Here you go:

  1. Selector blocks
  2. Layout
  3. Wanted: Layout System
  4. Animated Shapes
  5. Graphical Thoughts

I want to make clear up front that I’m not going to address every single point in the feedback document: it’s just too incredibly huge.  I did think about making my own copy and then just filling in my reactions to each point, but that didn’t scale very well.  Not only did it seem really overbearing and maybe just a touch egotistical, but some of my reactions were based on related topics in separate areas of the original.  Besides, I know what it’s like trying to read a really, really long article, so breaking it up and just focusing on the parts that got me fired up made way more sense.

There is one thing I want to address before I start serving up the follow-on installments.  At the end of Fantasai’s post, there’s a link to my 2006 post about the benefit of having a community liaison, someone who bridges the gap between the WG and the public.  She then asks if anyone is interested in volunteering, but personally, I don’t see the need.  The WG already has a community liaison:  it’s you, Fantasai.  It has been for some time now, thanks to your regular and informative CSS WG blog posts and other outreach work such as “WaSP Community CSS3 Feedback 2008″.  The job is being done, and being done very well, I don’t think there’s any doubt that the Working Group is much, much better for it.

JavaScript Will Save Us All

A while back, I woke up one morning thinking, John Resig’s got some great CSS3 support in jQuery but it’s all forced into JS statements.  I should ask him if he could set things up like Dean EdwardsIE7 script so that the JS scans the author’s CSS, finds the advanced selectors, does any necessary backend juggling, and makes CSS3 selector support Transparently Just Work.  And then he could put that back into jQuery.

And then, after breakfast, I fired up my feed reader and saw Simon Willison‘s link to John Resig’s nascent Sizzle project.

I swear to Ged this is how it happened.

Personally, I can’t wait for Sizzle to be finished, because I’m absolutely going to use it and recommend its use far and wide.  As far as I’m concerned, though, it’s a first step into a larger world.

Think about it: most of the browser development work these days seems to be going into JavaScript performance.  Those engines are being overhauled and souped up and tuned and re-tuned to the point that performance is improving by orders of magnitude.  Scanning the DOM tree and doing things to it, which used to be slow and difficult, is becoming lightning-fast and easy.

So why not write JS to implement multiple background-image support in all browsers?  All that’s needed is to scan the CSS, find instances of multiple-image backgrounds, and then dynamically add divs, one per extra background image, to get the intended effect.

Just like that, you’ve used the browser’s JS to extend its CSS support.  This approach advances standards support in browsers from the ground up, instead of waiting for the browser teams to do it for us.

I suspect that not quite everything in CSS3 will be amenable to this approach, but you might be surprised.  Seems to me that you could do background sizing with some div-and-positioning tricks, and text-shadow could be supportable using a sIFR-like technique, though line breaks would be a bear to handle.  RGBa and HSLa colors could be simulated with creative element reworking and opacity, and HSL itself could be (mostly?) supported in IE with HSL-to-RGB calculations.  And so on.

There are two primary benefits here.  The first is obvious: we can stop waiting around for browser makers to give us what we want, thanks to their efforts on JS engines, and start using the advanced CSS we’ve been hearing about for years.  The second is that the process of finding out which parts of the spec work in the real world, and which fall down, will be greatly accelerated.  If it turns out nobody uses (say) background-clip, even given its availability via a CSS/JS library, then that’s worth knowing.

What I wonder is whether the W3C could be convinced that two JavaScript libraries supporting a given CSS module would constitute “interoperable implementations”, and thus allow the specification to move forward on the process track.  Or heck, what about considering a single library getting consistent support in two or more browsers as interoperable?  There’s a chance here to jump-start the entire process, front to back.

It is true that browsers without JavaScript will not get the advanced CSS effects, but older browsers don’t get our current CSS, and we use it anyway.  (Still older browsers don’t understand any CSS at all.)  It’s the same problem we’ve always faced, and everyone will face it differently.

We don’t have to restrict this to CSS, either.  As I showed with my href-anywhere demo, it’s possible to extend markup using JS.  (No, not without breaking validation: you’d need a custom DTD for that.  Hmmm.)  So it would be possible to use JS to, say, add audio and video support to currently-available browsers, and even older browsers.  All you’d have to do is convert the HTML5 element into HTML4 elements, dynamically writing out the needed attributes and so forth.  It might not be a perfect 1:1 translation, but it would likely be serviceable—and would tear down some of the highest barriers to adoption.

There’s more to consider, as well: the ability to create our very own “standards”.  Maybe you’ve always wanted a text-shake property, which jiggles the letters up and down randomly to look like the element got shaken up a bit.  Call it -myCSS-text-shake or something else with a proper “vendor” prefix—we’re all vendors now, baby!—and go to town.  Who knows?  If a property or markup element or attribute suddenly takes off like wildfire, it might well make it into a specification.  After all, the HTML 5 Working Group is now explicitly set up to prefer things which are implemented over things that are not.  Perhaps the CSS Working Group would move in a similar direction, given a world where we were all experimenting with our own ideas and seeing the best ideas gain widespread adoption.

In the end, as I said in Chicago last week, the triumph of standards (specifically, the DOM standard) will permit us to push standards support forward now, and save some standards that are currently dying on the vine.  All we have to do now is start pushing.  Sizzle is a start.  Who will take the next step, and the step after that?

The Missing Link

One of the few things I think XHTML2 got absolutely, totally, 125% right was freeing the href attribute from the few elements that accepted it and spreading it all over the language.  It saddens me that this isn’t happening in HTML5, especially since at least 1.5 of the four reasons given seem off base or flat-out incorrect.  From where I stand, at any rate.

Here, let me explain by having a pseudo-dialogue with the four reasons.

It isn’t backwards compatible with existing browsers.

Neither was CSS, table markup, PNG support, or any number of other worthwhile advancements in the web.  And yes, table markup was an absolutely worthwhile advancement: previous to that, the only way to have a table of data that lined up in any fashion was to space-format it and throw the whole thing into a pre element.  Ugly nonsemantic fun!

For that matter, if lack of backwards compatibility is an accepted reason to exclude something from HTML5, then a whole bracket of new elements—like, say, nav, article, aside, dialog, section, time, progress, meter, figure, video, datagrid, header, footer, need I go on?—need to come out of the specification right now.  They’re totally unsupported, and may not even be stylable, by older browsers.

(Yes, I just proposed that the term for a group of elements be a “bracket”.  A pod of whales, a flock of seagulls, a bracket of elements.  Try it out, see how it feels on the tongue.  A little angular, perhaps?  Don’t worry, you’ll get used to it.)

It adds no new functionality that can’t already be achieved using the a element.

What?  What?!?

Given a table where each row contains several cells of of summary data, and there is a desire to be able to click on a row to get more detailed information via a search keyed off that summary information, please explain to me how being able to use <tr href="..."> on each row as opposed to writing a whole bunch of JavaScript to associate a click event listener and delegation code and handler functions and target assembly logic just to simulate what <tr href="..."> would do, were it permitted, constitutes “no new functionality”.  Please.  I would love to hear that one.

Unless of course HTML5 is going to let us wrap a elements around whatever arbitrary collection of elements we like, in which case, never mind.  I’ll just wrap all my trs in as and be done with it.  That’d be keen.  Will that be possible?  Will the HTML5 syntax be so flexible as to permit that?

Yeah, that’s what I thought.

Not that I spent half the week banging my head against this problem and getting a bunch of hand-holding in the arcana of JavaScript and inconsistent browser event handling just to address what twenty-five seconds or so would have sufficed to resolve in an href-everywhere world or anything.

And for the flip side of this, see Wilson Miner’s “Accessible Data Visualization with Web Standards“, where a bar graph is built out of spans so that they can all be wrapped in an a element in order to let you click on any “row”—that is, what would have been a row had he been able to use table markup—and get more information.  Yes, absolutely, all that stuff should be in a table, but it was a case of have a table with a bunch of not-that-easy JS forced onto it, or have the contents of every cell in a row be a separate hyperlink to the same destination, or do simple markup with savaged semantics.  We shouldn’t be forced into that choice.

It doesn’t make sense for all elements, such as interactive elements like input and button, where the use of href would interfere with their normal function.

True enough.  So don’t add it to those elements which would suffer, like input and button.  Or, alternatively, define behavior conflict resolution in those cases.  There might actually be good reasons to have button accept an href value as a fallback in cases where the normal function of the button fails in some manner.

Either way, the fact that adding href doesn’t work in some cases is no reason to forgo its addition in all cases.

Browser vendors have reported that implementing it would be extremely complex.

I’m always willing to hear why implementors think something is complex to implement, as they’re often subtle and fascinating insights into web browser development.  Still, it seems to me that everything ubiquitous href attribution would imply can be recreated with a heavy dose of JavaScript event handlers and related code—(on)click for the sending you off to the target (and any :active-style effects you wanted to bring in), (on)mouseover or plain old :hover for the interactive effects, et cetera, et cetera.  Are they really saying that it’s more complex to support this sort of thing in markup than it is to support all the scripting and DOMiness that permits people to laboriously recreate it on their own?  If so, why?  I’m really curious to know what would make this “extremely complex”, which sounds a good deal more dire than “complex” or just plain old “difficult”.

I’m open to having my mind changed by strong evidence that this would be borderline impossible to implement, even though it can apparently be simulated via existing DOM/JS implementations.  Anything short of that, however, isn’t going to convince me that this should be dropped.  It was a good idea when it was in XHTML2, and it shouldn’t be abandoned if there’s any chance to save it.

line-height: abnormal

When I first wrote Cascading Style Sheets: The Definitive Guide, the part that caused me the most difficulty and headaches was the line layout material.  Several times I was sure I had it all figured out and accurately described, only to find out I was wrong.  For two weeks I corresponded with Ian Hickson and David Baron, arguing for my understanding of things and having them show me, in merciless detail, how I was wrong.  I doubt that I will ever stop owing them for their dedication to getting me through the wilderness of my own misunderstandings.

Later on, I produced a terse description of line layout which went through a protracted vetting process with the CSS Working Group and the members of www-style.  At the time it was published, there was no more detailed and accurate description of line layout available.  Even at that, corrections trickled in over the years, which made me think of it as my own tiny little The Art of Computer Programming.  Only without the small monetary reward for finding errors.

The point here is that line layout is very difficult to truly understand—even given everything I just said, I’m still not convinced that I do—and that there are often surprises lurking for anyone who goes looking into the far corners of how it happens.  As I’ve said before, my knowledge of what goes into the layout of lines of text imparts a sense of astonishment that any page can be successfully displayed in less than the projected age of the universe.

Why bring all this up?  Because I went and poked line-height: normal with a stick, and found it to be both squamous and rugose.  As with all driven to such madness, I now seek, grinning wildly, to infect others.

Here’s the punchline: the effects of declaring line-height: normal not only vary from browser to browser, which I had expected—in fact, quantifying those differences was the whole point—but they also vary from one font face to another, and can also vary within a given face.

I did not expect that.  At least, not consciously.

My work, let me show it to you: a JavaScript-driven test file where you can pick from a list of fonts and see what happens at a variety of sizes.  (Yes, the JS is completely obtrusive; and yes, the JS is the square of amateur hour.  Let’s move on, please.  I’m perfectly happy to replace what’s there with unobtrusive and sharper JS, as long as the basic point of the page, which is testing line-height: normal, is not compromised.  Again, moving on.)

When you first go to the test, you should (I hope) see a bunch of rulered boxes containing text using the very common font face Webdings, set at a bunch of different font sizes.  The table shows you how tall the simple line boxes are at each size, and therefore the numeric equivalent for line-height: normal at those sizes.  So if a line box is using font-size: 50px and the line box is 55 pixels tall, the numeric equivalent for line-height: normal is 1.1 (55 divided by 50).

On my PowerBook, Webdings always yields a 1:1 ratio between the font-size and line box height.  The ten-pixel font size yields a ten-pixel-tall line box, and so on.

This is actually a little surprising by itself.  The CSS 2.1 specification says:

normal
Tells user agents to set the used value to a “reasonable” value based on the font of the element. The value has the same meaning as <number>. We recommend a used value for ‘normal’ between 1.0 to 1.2. The computed value is ‘normal’.

This is basically what CSS has said since its first days (see the equivalent text in CSS1 or in CSS2 for confirmation) and there’s always been a widespread assumption that, since 1.0 is probably too crowded, something around 1.2 is much more likely.

So finding a value of 1 was a surprise.  It was an even bigger surprise to me that this held true in Camino 1.5.2, Firefox 2.0.0.14, and Safari 2.0.4, all on OS X.  Firefox 3b5 didn’t render Webdings at all, so I don’t know if it would do the same.  I actually suspect not, for reasons best left for another time (and, possibly, a final release of Firefox 3).

Various browsers doing the same thing in an under-specified area of the spec?  That can’t be right.  It’s pretty much an article of faith that given the chance to do anything differently, browsers will.  The sailing was so unexpectedly smooth that I immediately assumed was that a storm lurked just over the horizon.

Well, I was right.  All I had to do was start picking other font faces.

To start, I picked the next font on the list, Times New Roman, and the equivalent values for normal immediately changed.  In other words, the numeric equivalents for Times New Roman are different than those for Webdings.  The browsers weren’t maintaining a specific value for normal, but were altering it on a per-face basis.

Now, this is legal, given the way normal is under-specified.  There’s room to allow for this behavior.  It’s actually, once you think about it, a fairly good thing from a visual point of view: the best default line height for Times New Roman is probably not the best default line height for Courier New.  So while I was initially surprised, I got over it quickly.  The seemingly obvious conclusion was that browsers were actually respecting the fonts’ built-in metrics.  This was reinforced when I found that the results were exactly the same from browser to browser.

Then I looked more closely at the numbers, and confusion set back in.  For Times New Roman, I was getting values of 1.1, 1.12, 1.16, 1.15, 1.149, and 1.1499.  If you were to round all of those numbers to two decimal points, you’d get 1.10, 1.12, 1.16, 1.15, 1.15, 1.15.  If you round them all to one decimal place, you’d get 1.1, 1.1, 1.2, 1.2, 1.1, 1.1.  They’re inconsistent.

But wait, I thought, I’m trying to compare numbers I derived by dividing pixels by pixels.  Let’s turn it around.  If I multiply the most precise measurement I’ve gotten by the various font sizes, I get… carry the two… 11.499, 28.7475, 57.495, 114.99, 1149.9, 11499.  As compared to the actual values I got, which were 11, 28, 58, 115, 1149, and 11499.

Which means the results were inappropriately rounded up in some cases and down in others.  28.7475 became 28 and 1149.9 became 1149, whereas 57.495 became 58.  Even though 11.499 became 11 and 114.99 became 115.

This was consistent across all the browsers I was testing.  So again, I was suspecting the fonts themselves.

And then I switched from Times New Roman to just plain old Times, and the storm was full upon me.  I’ll give you the results in a table.

Derived normal equivalents for Times in OS X browsers
font-size Camino 1.5.2 Firefox 2.0.0.14 Safari 2.0.4
10 1 1.2 1.3
25 1 1 1.16
50 1 1 1.18
100 1 1 1.15
1000 1 1 1.15
10000 1 1 1.15

Much the same happened when comparing Courier New with plain old Courier: full consistency on Courier New between browsers, albeit with the same strange (non-)rounding effects as seen with Times New Roman; but inconsistency between browsers on plain Courier—with Camino yielding a flat 1 down the line, Firefox going from 1.2 to 1, and Safari having a range of values above the others’ values.

Squamous!  Not to mention rugose!

Now it’s time for the stunning conclusion that derives from all this information, which is: not here.  Sorry.  So far all I have are observations.  I may turn all this into a summary page which shows the results for all the font faces across multiple browsers and platforms, but first I’ll need to get those numbers.

I do have a few speculations, though:

  1. Firefox’s inconsistency within font faces (see Times and Courier, above) may come from face substitution.  That’s when a browser doesn’t have a given character in a given face, so it looks for a substitute in another face.  If Firefox thinks it doesn’t have 10-pixel Times, it might substitute 10-pixel something else serif-ish, and that face has different line height characteristics than Times.  I don’t know what that other face might be, since it’s not Times New Roman or Georgia, but this is one possibility.  It is not the minimum font size setting in the preferences, as I’ve triple-checked to make sure I have that set to “None”.

  2. Another possibility for Firefox’s line height weirdness is a shift from subpixel font rendering to pixelly font rendering.  10-pixel text in Firefox is distinctly pixelly compared to the other browsers I tested, while sizes above there are nice and smooth.  Why this would drive up the line height by two pixels (20%), though, is not clear to me.

  3. Much of what I’ve observed will likely be laid to rest at the doorsteps of the font faces themselves.  I’d like to know how it is that the rounding behaviors are so (mathematically) messed up within faces, though.  Perhaps ideal line heights are described as an equation rather than a simple ratio?

Again, this was all done in OS X; I’ll be very interested to find out what happens on Windows, Linux, and other operating systems.  Side note for the Mac Opera fans warming up their flamethrowers: I’ve left Opera 9.27 for OS X out of this because it seems to cap font sizes at a size well below 1000, although this limit varied from one face to another.  Webdings and Courier capped at 507 pixels, whereas Courier capped at 574 pixels and Comic Sans MS stopped at 707 pixels.  I have no explanation, though doubtless someone will, but the upshot is that direct comparisons between Opera and the other browsers are impossible.  For sizes up to 100 pixels, the results were exactly consistent with Camino, if that means anything.

The one tentative conclusion I did reach is this: line-height: normal is a jumbled terrain of inconsistent behaviors, and it’s best avoided in any sort of precision layout work.  I’d already had that feeling, but at least now there’s some evidence to back up the feeling.

In any case, I doubt this is the last I’ll have to say on this particular topic.

Update 7 May 08: I’ve updated the test page with a fix from Ben Lowery so that it works in IE.  Thanks, Ben!  Now all I need is to add a way to type in any arbitrary font-family’s name, and we’ll have something everyone can use.  (Or else a way to use JavaScript to suck up the names of all the fonts installed on a machine and put them into the dropdown.  That would be cool, too.)

Crafting Ourselves

My referrers lit up recently due to Jonathan Snook’s article about CSS resets and how he doesn’t use them.  To Jonathan and all the doubters and nay-sayers out there, I have only one thing to say:

Good for you.

Seriously; no sarcasm or passive-aggressiveness intended.  If I thought my reset styles, or really anything I’ve ever published or advocated, was a be-all end-all ultimate solution for every designer and design that’s ever been and could ever be, I’d be long past due for six rounds on the receiving end of a clue-by-four.

Reset styles clearly work for a lot of people, whether as-is or in a modified form.  As I say on the reset page, those styles aren’t supposed to be left alone by anyone.  They’re a starting point.  If a thousand people took them and created a thousand different personalized style sheets, that would be right on the money.  But there’s also nothing wrong with taking them and writing your own overrides.  If that works for you, then awesome.

For others, reset styles are more of an impediment.  That’s only to be expected; we all work in different ways.  The key here, and the reason I made the approving comment above, is that you evaluate various tools by thinking about how they relate to the ways you do what you do—and then choose what tools to use, and how, and when.  That’s the mark of someone who thinks seriously about their craft and strives to do it better.

I’m not saying that craftsmen/craftswomen are those people who reject the use of common tools, of course.  I’m saying that they use the tools that fit them best and modify (or create) tools to best fit them, applying their skills and knowledge of their craft to make those decisions.  It’s much the same in the world of programming.  You can’t identify a code craftsman by whether or not they use this framework or that language.  You can identify them by how they decide which framework or language to use, or not use, in a given situation.

Craftsmanship is something I’ve been thinking about quite a bit recently, as has Joshua Porter.  I delivered a keynote address on that very topic just a few days ago in Minneapolis, and my thinking infuses both of the talks I’m giving next week at An Event Apart New Orleans.  I’ve started looking harder for evidence of it, both in myself and in what I see online, and I believe striving toward being a craftsman/craftswoman is an important process for anyone who chooses to work in this field.

Because this isn’t a field of straightforward answers and universal solutions.  We are often faced with problems that have multiple solutions, none of them perfect.  To understand what makes each solution imperfect and to know which of them is the best choice in the situation—that’s knowing your craft.  That’s being a craftsman/craftswoman.  It’s a never-ending process that is all the more critical precisely because it is never-ending.

So it’s no surprise that we, as a community, keep building and sharing solutions to problems we encounter.  Discussions about the merits of those solutions in various situations are also no surprise.  Indeed, they’re exactly the opposite: the surest and, to me, most hopeful sign that web design/development continues to mature as a profession, a discipline, and a craft.  It’s evidence that we continue to challenge ourselves and each other to advance our skills, to keep learning better and better how better to do what we love so much.

I wouldn’t have it any other way.

September 2014
SMTWTFS
August  
 123456
78910111213
14151617181920
21222324252627
282930  

Archives

Feeds

Extras