Making icons less painful and murky


#1

One thing that has long irritated me is that page icons, unlike backgrounds, stylesheets, or pretty much any other resource that a page may load, do not follow Cache-Control-family directives like ETag or Expires to get reloaded when they change. Icons, for some reason, are only reloaded if and when their URL changes.

EDIT EDIT EDIT: Apparently this has something to do with icons being overlayed by the history system in Chrome, which just feels like all kinds of mistaken. But at least it’s not a platform-wide mistake.

There’s also the annoyance of having tons and tons of different standards for icons, and, of course, each browser has their own arbitrary selection criteria for which to use, leading to more resolution-specific icons and inexplicably separate new standards like manifest.json (which still has this render-proliferation problem). What we really need is a simple “downscale whatever rel="icon" implements a size above what you need, or upscale the largest if there isn’t one” rule, which is capable of handling all of these (letting authors just upload a 2048x2048 icon and call it a day).

On the subject of the “many different renders cascade”, we’re inexplicably supposed to host tons of different-resolution raster renders, for every possible display size of what is most likely the same icon. Past 32x32, there’s only so much hinting that’s realistically going to differentiate the images beyond just being differently-sized downscales of a larger source image - and the number of sizes we need to provide is doubling every year. It’d be more space- and transfer-efficient (both in terms of image size and definition size), not to mention smoother and more future-proof, to just be able to provide the vector source for icons. I could write a polyfill for this, too, but again, there’s no reason this can’t be implemented by the browsers themselves (since there are sufficient code paths to do this in userland).

TL;DR:

  1. Icon caching needs to follow the regular asset pipeline caching model.
  2. In the presence of links to multiple sizes and definitions matching multiple vendor-specific standards, precedence and selection for icon loading and usage behavior needs to be simplified, specified, standardized, and made polyfillable.
  3. Browsers need to learn how to use SVG icons. I shouldn’t have to upload a new set of renders to my server every time Apple releases a new iPhone with an all-unprecedented Super Retina 2 Turbo HD Tournament Edition Plus-Size screen resolution.

Unify metadata in a more understandable & performant fashion
#2

Here are my thoughts, in no good order - ideally these could be rewritten into a sensible order and specified in more strict spec-speak language:

Icon selection algorithm

Icons MUST be specified as <link> children of the document’s <head> with rules following the current HTML Standard. Beyond this, icons may be defined in any order - User Agents MUST NOT prioritize definition order over size in any way.

User-Agents have a “minimum viable resolution” (heretofore known as the MVR). (On a traditional desktop, this would be 16x16, on an Android phone running Chrome on Lollipop, this would be 192x192, etc.) If and only if no icons are specified in the head that provide at least the size of the MVR, User-Agents MAY look for icons in legacy vendor locations. For this reason, it is recommended that developers implement either a vector source with sizes="any", or a sufficiently large raster source, as a final fallback.

User-Agents MUST start by loading the icon defined by a link that is smallest while still being greater than the MVR. (For the purposes of this selection algorithm, “any” has an infinite size.)

Caveat: if an icon is defined that is smaller but “close” (by the UA’s assessment) to the MVR, and the next-largest would be “prohibitively large” (again by the UA’s assessment) to retrieve, the User-Agent MAY elect to upscale the “close” smaller icon (or display a reduced-size version with transparent margins). The User-Agent MUST NOT request undefined / vendor-specific locations as long as a larger icon is defined.

(Example a User-Agent with an MVR of 196px encounters a page with a 192px icon defined and a 9000px icon defined, that User-Agent MUST use either the 192px icon upscaled, or retrieve the 9000px icon. it MUST NOT look for /apple-touch-precomposed-196px.)

If an icon fails to load (eg. 404), User-Agents MUST re-enter this logic with that icon removed from the pool. User-Agents MUST retry loading that icon the next time the page is loaded.

If any icon link is specified without a size in the head, if no suitable links with sizes are specified, the first one MUST be retrieved before resorting to vendor icons. If, after retrieval, it is larger than the MVR, it MUST be downscaled using the User-Agent’s best-quality downscaling. If it is smaller than the MVR, User-Agents MAY search fo an alternative in legacy vendor locations.

manifest.json takes precedence only when a page is being “installed” in some way, in which case it is assumed that the User-Agent will retrieve all relative icon sizes needed to represent the icon in its interface (using the same downscale-next-largest logic).

(Maybe manifest.json could be used as an alternative in the event that no icon links are defined in <head> - that would be polyfillable.)

Vendors are strongly discouraged from implementing any new vendor-specific icon locations (read: plz no apple-touch-icon-973px in 2017).

Icon retrieval

Each page has a property (or method) like document.displayIcon that resolves to the URL of the icon that is being used to represent the page live. (Assigning to this property could set the href on the corresponding link element, or create one on demand if none is present.)

Icons are retrieved the same way as stylesheets, and are refreshed with the same logic.

(One thing that would be cool would be if the fetch(es) for this (these) resource(s) were also exposed, but the Fetch API isn’t sufficiently specced out to permit designing this yet AFAIK.)


#3

Plus, in the ~month since this was posted, Apple screwed up icons for every other user agent by defining a different kind of icon that is differentiated by an additional attribute on the element. (Isn’t there a rule somewhere in some spec that says “don’t add attributes to distinguish things that will otherwise be recognized as something undesirable by UAs that don’t recognize the attribute”? There should be.)


#4

On a related note, I’m building an extension right now that, as part of its functionality, displays pages’ icons, and it gets messed up by .ico images - Chrome can render them just fine, but it uses the largest sie defined (I think) and then downscales that to whatever size I’m using it at (I think? Maybe attributes fix this. Should experiment.)

This ends up looking ugly for stuff like Gitter, which uses a .ico with a 16x16 render and a 32x32, and the 32x32 does not cleanly downsample to 16x16.

Not sure what I want here: is there already a spec for selecting images from multi-image container formats (would also be relevant for TIFF etc)?


#5

I agree SVG icons for sizes beyond a certain scale are ideal. (Safari’s new Pinned Tabs seem to scale them down to 16×16 though, so maybe they stopped caring?)

With media queries it’s possible to “hint” SVGs so they look better at smaller sizes, but the only browser that uses SVG in favicons, Firefox, doesn’t run a full SVG renderer for resource reasons, so it doesn’t work in practice. Maybe it should? The W3C has been chewing on this, and their list of problems/use-cases is handy.

I’d love to scorch the earth and start over with something that doesn’t fill every <head> with identical <link>s, but I guess we’d have to do an HTML5 and figure out what in the hell browsers are currently already doing.


#6

I have no strong opinion on how icons should be declared. But I would like to emphasis an overlooked issue: design discrepancy across platforms.

My favorite is the difference between Android Chrome and iOS Safari. At first, they look very similar. Same kind of OS, same kind of devices and the same “Add to home screen” feature (ie. the ability to place a bookmark on the home screen, among native apps). Using the same icon seems to make a lot of sense. In practice, it’s not that clear. Google’s native apps icons (Maps, Agenda, YouTube…) are not square but use transparency, with a slight drop shadow. Using this kind of style for a webapp icon sounds like a good idea. But iOS prevents transparency for icons: submit a transparent Touch icon and iOS will fill the transparent regions with black. Better design two different icons after all.

At the moment, the most widely used mechanism to declare multi-platform icons is the link markup with the sizes attribute. And it is also the most annoying. Some desktop browsers tend to use the largest icon, which is often the 192x192 icon for Android Chrome (for prior versions which do not support manifest.json). Whereas the proprietary, unsatisfying Touch icon has the merit of being used by iOS (and platforms for which iOS look and feel is okay).

A set of icons which differ only by their resolution is not enough. Even a system based on platform type (eg. phone vs tablet vs desktop, or touch- vs non-touch-screen) is not enough. Although it would be convenient to be able to ship a one-size-fits-all icon, it is important to have the ability to provide a particular icon to a particular platform.

TL; DR:

It is not enough to pick the right icon solely with resolution. Each platform has its own design guidelines. It is important to be able to provide a particular icon to a particular platform.


#7

@phbernard has a good point: although I personally don’t like trying to cater my icons to individual platforms (partly due to exactly the problems he describes), I know this is a common design pattern (as seen in generators like https://realfavicongenerator.net/), and having these aesthetic differences entangled with resolution changes is unacceptable (and having a vendor-specific override like apple-touch-icon basically all the same problems with leaky semantics as vendor prefixing).

Perhaps there should be another attribute on link elements for icons (like the sizes attribute), like theme, which can contain a list of spec-defined keywords like primary, flat, skeumorphic, solid-white, and opaque-square, where each of these are effectively euphemisms for specific current platform aesthetics, but may also be reused for future platforms with similar designs:

  • primary: In lieu of any other implemented design concerns, this icon should be used (like the rel=canonical of themes)
  • flat: Android, iOS 7+
  • skeumorphic: iOS <7
  • opaque-square: iOS and other platforms that don’t support transparent backgrounds for icons
  • solid-white: Windows 8 tile icons
  • solid-black: OSX Safari pinned tabs

Vendors may choose to prioritize icons for environment-fit based on these keywords, in either direction (eg. iOS might add a +1 priority for flat and opaque-square, whereas Android may treat flat as +1 and opaque-square as -1). Content authors are strongly discouraged from varying resolution between differently-themed icon variants (eg. only providing a 2048px variant for the skeumorphic themed icon): vendors are permitted to prioritize higher-resolution but mismatchingly-themed icons over lower-resolution but properly-themed icons. (NOTE: This seems like it has the best-aligned interests in the worst-case breakdown-of-adherence scenario, which would essentially resemble what we have now.)

Vendors could also add the ability to specifically target their environments’ rules with trademarked keywords like android or ios, with the explicit statement that vendors must not prioritize another vendor’s keyword over a spec-defined one (including default). Ideally, documentation for specifying icons for a specific document would suggest picking vendor keywords alongside the closest spec keywords, akin to the way shortcut icon is often recommended as a rel over icon:

<link rel="icon" sizes="any" theme="primary skeumorphic" href="/brand/logo.svg">
<link rel="icon" sizes="any" theme="flat android" href="/brand/android-logo.svg">
<link rel="icon" sizes="any" theme="flat opaque-square ios" href="/brand/ios-logo.svg">
<link rel="icon mask-icon" sizes="any" theme="solid-black" color="#abc123" href="/brand/mask-icon.svg">

#8

Next steps for this:

  • Write an explainer.
  • Write a use cases document.
  • Write a spec describing the interactions of the mechanisms and algorithms above.
  • Condense the spec into a “Recommendations for Vendors” document stating what browsers will need to start doing differently from what they’re doing now.
  • Write a polyfill to rewrite a series of rel definitions matching said spec into a single link element to make the correct icon selection crystal clear for the browser (including a shim for rasterizing SVG favicons).

#9

This post is similar to what I wrote in Making icons less painful and murky, so you can safely ignore this one. I’m writing this to describe how the lack of design criteria impacts Android Chrome.

TL; DR: As of today, you can design a set of icons for a web app that mimic Google’s own Android native app icon styles. However, this is brittle because the icons are only distinguished by their resolution (eg. “192x192” vs “512x512”) instead of roles (eg. “this icon is for the home screen” vs “this icon is for the splash screen”) or characteristics (eg. “this icon has a drop shadow” vs “this icon is flat”).

On Android, Google’s native apps (GMail, Maps, etc.) have two kind of icons and two distinct styles:

Home screen: icons have a small drop shadow.

Splash screen: icons have no drop shadow.

If you develop a web app, you can legitimately want to follow the same styles with your own app icon. You can actually do this by creating a 192x192 icon with a shadow (it will be used as the home screen icon) and a 512x512 icon without shadow (it will be used as the splash screen icon), and declare them in the manifest file.

However, this is not reliable. What if someday Android Chrome uses the 512x512 icon as the home screen?

This emphasises the need of a system such as @stuartpb’s, described above.


#10

Jotting down a couple notes here:

  • The way we currently specify icons is so wrong, in that we have inherently tied resolution to size - one very important extension any effort in this space should introduce is a decoupling of “size” (which is an abstract unit approximating real-world sizes, most consistently based on fraction of the user’s available view angle) from resolution (which is a concrete count of individual pixel dots in an image that, depending on the format, likely does not even apply). CSS (and the <picture> element in conjunction) understands this: icon definitions (including manifest.json) need to come up to speed.
  • Just because an image is an SVG doesn’t necessarily mean it’s resolution-independent. SVGs can have resolution-dependent components, especially if they embed a raster mask (I just made an SVG like this the other day). Resolution should always be treated as a variable, never superseded by inference from the image format - although “any” should always be an acceptable value, even for nominally raster formats (though possibly with a distinction between pixelated or smooth upscaling).
  • Deterministic design elements, such as drop shadows, should always be handled by the platform, and should never be expected to have been handled by the author’s content pipeline. (If and when the pendulum of design swings back to pseudo-three-dimensional skeumorphism where shadows need to be just so, shadows should still be handled by the platform, but based on something like an optional separate depth mask.) In this same vein, icon images should never be expected to have dead space around the icon - if the UA wishes to maintain a “weight” to its icons, it needs to integrate a way to weigh and shrink the icons appropriately itself.