Tab Completion

I'm Tab Atkins Jr, and I wear many hats. I work for Google on the Chrome browser as a Web Standards Hacker. I'm also a member of the CSS Working Group, and contribute to several other working groups in the W3C.
Listing of All Posts

Media Queries Can't Be Used for Resolution Negotiation

Or, why any Responsive Images solution based solely on MQs is doomed to failure.

tl;dr

Good, user-friendly behavior for deciding which resolution to send depends on several factors, which are difficult to get right. One of the major considerations, bandwidth, is variable, which means you can flip from "high" to "low" within a page load, You don't want to throw away the "high" images and request the "low" ones in this case (as that's ridiculous and user-hostile) but that's precisely what using Media Queries would require.

Let's Get Things Clear

One of the major use-cases for Responsive Image (though, unfortunately, not really one addressed by the Responsive Images CG) is the ability to send high-res images to high-DPI screens like the iPhone "retina" screen, while still sending normal images to everyone else.

Unfortunately, "has a high-DPI screen" isn't the only thing you want to be concerned about. High-DPI images are much larger than normal images (generally, one with double DPI will be four times the size), so you'd also like to segregate this by bandwidth somehow, so phones on shitty connections get the normal image quickly, instead of the high-res image slowly.

You may even want to go further, so that initial page-loads on mobile devices that are initially pretty zoomed out get an even lower resolution, lower than normal, just to make it happen even faster.

Already, we're looking at enough factors that it seems difficult to fit Media Queries to the solution. A good interaction with the user requires some pretty subtle reasoning and careful set-up of the queries. (Not to mention, it depends on several types of queries that don't currently exist.)

A Bandwidth Media Query

Now, let's just look at the hypothetical bandwidth query itself. Unfortunately, the concept is probably fatally flawed.

For one, bandwidth is complicated. It's not just a bit rate - latency is very important. Most of the time, phones can get a pretty good download rate, but their latency is terrible, so your goal above all else should be to minimize network requests, and not care as much about filesize.

That ties into the next point - bandwidth is variable. On a desktop, you might get "burst" speeds at the beginning of a page load, then significantly more restricted bandwidth after a second or so. A phone can start loading a page on a speedy 4G connection, but then get carried into an elevator that drops them into Edge mode.

If the bandwidth available changes, a hypothetical bandwidth query will change as well. You'll flip from "high" to "low", and thus flip from saying "use this high-res image" to "use this low-res image".

Whoops! This literally means "throw away that high-res image you've already downloaded, and pull down this low-res image instead". That's exactly what you don't want; the user is in a low-bandwidth situation, so you don't want to force them to make more requests for resources they already have better versions of. Unfortunately, Media Queries are stateless, so you can't say "request the low-res image, unless you've already finished getting the high-res version". Even if you could hack in a patch for this one case, what do you do about all the other properties that might be applied by the MQ?

More importantly, what about when you switch from "low" to "high"? Should you keep the current low-res image, or should you go ahead and request the good ones? Unlike the other case, both options are potentially reasonable. Which one is correct for the situation might be based on a prediction of whether you'll stay in high-bandwidth mode, or other subtle factors that are even more difficult to express in MQs.

In Other Words

You simply can't make a good decision about which resolution to send to the user based on information from Media Queries. It's fundamentally a hard decision based on information that's difficult to expose in a reasonable manner.

As such, any Responsive Image solutions that concentrate on using MQs to decide between images can not solve this use-case. This is a pretty important one, so you can't just ignore it.

It seems that the best way to solve this is to just announce to the browser what the resolutions of your URLs are, and let the browser decide which one to request based on its own heuristics. This pushes all the difficulty into a single, centralized place with access to all the necessary information, and lets browsers make the decision they think best across all pages.

Last updated:

Untitled

meticulous planning
tenacity spanning
decades of denial
is simply why i'll
be king undisputed
respected, saluted
and seen for the wonder i am

yes my teeth and ambitions are bared

Be prepared.

~Bartonesque

Last updated:

Why I'm Excited about Names in JavaScript

There's a ton of exciting activity taking place in TC39, which is the standards group responsible for handling JavaScript (known as ECMAScript there, as ECMA is the standards body that TC39 is part of). One in particular that I like quite a bit is Names. It's not very obvious why this is so good, though, or what advantages these have over other, similar proposals or similar features in other languages.

The Hell are Names?

You know how you access properties on an object with strings? In the Names proposal, you can additionally use a Name object to access properties. This is important, because Name objects are unique and unforgeable. In other words, unless someone gives you the Name object, there is no possible way for you to access that property.

There's another aspect, which is the ability to make some of these Names private. I'll distinguish the two by calling the original thing Unique Names, and the private things Private Names.

If you're familiar with the term "Object Capabilities", Names are a building block for that technology.

What's the Use of a Unique Name?

Having a guaranteed-unique name is wonderful. Many things that are cumbersome or even practically impossible without them become trivial once you have them.

If you're familiar with Lisp, unique names generated with GENSYM are absolutely necessary to write robust macros; without them, you stand a decent chance of accidentally colliding with existing names and breaking code in mysterious ways.

In JS, Unique Names are great for adding "interface" properties to an object. Let's say you define an Iterator interface, plus a bunch of functions that take Iterators and do cool stuff with them. When someone passes you an object, you want to check if it's an Iterator, and if not, ask it to give you an Iterator. For example, if someone passes you a string, you should be able to ask it for an iterator over the characters.

How do you ask for this, though? The simple answer is to say that objects need to have a particular method, getIterator() or __iterator() or something, that returns an iterator. This isn't great, though - what if they already have a property by that name that does something else?

Another way, if you have control over the language, would be to define a set of functions on something the language controls, like Object.setIterator(), Object.getIterator(), and Object.deleteIterator(), which maintain an internal map of classes to iterators. This is just plain cumbersome and ugly, though.

Using a Unique Name, though, this is easy! You just create a special Name and store it somewhere publicly accessible. When someone wants their object to expose an iterator, they just grab the Name you've created, and store their method using it. This'll look something like:

/* library code */
let Iterator = {
  ...
  getIterator: new Name()
}

/* user code */
function myCoolObject() { ... }
myCoolObject.prototype[Iterator.getIterator] = function(){...}

That's it! In the library, whenever a function that expects an iterator is passed something else, it'll first poke at the object using the Iterator.getIterator Name, and if it finds a function there, it'll just call that to extract an iterator.

The benefit of this little bit of indirection is that it's impossible for the user's class to have a property-collision with the Iterator library's property.

One can do even more extreme things, too. What if you want an object to be an iterator, rather than just provide one? (Analogous to the difference between PHP's Iterator and IteratorAggregate interfaces.) You need the object to expose a couple of properties; at minimum, you probably want something like .current, .valid, and .moveNext(). But, again, the object might already use those properties for something else! (This is especially true for names like this - 'current' and 'valid' are reasonably common property names.) Again, though, you can just use Unique Names for this, and in fact the method is exactly the same as before - just create some Names, store them in an easy-to-reach place, and then other classes can just grab and use those Names to store their implementations for you.

A final use of Unique Names - typing! Right now, there are two decent ways to ask an object what type it is - examine its prototype chain, or do "duck typing" (see if it exposes the properties you expect for the given type). Neither of these are great. Prototype-chain examining means you have to use inheritance for your objects, the sins of which are well-documented elsewhere. Duck typing is unreliable because objects can accidentally expose the properties you want without actually working the way you expect. Using Unique Names, though, we can resolve this. Again, just create a Unique Name and stash it somewhere. When an object wants to declare it's your type, it just takes that Name and sets it to true on itself. BAM, type checking is easy - if you check the property on a random object, you'll either get undefined or true based on whether it claims to be the type or not.

I'm sure there are plenty of other cool things in this vein, but my brain keeps getting twisted back to iterators, so you'll have to come up with them on your own.

Okay, But What About Those Private Names?

Private Names are just like Unique Names, except they've got some extra protections to avoid exposing them accidentally.

You'd think, from the name, that these might be useful for making private properties in JS, but you'd be wrong. JS already has private properties, through closures[1]:

(function(){
  let privateVar = 'foo';

  function Bar() {
    console.log("Hahaha, only I have access to the privateVar!");
    console.log("But I guess you can look at it:");
    console.log(privateVar);
  }
})();

What Private Names are good for is making protected variables, except ridiculously more flexibly and powerfully.

In most OO languages, if you want to have a property that's hidden to most, but available to some classes other than yourself, you have to mark it protected, and the other classes have to inherit from you. This is pretty horrible, because wanting to use something's private variables is not the same thing as wanting to inherit from it. Some languages like C++ have workarounds for this (the friend keyword in C++), but they're all pretty hacky.

Private Names let you hide properties from the public, and expose them to whoever you want - you just have to give them the corresponding Names. You can even expose different sets of properties to different consumers, just by handing out different subsets of your private Names. There's no need to tie this functionality into inheritance.

Here's yet another cool use. I'll assume you know about Proxies, those cool new JS things that let one object pretend to be another object by supplying functions that get called whenever you try and get a property, set a property, etc. on the Proxy. With that functionality, you can hide all details of what's going on underneath normal-looking syntax.

One use for Proxies is to supply someone with a limited-functionality version of an object. Make a Proxy object, store your original object in it, and make the proxy transparently supply the original object's properties if they're on a limited list, and block them (as if they aren't there at all) otherwise. This lets you supply a lesser interface for an object with a minimum of fuss, while still letting the actual object access all of itself.

This is somewhat limited, though. You have to hide the original object inside the Proxy object (or else there's not much point). Right now, that means you have to use a closure variable, as demonstrated above, to hide it so that only the Proxy's own functions can access it. This means, though, that if you pass the limited-functionality object back to the original API that gave it out, it can't extract the full-powered object back out again! (Any method you supply to allow it to do so would allow someone else to do this as well.) With Private Names, though, this concern disappears. You can just store the original object on the Proxy with a Private Name (storing the name itself both in your original API, and in a closure variable in the Proxy object), and then pull it back out again later with the same name, but no one else can access it! (Dave Herman points out another method to accomplish this.[2])

But What Actually Makes Private Names Different From Unique Names?

You're right, hidden-interlocutor-in-control-of-this-post's-titles, everything I described above can be done with Unique Names as well. The difference between the two is that Private Names have some different defaults set, and act differently with Proxies (in a different scenario than what I described above).

For starters, Unique Names are just ordinary properties; they just use Name objects instead of strings for their name. So, if you use a for-in loop to iterate through all the properties, you'll see properties that use Unique Names alongside all the string-named ones. On the other hand, properties using Private Names are automatically non-enumerable.

The other difference is their behavior with Proxies. When you set up a Proxy, you assign functions to several operations, like "get a property", which is called whenever someone performs that action on the Proxy. In the case of getting/setting a property, your function is passed the name of the property that's being get/set. If someone attempts to access a property on a Proxy using a Private Name, though, and the system naively passed it through, it would "leak" the name - the owner of the Proxy would then have your Private Name and could use it themselves.

Instead, Private Names automatically get a corresponding Unique Name when they're created. This is stored in the Private Name's .public property. When a Proxy attempts to deal with a Private Name, it instead receives the Private Name's public property. If the Proxy already has access to the Private Name, it can compare the .public is has with what it's received, but if it doesn't, then no private information is leaked. There's no linkage back from the public property to the corresponding Private Name; you can't use the Unique Name stored in the .public property for anything except comparisons.

Care to Wrap it Up?

In conclusion, Names are awesome. They let you do a lot of cool things that are difficult/hacky/impossible to do right now, and they're the building blocks for some important security tools like Object Capabilities.

Here's hoping they make it into JS in the nearish future!

[1]: Dave Herman, author of the current Private Names proposal, points out that Private Names do make private variables easier. If you want a per-instance closure variable, you also have to define all your methods per-instance, rather than defining them once on the prototype. This is hugely costly if you then create a lot of instances. Private Names let you accomplish this without pain:

(function(){
  let key = new Name();
  function Thingy(x) {
    this[key] = x;
  }
  Thingy.prototype = {
    doStuff: function() { ... this[key] ... }
  };
})();

[2]: Dave Herman points out another solution. Remember that Object.get/set/deleteIterator() thing I talked about earlier, where you maintain a hidden table of associations? Using WeakMaps, another upcoming feature which, among other things, lets you create a dictionary with object keys, you can create a side-table linking a given Proxy to its original object in the same way. Whether this is easier or harder than using Private Names may vary based on the individual case.

Last updated:

CSS Spec Terms, for Future Reference

I accidentally use some CSS terms interchangeably sometimes. I try to maintain discipline here, but not everyone even knows what the correct terms are, so they can't make themselves do it right.

I'll add to this list in the future as I come up with more stuff that occasionally confuses me.

rule or ruleset: A selector + braces combo, or an at-rule.

declaration block: A sequence of declarations.

declaration: A property + colon + value combo.

property value: The entire value of a property.

component value: A single piece of a property value. Like the 5px in text-shadow: 0 0 5px blue;. Can also refer to things that are multiple terms, like the 1-4 terms that make up the background-size portion of the background shorthand.

term: The basic unit of author-facing CSS, like a single number (5), dimension (5px), string ("foo"), or function. Officially defined by the CSS 2.1 grammar (look for the 'term' production)

outer : Refers to the margin box.

inner : Refers to the content box.

start/end/before/after: Refers to the logical directions, which are dependent on the 'direction' and 'writing-mode' properties. start and end are in the "inline" axis, the axis that a line of text is laid out in (horizontal in English text). Perpendicular to that, before and after are in the "block" axis, the axis that block elements are laid out in (vertical in English text).

simple selector: A single atomic selector, like a type selector, an attr selector, a class selector, etc.

compound selector: One or more simple selectors without a combinator. div.example is compound, div > .example is not.

complex selector: One or more compound selectors chained with combinators.

combinator: The parts of selectors that express relationships. There are four currently - the space (descendant combinator), the greater-than bracket (child combinator), the plus sign (next sibling combinator), and the tilda (following sibling combinator).

sequence of selectors: One or more of the named type of selector chained with commas.

inline: Something that participates in inline layout (it goes into lineboxes) and will break across lines, like <span>.

atomic inline: Something that participates in inline layout but doesn't break across lines, like <img> or anything with display:inline-block.

inline-level: Either inline or atomic inline.

block container: Something whose insides are formatted with block layout, like <div> or anything with display:inline-block.

block-level: Something that participates in block layout, like <div>.

block: A block-level block container.

Last updated:

TopatoCo is the Best, and You Should Buy Everything They Have

I just got this email today:

Someone is About to Get a Package From TopatoCo!

And that someone is Tab Atkins Jr! Tab is about to get a package in the mail from TopatoCo, former freelance hovercraft pilot training center turned world famous webcomic merchandise distributor! Basically we just wanted to let you know that your order 196811 has shipped and the tracking information follows (if available). Thank you so much!

Shipped on 9/16/2011 using USPS First Class: XXXXXXXXXXXXXXXXXXXX

If the shipment is USPS International Priority or First Class, the number above is NOT an actual tracking number, it is only a Customs ID for use in the event of a lost > package. Keep in mind none of these numbers become active in the UPS/USPS system until they actually grab them from us, which can take 24 hours and even longer on weekends.

USPS packages within the United States should arrive in 2-5 days, and UPS packages in the exact amount of time the tracking number indicates. Canadian deliveries should be expected anywhere between three days and two weeks, mostly depending on border activity.

If your package is destined for a distant, magical land it can take up to four weeks depending on how seriously the Customs Agent takes their job. We strongly urge you to familiarize yourself on any weird silliness your local mail delivery place might pull when receiving and delivering packages from the US Postal Service. USPS tracking is not available for international destinations (unless you paid for Express shipping), but all packages have Customs IDs that can sometimes be used to determine the approximate location of mischevious packages. If you need more information, please visit http://www.topatoco.com/help/ or write to support@topatoco.com. Thanks for supporting independent artists on the Inter-Tubes of CyyyyberSpace!

TopatoCo provides storefront and/or shipping services for the following independent creators. Learn more about them at http://www.topatoco.com/creators/

Sincerely, Holly, Kaliis, Jeffrey, Lucid John, and Wolfman Green http://www.topatoco.com

"TopatoCo. Occasionally Thinking About the Children, Then Quickly Thinking of Something Else."

This is why I love TopatoCo and all the wondrous things they sell. They sold me the always-popular and oh-so-comfy Fat Pony Tshirt, and this most recent email is announcing that I'm soon going to receive my personalized copy of the Dresden Codak Primer with some sort of sketch in it! Yay!

So yeah, go to TopatoCo and give them all your money. They're starving artists, and you're a good person, right? Good people support the arts.

Last updated:

Older Posts