meyerweb.com

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

Archive: 'Standards' Category

Unsupportable Promises

Over the past year and a half, the CSS Working Group has been working on a CSS Conditional Rules Module Level 3 module.  Now, don’t get overexcited: this is not a proposal to add generalized, formal if/then/else or switch statements to CSS—though in a very limited way, it does just that.  This is the home of the @media rule, which lets you create if/then conditions with regard to the media environment.  It’s also the home of the @supports rule, which lets you…well, that’s actually more complicated than you might think.

I mean, what do you think @supports means?  Take a moment to formulate a one-line definition of your understanding of what it does, before moving on to the rest of this piece.

If you’ve never heard of it before and wonder how it works, here’s a very basic example:

body {background-color: white;}
@supports (background-color: cornflowerblue) {
	body {background-color: cornflowerblue;}
}

The idea is that if the browser supports that property:value combination, then it will apply the rule or rules found inside the curly brackets.  In this sense, it’s just like @media rules: if the conditions in the parentheses are deemed to apply, then the rules inside the declaration block are used.  The module refers to this ability as “feature queries”.

There are some logical combination keywords available: and, or, and not.  So you can say things like:

body {color: #222; background-color: white;}
@supports ((background-color: cornflowerblue) and (color: rgba(0,0,0,0.5))) {
	body {background-color: cornflowerblue; color: rgba(0,0,0,0.5);}
}

Okay, but what does that actually mean?  Here’s what the specification says:

A CSS processor is considered to support a declaration (consisting of a property and value) if it accepts that declaration (rather than discarding it as a parse error). If a processor does not implement, with a usable level of support, the value given, then it must not accept the declaration or claim support for it.

So in that first sentence, what we’re told is that “support” means “accepts [a] declaration” and doesn’t drop it on the floor as something it doesn’t recognize.  In other words, if a browser parses a property:value pair, then that qualifies as “support” for said pair.  Note that this sentence says nothing about what happens after parsing.  According to this, a browser could have a completely botched, partial, and generally unusable implementation of the property:value pair, but the act of recognizing means that there’s “support”.

But wait!  That second sentence adds an additional constraint, after a fashion: there must be “a usable level of support”, the lack of which means that a browser “must not…claim support”.  So not only must a browser parse a property:value pair, but support it to “a usable level”.

But what constitutes a “usable level”?  According to everyone who’s told me that I was wrong about vendor prefixes, any browser implementation of a feature should be complete and error-free.  Is that what’s required to be regarded as a usable level?  How about if the implementation has one known bug?  Three?  Ten?  Can any of them be severe bugs?  What about merely serious bugs?  What if two browsers claim usable support, and yet are not interoperable?

So.  How does the definition of @supports match the one-line definition I asked you to formulate, back at the beginning?  Are they exactly the same, or is there a difference?

I suspect that most people, especially those coming across @supports for the first time, will assume that the word means that a browser has complete, error-free support.  That’s the implicit promise.  Very few people think of “supports” as a synonym for “recognizes” (let alone “parses”).  There’s a difference, sometimes a very large one, between recognizing a thing and supporting it.  I’m sure that browser teams will do their best to avoid situations where a property:value pair is parsed but not well supported, but it’s only a matter of time before a “supported” pair proves to be badly flawed, or retroactively made wrong by specification changes.  Assuming that such things will be allowed, in an environment where @supports exists.

If feature queries were set with @feature, as media queries are set using @media, or even if the name were something along the lines of @parses or @recognizes, I’d be a lot less bothered.  The implicit promise would be quite a bit different.  What I feel like we face here is the exact inversion of vendor prefixes: instead of a marker for possible instability and a warning that preserves the possibility of changing the specification when needed, this pretends to promise stability and safety while restricting the WG’s ability to make changes, however necessary.  My instinct is that @supports will end up in the same place: abused, broken, and eventually reviled—except this time, there will be the extra bitterness of authors feeling that they were betrayed.

The Stinger

(In television, the “stinger” is the clip that plays during or just after the closing credits of a show.)

On Friday, the Web Standards Project announced its own dissolution.  I felt a lot of things upon reading the announcement, once I got over my initial surprise: nostalgia, wistfulness, closure.  And over it all, a deep sense of respect for the Project as a whole, from its inception to its peak to its final act.

In some ways, the announcement was a simple formalization of a longstanding state of affairs, as the Project has gradually grown quieter and quieter over the years, and its initiatives had been passed on to other, more active homes.  It was still impressive to see the group explicitly shut down.  I can’t think of the last time I saw a group that had been so influential and effective recognize that it was time to turn off the lights, and exit with dignity.  As they wrote:

Thanks to the hard work of countless WaSP members and supporters (like you), Tim Berners-Lee’s vision of the web as an open, accessible, and universal community is largely the reality. While there is still work to be done, the sting of the WaSP is no longer necessary. And so it is time for us to close down The Web Standards Project.

I have a long history with the WaSP.  Way, way back, deep in the thick of the browser wars, I was invited to be a member of the CSS Action Committee, better known as the CSS Samurai.  We spent the next couple of years documenting how things worked (or, more often, didn’t) in CSS implementations, and—and this was the clever bit, if you ask me—writing up specific plans of action for browsers.  The standards compliance reviews we published told browsers what they needed to fix first, not just what they were getting wrong.  I can’t claim that our every word was agreed with, let alone acted upon, but I’m pretty confident those reviews helped push browser teams in the right direction.  Or, more likely, helped browser teams push their bosses in the direction the teams already wanted to go.

Succumbing to a wave of nostalgia, I spent a few minutes trawling my archives.  I still have what I think is all the mail from the Samurai’s mailing list, run through Project Cool’s servers, from when it was set up in August 1998 up through June of 2000.  My archive totals 1,716 messages from the group, as well as some of the Steering Committee members (mostly Glenn Davis, though George Olsen was our primary contact during the Microsoft style sheets patent brouhaha of February 1999).  If I’m not reading too much into plain text messages over a decade old, we had a pretty great time.  And then, after a while, we were done.  Unlike the WaSP itself, we never really declared an end.  We didn’t even march off into the sunset having declared that the farmers always win.  We just faded away.

Not that that’s entirely a bad thing.  At a certain point, our work was done, and we moved on.  Still, I look back now and wish we’d made it a little more formal.  Had we done so, we might have said something like the WaSP did:

The job’s not over, but instead of being the work of a small activist group, it’s a job for tens of thousands of developers who care about ensuring that the web remains a free, open, interoperable, and accessible competitor to native apps and closed eco-systems. It’s your job now…

And so it is.  These last years have shown that the job is in very good hands.

“Never doubt that a small group of thoughtful, committed citizens can change the world. Indeed, it is the only thing that ever has.” said Margaret Mead.  I see now that the way those small groups truly change the world is by convincing the rest of the world that they are right, thus co-opting the world to their cause.  Done properly, the change makes the group obsolete.  It’s a lesson worth remembering, as we look at the world today.

I’m honored to have been a part of the WaSP, and I offer my deepest samurai bow of respect to its founders, its members, and its leaders.  Thank you all for making the web today what it is.

Sixth Annual Blue Beanie Day

I just recently stumbled across a years-ago post where I said, almost as an aside:

Web design isn’t like chemistry, where the precipitate either forms or it doesn’t. If chemical engineers had to work in conditions equivalent to web developers, they’d have to mix their solutions in several parallel universes, each one with different physical constants, and get the same result in all of them.

While that’s still true, the constants are a lot less divergent these days.  The parallel universes that are web browsers are much closer to unity than once they were.

Remember those days?  When major web sites had a home page with two links: one for Netscape users to enter, the other for IE users?

Madness.

We know better now, of course.  Thanks to early pioneers like the organizers of the Web Standards Project, the path of web development was bent to a much saner course.  We still have little glitches and frustrations, of course, but it could be so unimaginably worse.  We know that it could be, because it was, once.

Along the way, the book cover of my friend and business partner’s book, Designing With Web Standards, gave rise to Blue Beanie Day, the day on which we give visible presence to our solidarity with the idea that web standards make possible the web as we know it.  Pictures go up on Twitter, Instagram, and Flickr with the tag #bbd12, and can be added to the Flickr group if you post there.

In this rapidly unfolding age of multiple device platforms and web access experiences, standards are more important than ever, even as they come under renewed pressure.  There will always be those who proclaim that standards are a failed process, an obstruction, an anachronism.  The desire to go faster and be shinier will always tempt developers to run down proprietary box canyons.

But so too will there always be those of us who remember the madness that lies that way.  Come November 30th, thousands of us will don our blue beanies.  I hope you’ll be among us.

Image © Kevin Cornell.  Used with permission.

Pricing ‘CSS:The Definitive Guide’

When I announced the serial publication of CSS: The Definitive Guide, Fourth Edition, I failed to address the question how pricing will work.  Well, more decided to break it out into its own post, really.  As it turns out, there are two components to the answer.

First component is the pricing of the pre-books.  Roughly speaking, each pre-book will be priced according to its length.  The assumed base for the electronic version is $2.99, and $7.99 for the print version, with significantly longer pre-books (say, one where two chapters are combined) priced somewhat higher.  How much higher depends on the length.  It’s possible that prices will drift a bit over time as production or printing costs change, but there’s no way to guarantee that.  We’re basically pricing them as they come out.

At the end of the process, when all the chapters are written and bundled into an omnibus book edition, there will be discounts tied to the chapters you’ve already purchased.  The more chapters you bought ahead, the deeper the discount.  If you bought the pre-books direct from O’Reilly, then you’ll automatically get a discount code tailored to the number of pre-book you’ve already bought.  If you bought them elsewhere, then O’Reilly’s customer service will work to create a comparable discount, though that will obviously be a slower process.

The second component is: how much will the codes cut the price of the final, complete book?  That I cannot say.  The reason is that I don’t know (nor does anyone) what minimum price O’Reilly will need to charge to cover its costs while taking into account the money already paid.  I’m hopeful that if you bought all of the pre-books, then the electronic version of the final book will be very close to free, but again, we have to see where things stand once we reach that point.  It might be that the production costs of the complete book mean that it’s still a couple of bucks even at the deepest discount, but we’ll see!  One of the exciting things about this experiment is that even my editor and I don’t know exactly how it will all turn out.  We really are forging a new trail here, one that I hope will benefit other authors—and, by direct extension, readers—in the future.

‘CSS: The Definitive Guide’, Fourth Edition

I’m really excited to announce that CSS: The Definitive Guide, Fourth Edition, is being released one piece at a time.

As announced last week on the O’Reilly Tools of Change for Publishing blog, the next edition of CSS:TDG will be released chapter by chapter.  As each one is finished, it will go into production right away instead of waiting for the entire omnibus book to be completed.  You’ll be able to get each standalone as an e-book, a print-on-demand paper copy, or even as both if that’s how you roll.  I’ve taken to calling these “pre-books”, which I hope isn’t too confusing or inaccurate.

There are a lot of advantages to this, which I wrote about in some detail for the TOC post.  Boiled down, they are: accuracy, agility, and à la carte.  If you have the e-book version, then updates can be downloaded for free as errata are corrected or rewrites are triggered by changes to CSS itself.  And, of course, you can only buy the pre-books that interest you, if you don’t feel like you need the whole thing.

I should clarify that not every pre-book is a single chapter; occasionally, more than one chapter of the final product will be bundled together into a single pre-book.  For example, Selectors, Specificity, and the Cascade is actually chapters 2 and 3 of the final book combined.  It just made no sense to sell them separately, so we didn’t.  “Values, Units, and Colors”. on the other hand, is Chapter 4 all by itself.  (So if anyone was wondering about the pricing differences between those two pre-books, there’s your explanation.)

If you want to see what the e-book versions are like, CSS and Documents (otherwise known as Chapter 1) has been given the low, low price of $0.00.  Give it a whirl, see if you like the way the pre-books work as bits.

My current plan is to work through the chapters sequentially, but I’m always willing to depart from that plan if it seems like a good idea.  What amuses me about all this is the way the writing of CSS: The Definitive Guide has come to mirror CSS itself—split up into modules that can be tackled independently of the others, and eventually collected into a snapshot tome that reflects a point in time instead of an overarching version number.

Every pre-book is a significantly updated version of their third-edition counterparts, though of course a great deal of material has stayed the same.  In some cases I rewrote or rearranged existing sections for greater clarity, and in all but “CSS and Documents” I’ve added a fair amount of new material.  I think they’re just as useful today as the older editions were in their day, and I hope you’ll agree.

Just to reiterate, these are the three pre-books currently available:

  • CSS and Documents (free) — the basics of CSS and how it’s associated with HTML, covering things like link and style as well as obscure topics like HTTP header linking
  • Selectors, Specificity, and the Cascade — including all of the level 3 selectors, examples of use, and how conflicts are resolved
  • Values, Units, and Colors — fairly up to date, including HSL/HSLa/RGBa and the full run of X11-based keywords, and also the newest units except for the very, very latest—and as they firm up and gain support, we’ll add them into an update!

As future pre-books come out, I’ll definitely announce them here and in the usual social spaces.  I really think this is a good move for the book and the topic, and I’m very excited to explore this method of publishing with O’Reilly!

Defining ‘ch’

I’m working my way through a rewrite of Two Salmon (more on that anon), and I just recently came to the ch unit.  Its definition in the latest CSS Values and Units module is as follows:

ch unit

Equal to the advance measure of the “0″ (ZERO, U+0030) glyph found in the font used to render it.

…and that’s it.  I had never heard the term “advance measure” before, and a bit of Googling for font "advance measure" only led me to copies of the CSS Values and Units module and some configuration files for the Panda 3D game engine.  So I asked the editor and it turns out that “advance measure” is a CSS-ism that corresponds to the term “advance width”, which I had also never heard before but which yielded way more Google results.  Wikipedia’s entry for “Font” has this definition:

Glyph-level metrics include … the advance width (the proper distance between the glyph’s initial pen position and the next glyph’s initial pen position)…

My question for the font geeks in the room is this:  is that the generally accepted definition for “advance width”?  If not, is there a better definition out there; and if so, where?  I’d like to be able to recommend the best known definition for inclusion in the specification; or, if there’s no agreement as to the best, then at least a good one.  The Wikipedia definition certainly sounds good, assuming it’s accurate.  Is it?

In CSS terms, if I’ve understood things correctly, 1ch is equal to the width of the character box for the glyph for “0”.  In other words, if I were to create a floated element with just a “0” and no whitespace between it and the element’s open and close tags, then the float’s width would be precisely 1ch.  But that’s if I’ve understood things correctly.  If I haven’t, I hope I’ll be corrected soon!

Linear Gradient Keywords

Linear gradients in CSS can lead to all kinds of wacky, wacky results—some of them, it sometimes seems, in the syntax itself.

Let me note right up front that some of what I’m talking about here isn’t widely deployed yet, nor for that matter even truly set in stone.  Close, maybe, but there could still be changes.  Even if nothing actually does change, this isn’t a “news you can use RIGHT NOW” article.  Like so much of what I produce, it’s more of a stroll through a small corner of CSS, just to see what we might see.

For all their apparent complexity, linear gradients are pretty simple.  You define a direction along which the gradient progresses, and then list as many color stops as you like.  In doing so, you describe an image with text, sort of like SVG does.  That’s an important point to keep in mind:  a linear (or radial) gradient is an image, just as much as any GIF or PNG.  That means, among other things, that you can mix raster images and gradient images in the background of an element using the multiple background syntax.

But back to gradients.  Here’s a very simple gradient image:

linear-gradient(45deg, red, blue)

The 45deg defines the gradient line, which is the line that defines how the gradient progresses.  The gradient line always passes through the center of the background area, and its specific direction is declared by you, the author.  In this case, it’s been declared to point toward the 45-degree angle.  red and blue are the color stops.  Since the colors don’t have stop distances defined, the distances are assumed to be 0% and 100%, respectively, which means you get a gradient blend from red to blue that progresses along the gradient line.

You can create hard stops, too:

linear-gradient(45deg, green 50%, lightblue 50%)
Figure 1

That gets you the result shown in Figure 1, to which I’ve added (in Photoshop) an arrow showing the direction of the gradient line, as well as the centerpoint of the background area.  Each individual “stripe” in the gradient is perpendicular to the gradient line; that’s why the boundary between the two colors at the 50% point is perpendicular to the gradient line.  This perpendicularness is always the case.

Now, degrees are cool and all (and they’ll be changing from math angles to compass angles in order to harmonize with animations, but that’s a subject for another time), but you can also use directional keywords.  Two different kinds, as it happens.

The first way to use keywords is to just declare a direction, mixing and matching from the terms top, bottom, right, and left.  The funky part is that in this case, you’re declaring the direction the gradient line comes from, not that toward which it’s going; that is, you specify its origin instead of its destination.  So if you want your gradient to progress from the bottom left corner to the top right corner, you actually say bottom left:

linear-gradient(bottom left, green 50%, lightblue 50%)
Figure 2

But bottom left does not equal 45deg, unless the background area is exactly square.  If the area is not square, then the gradient line goes from one corner to another, with the boundary lines perpendicular to that, as shown in Figure 2.  Again, I added a gradient line and centerpoint in Photoshop for clarity.

Of course, this means that if the background area resizes in either direction, then the angle of the gradient line will also change.  Make the element taller or more narrow, and the line will rotate counter-clockwise (UK: anti-clockwise); go shorter or wider and it will rotate clockwise (UK: clockwise).  This might well be exactly what you want.  It’s certainly different than an degree angle value, which will never rotate due to changes in the background’s size.

The second way to use keywords looks similar, but has quite different results.  You use the same top/bottom/left/right terms, but in addition you prepend the to keyword, like so:

linear-gradient(to top right, green 50%, lightblue 50%)
Figure 3

In this case, it’s clear that you’re declaring the gradient line’s destination and not its origin; after all, you’re saying to top right.  However, when you do it this way, you are not specifying the top right corner of the background area.  You’re specifying a general topward-and-rightward direction.  You can see the result of the previous sample in Figure 3; once more, Photoshop was used to add the gradient line.

Notice the hard-stop boundary line.  It’s actually stretching from top left to bottom right (neither of which is top right).  That’s because with the to keyword in front, you’re triggering what’s been referred to as “magic corners” behavior.  When you do this, no matter how the background area is (re)sized, that boundary line will always stretch from top left to bottom right.  Those are the magic corners.  The gradient line thus doesn’t point into the top right corner, unless the background area is perfectly square—it points into the top right quadrant (quarter) of the background area.  Apparently the term “magic quadrants” was not considered better than “magic corners”.

The effect of changing the background area’s size is the same as before; decreasing the height or increasing the width of the background area will deflect the gradient line clockwise, and the opposite change to either axis will produce the opposite deflection.  The only difference is the starting condition.

Beyond all this, if you want to use keywords that always point toward a corner, as in Figure 2 except specifying the destination instead of the origin, that doesn’t appear to be an option.  Similarly, neither can you declare an origin quadrant.  Having the gradient line always traverse from corner to corner means declaring the origin of the gradient line (Figure 2).  If you want the “magic corners” effect where the 50% color-stop line points from corner to corner, with the gradient line’s destination flexible, then you declare a destination quadrant (Figure 3).

As for actual support:  as of this writing, only Firefox and Opera support “magic corners”.  All current browsers—in Explorer’s case, that means IE10—support angles and non-magic keywords, which means Opera and Firefox support both keyword behaviors.  Nobody has yet switched from math angles to compass angles.  (I used 45deg very intentionally, as it’s the same direction in either system.)

That’s the state of things with linear gradients right now.  I’m interested to know what you think of the various keyword patterns and behaviors—I know I had some initial trouble grasping them, and having rather different effects for the two patterns seems like it will be confusing.  What say you?

Firefox Failing localStorage Due to Cookie Policy

I recently stumbled over a subtle interaction between cookie policies and localStorage in Firefox.  Herewith, I document it for anyone who might run into the same problem (all four of you) as well as for you JS developers who are using, or thinking about using, locally stored data.  Also, there’s a Bugzilla report, so either it’ll get fixed and then this won’t be a problem or else it will get resolved WONTFIX and I’ll have to figure out what to do next.

The basic problem is, every newfangled “try code out for yourself” site I hit is just failing in Firefox 11 and 12.  Dabblet, for example, just returns a big blank page with the toolbar across the top, and none of the top-right buttons work except for the Help (“?”) button.  And I write all that in the present tense because the problem still exists as I write this.

What’s happening is that any attempt to access localStorage, whether writing or reading, returns a security error.  Here’s an anonymized example from Firefox’s error console:

Error: uncaught exception: [Exception... "Security error"  code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)"  location: "http://example.com/code.js Line: 666"]

When you go to line 666, you discover it refers to localStorage.  Usually it’s a write attempt, but reading gets you the same error.

But here’s the thing: it only does this if your browser preferences are set so that, when it comes to accepting cookies, the “Keep until:” option is set to “ask me every time”.  If you change that to either of the other two options, then localStorage can be written and read without incident.  No security errors.  Switch it back to “ask me every time”, and the security errors come back.

Just to cover all the bases regarding my configuration:

  1. Firefox is not in Private Browsing mode.
  2. dom.storage.default_quota is 5120.
  3. dom.storage.enabled is true.

Also:  yes, I have my cookie policy set that way on purpose.  It might not work for you, but it definitely works for me.  “Just change your cookie policy” is the new “use a different browser” (which is the new “get a better OS”) and it ain’t gonna fly here.

To my way of thinking, this behavior doesn’t conform to step one of 4.3 The localStorage attribute, which states:

The user agent may throw a SecurityError exception instead of returning a Storage object if the request violates a policy decision (e.g. if the user agent is configured to not allow the page to persist data).

I haven’t configured anything to not persist data—quite the opposite—and my policy decision is not to refuse cookies, it’s to ask me about expiration times so I can decide how I want a given cookie handled.  It seems to me that, given my current preferences, Firefox ought to ask me if I want to accept local storage of data whenever a script tries to write to localStorage.  If that’s somehow impossible, then there should at least be a global preference for how I want to handle localStorage actions.

Of course, that’s all true only if localStorage data has expiration times.  If it doesn’t, then I’ve already said I’ll accept cookies, even from third-party sites.  I just want a say on their expiration times (or, if I choose, to deny the cookie through the dialog box; it’s an option).  I’m not entirely clear on this, so if someone can point to hard information on whether localStorage does or doesn’t time out, that would be fantastic.  I did see:

User agents should expire data from the local storage areas only for security reasons or when requested to do so by the user.

…from the same section, which to me sounds like localStorage doesn’t have expiration times, but maybe there’s another bit I haven’t seen that casts a new light on things.  As always, tender application of the Clue-by-Four of Enlightenment is welcome.

Okay, so the point of all this: if you’re getting localStorage failures in Firefox, check your cookies expiration policy.  If that’s the problem, then at least you know how to fix it—or, as in my case, why you’ll continue to have localStorage problems for the next little while.  Furthermore, if you’re writing JS that interacts with localStorage or a similar local-data technology, please make sure you’re looking for security exceptions and other errors, and planning appropriate fallbacks.

April 2014
SMTWTFS
March  
 12345
6789101112
13141516171819
20212223242526
27282930  

Archives

Feeds

Extras