WICG / web-preferences-api

The Web Preference API aims to provide a way for sites to override the value for a given user preference (e.g. color-scheme preference) in a way that fully integrates with existing Web APIs.
https://wicg.github.io/web-preferences-api/
Other
41 stars 2 forks source link

Web Preferences API

Authors: Luke Warlow

Contributors: Jason Williams (Bloomberg)

Status of this Document

This document is intended as a starting point to engage standards bodies in developing a solution to the problem listed below.

See the draft spec for more details.

Introduction

Currently, website authors have a choice when wishing to honour a user's preference for a given setting:

They can choose to "use the platform" where the user must indicate their preference via their OS or, if lucky, they can override in the browser. This comes with a number of issues:

Alternatively, sites can and do offer site-level settings, but this currently comes with a number of issues:

The Web Preferences API aims to solve this by providing a way for sites to indicate a user preference for a given pre-defined setting.

It is intended for this override to apply permanently and be scoped per origin. The override should be passed down to sub-resource where possible, see privacy section for details. This explainer refers to "site" but it should be read to mean origin.

Goals

Non-Goals

Demonstration

You can try it out by running a recent version of Chrome Canary with the following flags enabled: --enable-experimental-web-platform-features

Simple Example

A common use case for this API would be allowing a user to override their color scheme preference for a given site. Usually via some kind of toggle switch. Here is an example of how this could be implemented:

button.onClick(() => {
  // Toggle the color scheme preference
  const newVal =
    navigator.preferences.colorScheme.value === "dark" ? "light" : "dark";
  navigator.preferences.colorScheme
    .requestOverride(newVal)
    .then(() => {
      // The preference override was successful.
    })
    .catch((error) => {
      // The preference override request was rejected.
    });
});

Use Cases

Color scheme toggle switch

Currently, sites can use a variety of UI components to implement a per site configuration of color scheme preference. An example of a custom element library for this is dark-mode-toggle.

This library currently requires users to use a class to indicate the dark mode preference, rather than being able to use the preference media query. It also contains a "hack" to allow the media attribute on <link> elements to work.

With the Web Preferences API, this library could be updated to remove the "hack" for <link> elements, and all limitations such as requiring a dark mode class would be removed.

Syncing preferences across devices

Like with the previous use case, if a site wanted to sync a user's animation preference across devices, they'd currently have to remove any usages of media queries and swap to using the DOM and a CSS selector (e.g. class, or attribute).

With the Web Preference API, this would no longer be the case and sites could use a simple sync function on page load to ensure the server and client preference matches.

This would have the added effect of the site benefiting from any potential future UA stylesheet to reduce animations for users who have indicated a preference for reduced motion.

Fully Themed Browser UI

Currently, if a site decides not to use prefers-color-scheme, they're likely also not using the color-scheme property to declare support for dark mode.

This likely results in having to manually theme all browser provided UI (e.g. form controls, scrollbars) for dark mode. This is a lot of work and is likely to be missed in some places.

With the Web Preferences API, sites could simply use the color-scheme property and rely on the browser to theme all browser provided UI.

Proposed Solution

The navigator.preferences object

A new navigator.preferences object will be added to the platform. This object will be the entry point to this API.

TypeScript

interface Navigator {
  readonly preferences: PreferenceManager;
}

interface PreferenceManager {
  readonly colorScheme: PreferenceObject;
  readonly contrast: PreferenceObject;
  readonly reducedMotion: PreferenceObject;
  readonly reducedTransparency: PreferenceObject;
  readonly reducedData: PreferenceObject;
  // Future preferences can be added here, the exact properties will be down to the browser support.
}

interface PreferenceObject {
  // null means the preference is not overridden
  readonly override: string | null;
  readonly value: string;
  readonly validValues: string[];

  requestOverride(value: string | null): Promise<void>;
  clearOverride(): void;
}

interface PreferenceSupportData {
  readonly name: string;
  readonly values: string[];
}

Privacy and Security Considerations

Avoiding fingerprinting

This API exposes no new fingerprinting surfaces beyond that which already exist in the platform.

Permissions & User Activation

As the requestOverride method is a promise it gives user agents more control over the process of overriding a preference.

The requestOverride method is gated behind a UA defined algorithm for determining if the action can proceed.

This could include a user prompt, or it could be a simple check to see if the user has interacted with the page.

Iframes etc

See #8 for discussion regarding this.

For the spec we can probably find an existing definition to reference, but for the purposes of this explainer:

Wherever the override value is passed down it should be done so in an opaque manner.

e.g. if the parent frame sets colorScheme to dark then the iframe should see prefers-color-scheme as dark but shouldn't read navigator.preferences.colorScheme as dark.

Alternative Solutions

Use a custom media query

A site could hypothetically use the as yet unimplemented Custom Media Queries this way they could define custom media queries for each preference they wish to override.

This spec is currently in the early stages of development, and it is unclear if it will ever be implemented or in what shape it will take. For example, would this allow a site to use a custom media query inside the media attribute of a <link> element?

This also doesn't solve the key issue of third party libraries being aware of this preference override.

Request that browsers provide a UI for overriding preferences per site

While this would be a nice solution, the lack of any such UI in any browser makes it unlikely that this will happen any time soon.

This also doesn't fix the (relatively minor) issue of preference syncing across devices.

Open Questions

Acknowledgements

Special thanks to Ryan Christian for his help in reviewing the original explainer and providing feedback.