A proposal for preloading resources bound by media queries

by Robert Shilston,

If you use media queries to vary which resources your page uses, it’s worth considering at what point those resources should be downloaded. On the one hand, a user agent could download all resources specified in a stylesheet regardless of whether the associated media query condition is currently satisifed. Proactive pre-fetching promotes a smoother user experience in cases such as orientation change, where the re-layout and rendering of the page content should be completed as quickly as possible. On the other hand, pre-fetching may result in downloading resources that are not ultimately used, wasting possibly metered or capped data allowance and device memory.

Following the meeting of the W3C CoreMobile Commuity group in Palo Alto last month, we took an action to produce a document discussing this issue, so this is our response. As it turns out, the issue is thornier than we thought.

In current implementations as of August 2012, no popular user agent pre-fetches resources that are subject to media queries until those media queries are satisfied. However, it seems like a more intelligent approach could be taken based on the liklihood that the media query may be satisfied at some point after a page has loaded.

Some media features are liable to change as a result of user interaction with the page content, the device OS, or the physical handling of the device itself. Others cannot change without a fundamental hardware change on the device which is unlikely to happen while a webpage remains open. And in some cases the volatility of the feature value is dependent on whether certain behaviour is supported (or indeed has any meaning) for the device in question.

For example, orientation and device-width may change as a result of rotating a device, but only if the device is capable of being rotated. A tablet or phone would support this behaviour, while a desktop computer typically would not.

Other properties are typically variable on almost all platforms. A change to width can be commonly expected on any device that uses a window-based UI and therefore displays the web page in a resizable viewport, or which has a non-square aspect ratio and is capable of being rotated.

In contrast, resolution (or webkit’s non-standard and roughly equivilent device-pixel-ratio) will not change unless the pixel density of the display changes. This isn’t impossible, though currently the only situation in which this will happen is with an Apple MacBook Pro with Retina display hooked up to a standard-density external monitor. When a webpage is dragged from the high density screen to the low density one, the value of the device-pixel-ratio media feature changes from 2 to 1 (we owe the staff of the Apple store in London thanks for letting us try this!)

Since such edge cases as these exist, it is unwise to suggest that any media feature value is always constant. However, it is true to say that the probability of values changing post-pageload is significantly higher for some media features than for others, and that probability varies from one class of device to another.

To try and optimise for these variations is hard. To take the orientation change use case, when on a device where orientation change is a possibility, we may like to preload the graphics for the inactive orientation, so that when the device is rotated the images are already in cache. However, if we’re also providing high-resolution versions of both the portrait and landscape images, we only want to preload the ones that apply to the active pixel density (since pixel density, as discussed earlier, is far less likely to change).

I said ‘may’, and here lies the further complication – the way the app is designed is important too. Some pages may be designed to invite rotation, while on others it may be less desirable. So different developers building apps for the same device might differ in their opinions about whether some specific case of preloading is worth doing.

So, we cannot simply preload everything, and we cannot have a ‘prefetch’ flag on a media query because it may be a compound query containing tests for features that are likely to change in combination with other features that are not. We should not flag a media feature for prefetch, since the volatility of that feature may be device dependent.

media-preload-hint

I’d therefore like to suggest a new CSS block rule called media-preload-hint. This would contain a code block qualified by a standard media query, but instead of CSS properties, the block would contain media features with ranges that the developer wishes to preload for.

@media-preload-hint screen {
  width: 0-1000px;
  orientation:portrait,landscape;
}

In this example, the developer expresses a preference that on screen based media, the user agent should preload any media query resources that would be required if the width feature were to have a value of between 0 and 1000 and if the orientation feature were to have a value of portrait or landscape (disregarding what the actual values are at pageload). A media query that contains a conditional test of a feature not specified in a preload hint will only be preloaded if that part of the query is satisfied on page load. For example, this is how the media-preload-hint clause shown above would affect some real media queries:

@media (orientation:portrait){}  /* Preload */
@media (min-width:600px) {} /* Preload */
@media (orientation:landscape) and (min-resolution:180dpi) {} /* Preload if on high-density screen */
@media (min-device-height:400px) {} /* Don't preload */

This solution is flexible and powerful, because as well as respecting compound queries, it allows for multiple preload-hints that are themselves restricted by media query (in the examples above, preloading would only ever happen on screen based media because the preload hint would not apply to any other media type).

The syntax for media-preload-hint would be, in more complete terms:

@media-preload-hint <MEDIA-QUERY> {
  <MEDIA-FEATURE>: [<RANGE>|<LIST>|*];
  ...
}

Those media features that have continuous values, such as a length, ratio, resolution or integer, would have a preload range (eg 0-1000px), while those with discrete values would have a comma delimited preload list (eg. landscape,portrait). Any media feature can have a preload value of * meaning that feature should be considered preloadable regardless of its value.

Finally, this is a hint precisely because the user agent will know more than the developer about the capabilities of a device, and should apply that knowledge where appropriate. The hint declares the developer’s view of what is likely to be required, and the user agent should not be required to comply if it can do better.