This document specifies an API that allows web applications to request and be notified of changes of the posture of a device.

Implementors need to be aware that this specification is extremely unstable. Implementors who are not taking part in the discussions will find the specification changing out from under them in incompatible ways. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation phase should subscribe to the repository on GitHub and take part in the discussions.

Introduction

The device posture is the physical position in which a device holds which may be derived from sensors in addition to the angle. New types of mobile devices are appearing that have some sort of capabilities that allow them to change their posture. The most common types of devices are the ones that can fold (their screen or around their screen), allowing them to physically alter their form factor. The main interest in knowing the posture of a device is to enable new user experiences with responsive design.

Among the described "folding" devices, there are mainly two different physical form factors: devices with a single flexible screen (seamless), and devices with two screens (with seam). They can both fold around a hinge, and the current specification applies to both types. It should be clarified as well that both seamless and (devices) with seam can be of different dimension ranging from mobile and tablets to laptop sizes. It should also be noted that different devices will have different default orientations (portrait or landscape), and that the fold might happen in a vertical or horizontal way.

drawing of different type of foldable devices

From enhancing the usability of a website by avoiding the area of a fold, to enabling innovative use cases for the web, knowing the posture of a device can help developers tailor their content to different devices.

Content can be consumed and browsed even when the device is not flat, in which case the developer might want to provide a different layout for it depending on the posture state in which the device is being used.

Internal slots

The following internal slots are added to the {{Document}} interface. As it name implies, it will house the value of the current posture the device is

Internal slot Description
[[\CurrentPosture]] The current posture.

Extensions to the `Navigator` interface

The [[HTML]] specification defines the {{Navigator}} interface, which this specification extends:

        [SecureContext, Exposed=(Window)]
        partial interface Navigator {
          [SameObject] readonly attribute DevicePosture devicePosture;
        };
      

The DevicePosture interface


        [SecureContext, Exposed=(Window)]
        interface DevicePosture : EventTarget {
          readonly attribute DevicePostureType type;
          attribute EventHandler onchange;
        };

        enum DevicePostureType {
          "continuous",
          "folded"      
        };
      

The type attribute: Get current device posture

When getting the type attribute, the user agent MUST return the value of [=this=]'s [=relevant global object=]'s [=associated Document=]'s internal slot {{Document/[[CurrentPosture]]}}.

The onchange attribute: Handle posture changes

The {{onchange}} attribute is an event handler IDL attribute for the {{onchange}} [=event handler=], whose [=event handler event type=] is "change".

Posture types

This specification defines the following posture values:

  1. drawing of the continuous posture

    Continuous posture: The continuous posture refers to a "flat" position. This is the default case for most devices not allowing different postures.

    It includes devices with no folds, hinges or similar capabilities.

    Due to the nature of hardware innovation, it also includes devices with dual, foldable, rollable or curved screens, as long as they are in a posture where the {{Document}} is expected to be displayed with a flat layout.

    Examples of these are:

    • Foldable device in a flat, fully unfolded posture.
    • Foldable device running the browser in a window/section that does not span across the hinge.
    • 2-in-1 device in tablet mode using only 1 screen/side.
    • Devices that do not fold.

    In some cases, devices can run several apps and be in a physical posture other than flat, but as long as the browser does not span through several screens/sections, the corresponding posture is continuous.

  2. drawing of the folded posture Folded posture: The folded posture refers to devices that can physically fold. These devices can have one flexible screen or two adjacent screens. This posture forms an angle between the displays/sections that does not exceed a 'flat' position.

    Examples of these are:

    • Foldable device with a vertical hinge and internal screens being used in a 'book' posture, where the content spans through both sections and forms an angle between ~30° and ~170°.
    • Foldable device with a horizontal hinge and internal screens being used in a 'laptop' posture.

In the API, the [=posture=] values are represented by the {{DevicePostureType}} enum values.

Device Posture Media Queries

The device-posture media feature

The [=device-posture=] media feature represents, via a CSS media query [[MEDIAQ]], the posture of the device. All navigables reflect the posture of their [=navigable/top-level traversable=].

Value:
continuous | folded
Applies to:
visual media types
Accepts min/max prefixes:
No

A user agent MUST reflect the applied posture of the web application via a CSS media query [[MEDIAQ]].

Reading the posture

Every instance of {{Document}} has an internal slot {{Document/[[CurrentPosture]]}}, which should be initialized when the {{Document}} is created, otherwise they MUST be initialized the first time they are accessed and before their value is read. The user agent MUST run the device posture change steps with [=device posture change steps/document=] set to the {{Document}} and [=device posture change steps/disallowRecursion=] set to true to initialize it.

For a given {{Document}}, the current posture is derived from the current hinge angle and the screen orientation, and potentially other implementation-specific signals.

These tables are non-normative.

Posture values table

The values are approximations and might differ per device. For instance, a device might not yield exactly 180° when laying flat, but instead values ranging from 175° to 185°. Device makers SHOULD make sure that the physical device postures map correctly to the postures defined by this specification. Device makers are also allowed to determine the posture using more sensors than just the hinge angle. For example, they can also detect if keyboard is docked on the bottom half of the screen or not. Another example is to detect whether the kickstand is deployed or not.

Some devices might also lack one or more of the postures due to physical constraints or device design, in which case the device SHOULD make sure that all combinations of angles and device orientation (which can be locked by [[SCREEN-ORIENTATION]] and host OS), as well as device specific signals, maps into one of the defined postures.

Foldables

Posture values for foldable devices
Posture Angle value
continuous < ~180°
folded ~180°

Algorithms

Calculating the device posture information

The steps to calculate the device posture information of a {{Document}} |document:Document| are as follows:

  1. Return a {{DevicePostureType}} value determined in an [=implementation-defined=] way based on the current hinge angle value, current screen orientation, as well as potential implementation-specific signals, according to the [=posture values table=].

Device Posture change

When the user agent determines that the screen(s)' fold angle, orientation or device-specific signals have changed for a [=top-level traversable=], it MUST run the [=device posture change steps=] with the [=top-level traversable=]'s [=navigable/active document=].

The device posture change steps for a {{Document}} document and an optional boolean disallowRecursion (default false) are as follows:

  1. If |document:Document|'s [=Document/visibility state=] is "hidden", then abort these steps.
  2. Let |posture| be the result of invoking [=calculate the device posture information=] with |document|.
  3. If |posture| is equal to |document|.{{Document/[[CurrentPosture]]}}, abort these steps.
  4. [=Queue a global task=] on the [=user interaction task source=] with |document|'s [=relevant global object=] to perform the following steps:
    1. Set |documet|.{{Document/[[CurrentPosture]]}} to |posture|.
    2. [=Fire an event=] named "{{DevicePosture/change}}" at the {{DevicePosture}} object associated with |document|'s [=relevant global object=]'s associated {{Navigator}}.
  5. If |disallowRecursion| is true, abort these steps.
  6. [=List/For each=] |descendantNavigable| of |document|'s [=Document/descendant navigables=]:
    1. Run the [=device posture change steps=] with [=device posture change steps/document=] set to |descendantNavigable|'s [=navigable/active document=] and [=device posture change steps/disallowRecursion=] set to true.

This specification defines the following [=page visibility change steps=] given |visibility state| and |document:Document|:

  1. Run the [=device posture change steps=] on |document| and [=device posture change steps/disallowRecursion=] set to false to initialize it.

Security Considerations

No new security considerations have been reported on this specification.

Privacy considerations

The Device Posture API exposes a posture determined from the hinge angle sensor, but additional data can be used to determine the posture such as whether the keyboard is attached or not, whether the kickstand is deployed or not, etc.

Device Posture exposes high level concept and not sensor values making fingerprinting possibilities more limited. Changing posture is a physical manipulation done by the user. The frequency of the posture changes are low, users do not constantly adjust the angle, and even if they do the posture will only be changed in certain scenarios as described in [=posture values table=].

Types of privacy threats

This section is non-normative.

Identifying users across contexts

If this API can be used simultaneously in different window contexts on the same device it may be possible for that code to correlate the user across those two contexts, creating unanticipated tracking mechanisms. However, because the posture value is typically stable for a long time it could only be used to verify that two users are not the same, but it would not help to identify a given user given the fact that there are multiple types and models of foldable devices.

This API's entropy is comparable to the pointer API which tells whether the user's primary input is touch-based or not. However, the primary input can change on devices where the keyboard can be removed/added or the tablet mode is activated/deactivated.

iframes

iframes have access to the posture through this API and therefore could use this information to identify users as mentioned in [[[#identifying-users-across-contexts]]].

Mitigation Strategies

Secure Context

Posture value readings are explicitly flagged by the Secure Contexts specification as a high-value target for network attackers. {{DevicePosture}} has the {{SecureContext}} extended attribute in its declaration, and so does the addition to the {{Navigator}} interface ([[[#extensions-to-the-navigator-interface]]]).

Visibility State

Posture value change events are only fired for each [=navigable/active document=] whose [=Document/visibility state=] is "visible" as explained in [=device posture change steps=], and polling the value while that is not the case, will return a stale value as the value is only updated while the visibility state is "visible" or just changed to "visible".

Accessibility considerations

The main focus of the Device Posture API is to improve the user experience. There are three ways in which applications that build on the API can positively impact accessibility.
  1. Designing and making applications which do not place content in the fold/hinge area, especially buttons. This area is typically hard to interact with with fingers because the curvature of the fold makes touch less precise or impossible.
  2. Designing and making applications which do not put large, contiguous content (such as video or a picture) spanning across the fold/hinge area if the device is folded. This area slightly distorts content and colors.
  3. Designing and making applications which use the screen estate better by providing a split UI (a user interface where the content is split up across the screen segments), allowing the application to provide a differentiated and more powerful interface.
When using this API it is important to consider the opportunities above with accessibility in mind. Here are few concrete examples:

Examples

Example 1: Posture data

This is a simple use case of the posture being printed on the console.

          navigator.devicePosture.addEventListener("change", () => {
            console.log(`The current posture is: ${navigator.devicePosture.type}!`);
          })
      

Example 2: device-posture

The device is being used for a video call web service. It can be folded into the laptop posture to enable a hands-free when placed on a surface. The UA detects the posture and the UI is enhanced. Similar examples can be drafted for content to adapt to any posture. See the explainer for other key scenarios.

An illustration of a video call web service that uses the device-posture media feature and the viewport segment media feature
        @media (device-posture: folded) and (vertical-viewport-segments: 2) {
          body {
            display: flex;
            flex-flow: column nowrap;
          }

          .videocall-area, .videocall-controls  {
            flex: 1 1 env(viewport-segment-bottom 0 0);
          }
        }
      

Example 3: Feature detection of device-posture media feature

As one of the valid device-posture values will always be true, you can use the following snippet to detect whether a user agent supports the media feature:

          @media (device-posture) {
            /*The browser supports device-posture feature*/
          }
        
For more information about media features in a boolean context please refer to Evaluating Media Features in a Boolean Context.

This specification defines conformance criteria for a single product: a user agent that implements the interfaces that it contains.

Acknowledgments

We would like to offer our sincere thanks to Daniel Appelquist, Jo Balletti, Michael Blix, Paul Grenier and Laura Morinigo for their contributions to this work.