Responsive Image Client Hints

Draft Community Group Report,

This version:
https://wicg.github.io/responsive-image-client-hints
Previous Versions:
Issue Tracking:
GitHub
Inline In Spec
Editor:
Eric Portis (Cloudinary)
Former Editors:
Yoav Weiss (Google)
Ilya Grigorik (Google)

Abstract

This spec introduces several client hints useful for delivering responsive images via pro-active content negotiation.

Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

1. Introduction

Existing solutions for the responsive image use cases rely on a suite of markup (picture and srcset) which allows authors and browsers to decide how images on the web should adapt to varying contexts, so that different users receive different resources, tailored to their particular context.

Authors know the most about the page which an image is appearing; user agents know the most about the end user’s current context and preferences. Servers, however, often know the most about the available resources, and are well-situated to make good decisions in more-scalable, easier-to-implement-and-maintain ways, via proactive content negotiation. Servers require a bit of extra information about the page and user, though, in order to make those decisions; that information may be delivered in a secure, privacy-preserving way via these client hints.

By moving this decision-making to the server, we:

ShoeShoppe.biz wants to send responsive hero images on their product pages. With the responsive image client hints, they author markup like this:
<img
  src="https://media.shoeshoppe.biz/cool-shoe-hero.jpg"
  sizes="(min-width: 800px) 800px, 100vw"
  alt="A cool shoe"
/>

...and send the following Accept-CH and Permissions-Policy response headers along with their root HTML document:

Accept-CH: Sec-CH-DPR, Sec-CH-Width
Permissions-Policy: ch-dpr=(self "https://media.shoeshoppe.biz"), ch-width=(self "https://media.shoeshoppe.biz")

A user agent running on a 3x device, with a 400-px-wide viewport, then sends the following headers along with the image request:

GET https://media.shoeshoppe.biz/cool-shoe-hero.jpg
Sec-CH-Width: 1200
Sec-CH-DPR: 3

media.shoeshoppe.biz might note that cool-shoe-hero.jpg contains photographic content, and that the apparent-quality benefits of sending a full-3x, 1200-pixel-wide version won’t outweigh the cost in increased filesize. So it sends an 800-pixel-wide, 2x response instead, and modifies the response resource’s EXIF resolution in order to ensure that resulting img has the expected density-corrected intrinsic width of 400px.

2. Responsive Image Hints

2.1. The Sec-CH-Width Header Field

The Sec-CH-Width request header field gives a server the layout width of the image, in device pixels (or printed dots). It is a Structured Header whose value MUST be an integer greater than or equal to 0.

For fetches triggered by img elements, its value SHOULD be calculated by multiplying the source set’s current source size by the Window's current devicePixelRatio.

It MUST NOT be sent when the user-agent is using a fallback source size. Which is to say, if an img's current source size is 100vw because any of the conditions in step 5 of parse a sizes attribute returned true, Sec-CH-Width MUST NOT be sent.

Note: We should probably specify how user-agents track this state? I guess by setting a property like fallback sizes used (or whatever) on img.

Note: the source size may be zero. Servers should plan to receive requests for images to fit zero-width layout containers, and respond as best they can; for instance, with images clamped to some minimum (greater-than-zero) width.

Given:
  1. this markup:
    <img src="a.jpg" sizes="33vw">
    
  2. a 1000-px-wide viewport, and
  3. a devicePixelRatio of 2,

...a user agent calculates the Sec-CH-Width value to be the source size (33vw, which in this context equals 330px) * the devicePixelRatio (2), and attaches the following header to the request for a.jpg:

Sec-CH-Width: 660

Note: do we need to talk about fetches initiated by CSS (probably)? Other sorts of fetches?

Note: An older version of this hint gave the layout width in CSS px. However, to improve cache reusability, the definition was changed to device pixels. As long as the resources only Vary: Sec-CH-Width, this, for instance, allows the same 1000-pixel-wide cached resource to satisfy both 500px@2x and 1000px@1x requests, as both get Sec-CH-Width: 1000 in their cache key.

If servers want to know the layout width of the image in CSS px, they need both the Sec-CH-Width and Sec-CH-DPR hints: the img's clientWidth is equal to the value of Sec-CH-Width divided by the value of Sec-CH-DPR.

Note: does this get sent when there’s no sizes?

2.2. The Sec-CH-Viewport-Width Header Field

The Sec-CH-Viewport-Width request header field gives a server information about the user-agent’s current viewport width. It is a Structured Header whose value MUST be an integer greater than or equal to 0.

For fetches within web contexts, its value SHOULD be the Window's current innerWidth.

Note: innerWidth (and innerHeight) return zero when there is no viewport, which can happen when an iframe is styled with display: none or after a call to iframe.remove(). Servers should plan for zero-values, and respond as best they can; for instance, in the case of image requests, with resources clamped to some minimum (greater-than-zero) size.

Note: window.innerWidth includes scrollbar width. Do we want to use the width of the initial containing block (minus any scrollbar width); gettable with document.documentElement.clientWidth), instead?

Given:

  1. this markup:
    <img src="a.jpg">
    
  2. and a innerWidth of 1000,

...a user agent attaches the following header to the request for a.jpg:

Sec-CH-Viewport-Width: 1000

In the absence of any other client hints, the server does the best it can and sends back a 1000-pixel-wide response.

2.3. The Sec-CH-Viewport-Height Header Field

The Sec-CH-Viewport-Height request header field gives a server information about the user-agent’s current viewport height. It is a Structured Header whose value MUST be an integer greater than or equal to 0.

For fetches within web contexts, its value SHOULD be the Window's current innerHeight.

Note: window.innerHeight includes horizontal scrollbar width. Do we want to use the height of the initial containing block (minus any scrollbar height); gettable with document.documentElement.clientHeight), instead?

Given:

  1. this markup:
    <img src="a.jpg">
    
  2. and a innerHeight of 1000,

...a user agent attaches the following header to the request for a.jpg:

Sec-CH-Viewport-Height: 1000

In the absence of any other client hints, the server does the best it can and sends back an image optimized for a 1000-pixel-tall viewport.

2.4. The Sec-CH-DPR Header Field

The Sec-CH-DPR request header field gives a server information about the user-agent’s current device pixel ratio. It is a Structured Header whose value MUST be an decimal greater than 0.

For fetches within web contexts, its value SHOULD be the Window's current devicePixelRatio.

Servers that send resources in response to requests including Sec-CH-DPR SHOULD adjust those resource’s intrinsic resolutions via metadata to ensure that, even as the resolution of the width is changing, its density-corrected intrinsic width does not.

Given:

  1. this markup:
    <img src="a.jpg">
    
  2. and a devicePixelRatio of 2,

...a user agent attaches the following header to the request for a.jpg:

Sec-CH-DPR: 2

The default (1x) version of a.jpg is 800x600. The server sees the Sec-CH-DPR header and sends a 2x, 1600x1200 response. It tells the user agent to treat the returned resource as 2x by ensuring that it contains the following EXIF metadata, before the image data:

XResolution: 144
XResolutionUnit: Inch
PixelXDimensions: 800
PixelYDimensions: 600

And it sends the following Vary header along with the response, so that Sec-CH-DPR header field is added to the cache key:

Vary: Sec-CH-DPR

2.5. Integration with Fetch

This specification’s integration with Fetch is defined as part of the [client-hints-infrastructure] specification.

3. Security and Privacy Considerations

3.1. Secure Transport

Client Hints will not be delivered to non-secure endpoints (see the secure transport requirements in Section 2.2.1 of [RFC8942]). This means that information about the user’s device pixel ratio and viewport size will not be leaked over plaintext channels, reducing the opportunity for network attackers to build a profile of a given agent’s behavior over time.

3.2. Delegation

Client Hints will be delegated from top-level pages via Permissions Policy. This reduces the potential for passive fingerprinting by:

  1. Sending fewer hints to third parties.

  2. Never doing so indiscriminately. Information can only be revealed to third parties after the root page author explicitly asks it to be revealed to them.

  3. Ensuring that everyone (users, user agents, privacy advocates...) can see who is getting what information.

That delegation is defined as part of append client hints to request.

3.3. Access and Accuracy Restrictions

The information in the Client Hints defined above reveals extra information about the user’s context. User agents ought to exercise judgement before granting access to this information, and MAY impose restrictions above and beyond the secure transport and delegation requirements noted above. For instance, screen readers may choose not to indicate that they have no viewport, to ensure that their users are not served separate content. Similarly, user agents might offer users control over when hints are revealed to servers, gating them based on privacy modes or settings.

User agents may also choose to reduce the accuracy of these values, by rounding to reduce variation between users, and/or adding jitter to increase variation for a single user.

Servers MUST NOT require any of these hints in order to deliver content, and MUST NOT depend on pixel-accurate values in order to deliver acceptable experiences.

4. Interface and Processing model

TODO!? Or do the "in web contexts" notes above, cover this? Do we need an IDL interface? Related - do I need ABNFs, or are the simple structured header types enough?

5. Implementation Considerations

5.1. The Sec-CH prefix

TODO (start with https://github.com/WICG/ua-client-hints/blob/master/index.bs#L282 or https://github.com/WICG/ua-client-hints/blob/master/index.bs#L554)

6. IANA Considerations

This document intends to define the Sec-CH-Width, Sec-CH-Viewport-Width, and Sec-CH-DPR HTTP request header fields, and register them in the permanent message header field registry ([RFC3864]).

6.1. Sec-CH-Width Header Field

Header field name: Sec-CH-Width

Applicable protocol: http

Status: standard

Author/Change controller: IETF

Specification document: this specification (§ 2.1 The Sec-CH-Width Header Field)

6.2. Sec-CH-Viewport-Width Header Field

Header field name: Sec-CH-Viewport-Width

Applicable protocol: http

Status: standard

Author/Change controller: IETF

Specification document: this specification (§ 2.2 The Sec-CH-Viewport-Width Header Field)

6.3. Sec-CH-DPR Header Field

Header field name: Sec-CH-DPR

Applicable protocol: http

Status: standard

Author/Change controller: IETF

Specification document: this specification (§ 2.4 The Sec-CH-DPR Header Field)

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CLIENT-HINTS-INFRASTRUCTURE]
Yoav Weiss. Client Hints Infrastructure. CG-DRAFT. URL: https://wicg.github.io/client-hints-infrastructure/
[CSSOM-VIEW-1]
Simon Pieters. CSSOM View Module. URL: https://drafts.csswg.org/cssom-view/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[FINGERPRINTING-GUIDANCE]
Nick Doty. Mitigating Browser Fingerprinting in Web Specifications. URL: https://w3c.github.io/fingerprinting-guidance/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RESPIMG-USECASES]
Marcos Caceres; et al. Use Cases and Requirements for Standardizing Responsive Images. URL: https://usecases.responsiveimages.org
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC8941]
M. Nottingham; P-H. Kamp. Structured Field Values for HTTP. February 2021. Proposed Standard. URL: https://httpwg.org/specs/rfc8941.html
[RFC8942]
I. Grigorik; Y. Weiss. HTTP Client Hints. February 2021. Experimental. URL: https://www.rfc-editor.org/rfc/rfc8942

Informative References

[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. URL: https://drafts.csswg.org/css-values-4/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC3864]
G. Klyne; M. Nottingham; J. Mogul. Registration Procedures for Message Header Fields. September 2004. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc3864

Issues Index

TODO!? Or do the "in web contexts" notes above, cover this? Do we need an IDL interface? Related - do I need ABNFs, or are the simple structured header types enough?
TODO (start with https://github.com/WICG/ua-client-hints/blob/master/index.bs#L282 or https://github.com/WICG/ua-client-hints/blob/master/index.bs#L554)