This document specifies an API that allows web applications to request the angular value to which a device with a screen hinge is folded. Under the right conditions, and if allowed, the value representing the angle in degrees is returned.

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

New types of mobile devices are appearing that have some sort of folding capabilities around the screen. Hence, when the device folds, it physically forms an angle. The main interest in knowing the fold angle is because there are opportunities in responsive design that enable new user experiences.

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 fold angle can help developers tailor their content to different devices. It can also enable to detect different postures the device might be in.

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 state of the angle of the fold. Additionally, developers can adapt content depending on various “postures” and potentially also animate some of these transitions. You can refer to a description of use cases.

Extensions to the `Screen` interface

The [[cssom-view]] specification defines the Screen interface, which this specification extends:

        [SecureContext]
        partial interface Screen {
          [SameObject] readonly attribute ScreenFold fold;
        };
      

The ScreenFold interface

        [SecureContext, Exposed=(Window)]
        interface ScreenFold : EventTarget {
          readonly attribute unsigned short angle;
          readonly attribute ScreenFoldPosture posture;
          attribute EventHandler onchange;
        };

        enum ScreenFoldPosture {
          "no-fold",
          "laptop",
          "flat",
          "tent",
          "tablet",
          "book"
        };
      

The angle attribute: Get current screen fold angle

When getting the type attribute, the user agent MUST return the [=environment settings object/responsible document=]'s current screen fold angle.

The posture attribute: Get current screen fold posture

When getting the type attribute, the user agent MUST return the [=environment settings object/responsible document=]'s current screen fold {{posture}}.

The onchange attribute: Handle angle/posture changes

The {{onchange}} attribute is an event handler whose corresponding event handler event type is "change".

Posture modes

This specification defines the following posture values:

    drawing of no-fold mode
  1. No-Fold is the posture of a device without a hinge. This is the expected value for devices that do not fold.
  2. drawing of laptop mode
  3. Laptop posture indicates that the device is being used as a traditional laptop, meaning one screen is placed on a more or less horizontal surface with a screen angle between 180 to 0 degrees.
  4. drawing of flat mode
  5. Flat posture indicates that one screen is being placed on a more or less horizontal surface with a screen angle around 180 degrees.
  6. drawing of tent mode
  7. Tent posture indicates that the edges of both screens are placed on a horizontal surface but with an angle > 180 degrees.
  8. drawing of tablet mode
  9. Tablet posture is when the device can turn around on its hinge all the way to have the screen back to back. The angle is considered to be around 360 degrees.
  10. drawing of book mode
  11. Book posture is when the device is used between around 50 and 160 degrees. It is generally used while being held on (not on a surface).

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

Screen Fold Media Queries

The 'screen-fold-posture' media feature

The screen-fold-posture media feature represents, via a CSS media query [[MEDIAQ]], the posture of the device. This media feature applies to the top-level browsing context and any child browsing contexts. Child browsing contexts reflect the posture of the top-level browsing context.

Value:
no-fold | laptop | flat | tent | tablet | book
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]].

The 'screen-fold-angle' media feature

The screen-fold-angle media feature represents, via a CSS media query [[MEDIAQ]], the <angle> of the device. This media feature applies to the top-level browsing context and any child browsing contexts. Child browsing contexts reflect the <angle> of the top-level browsing context.

Value:
<angle>
Applies to:
visual media types
Accepts min/max prefixes:
Yes

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

Reading the posture

All documents have a current screen fold angle and a current posture. Both of them 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 update the screen fold information of the document to initialize them.

For a given document, the current posture is derived from the current screen fold angle and the current screen orientation.

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.

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) maps into one of the defined postures.

The posture values table shows how the {{posture}} values are derived depending on the orientation of the fold:

Horizontal Fold

drawing of a device with a vertical fold

Devices with a horizontal fold are the ones for which in their main form factor, the folding occurs from side to side, across the screen(s).

The posture values table for devices with a horizontal fold
Current posture Current screen orientation Current screen fold angle
Laptop "portrait-primary" | "portrait-secondary" `[0° - 140°[`
Flat any orientation `[140° - 185°[`
Tent any orientation `[185° - 335°[`
Tablet any orientation `[335° - 360°]`
Book "landscape-primary" | "landscape-secondary" `[0° - 140°[`

Vertical Fold

drawing of a device with a horizontal fold

Devices with a vertical fold are the ones for which in their main form factor, the folding occurs from top to bottom, across the screen(s).

The posture values table for devices with a vertical fold
Current posture Current screen orientation Current screen fold angle
Laptop "landscape-primary" | "landscape-secondary" `[0° - 140°[`
Flat any orientation `[140° - 185°[`
Tent any orientation `[185° - 335°[`
Tablet any orientation `[335° - 360°]`
Book "portrait-primary" | "portrait-secondary" `[0° - 140°[`

Algorithms

Updating the screen fold information

The steps to update the screen fold information of a document are as follows:

  1. Set the document's current screen fold angle to the angle between the screen fold in degrees (or two screens in case of a dual screen device).
  2. Update the document's current posture given the current screen fold angle and current screen orientation, according to posture values table.

Screen fold angle change

Whenever the screen(s) fold angle changes, the user agent MUST run the following steps as part of the next animation frame task:

  1. Let |browsing contexts| be the list of the descendant browsing contexts of the top-level browsing context's document.
  2. [=list/for each=] |context:browsing context| in |browsing contexts|, run the following sub-steps:
    1. Let |document| be the |context|'s active document.
    2. If |document| is not visible per [[PAGE-VISIBILITY]], abort these steps.
    3. Update the screen fold information of |document|.
    4. Fire an event named `change` at |document|'s {{Screen.fold}} object.

Whenever a document becomes visible per [[PAGE-VISIBILITY]], in other words after the now visible algorithm is run, the user agent MUST run the following substeps as part of the next animation frame task:

  1. Let |document| be the document in question.
  2. Let |posture| and |angle| be respectively the |document|'s current posture and current screen fold angle.
  3. Update the screen fold information of the |document|.
  4. If |posture| is different from the |document|'s current posture or |angle| from the |document|'s current screen fold angle, run the following sub-steps:
    1. Fire an event named `change` at the |document|'s {{Screen.fold}} object.

Developers need to be aware that a {{Screen.fold}} object from a document that is not visible, as per [[PAGE-VISIBILITY]], will not receive an orientation change event. This is to prevent unnecessary changes to layout, etc. in the non-visible web application.

This section could be improved if the [[PAGE-VISIBILITY]] specification had a hook for when the document becomes visible and hidden. PR 54.

Security and Privacy considerations

Exposing the screen fold angle can have some privacy implications when it comes to privacy and security. Specifically, the angle value could be used for browser fingerprinting, in a way that can help fully or partially identify individual users. It is up to the implementer to minimize this, and some proposed solutions are listed below.

Lowering the resolution of the angle value

Lowering the resolution of the angle MAY lead to reducing the uniqueness that the value can have. Nonetheless, if several sites are being displayed on the same device, it can be easy to identify that it is the same user, even if the value is rounded. As a solution, applying some fuzziness to the value itself MAY work.

Applying fuzziness to the angle value

Lowering the resolution of the returned value may not be enough, so fuzzing out the value can algo help, in order to report different values. This fuzzy offset can help differentiate returned values, minimizing the risk of fingerprinting.

Examples

Example 1: screen.fold data

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

          screen.fold.addEventListener("change", () => {
            const { angle, posture } = screen.fold;
            console.log(`The current screen angle is ${angle}, which means it is in ${posture} posture!`);
          })
      

Example 2: screen-fold-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.

        @media (screen-fold-posture: laptop) and (spanning: single-fold-horizontal){
          body {
            display: flex;
            flex-flow: column nowrap;
          }

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

Example 3: screen-fold-angle

Some scenarios might span outside of the default postures envisioned in this document. The screen-fold-angle media feature allows to define a range or threshold for the layout to change.

As an example, an experience that might require a separate viewing area by user (like a game) might find that the default 185° starting angle for the tent posture is too "open" to guarantee one user will not see the other user's screen. Using screen-fold-angle the threshold can be defined by the developer.

diagram of an example that uses an angle range to tailor content
          @media (min-screen-fold-angle: 270deg) {
            /*enable custom layout for the app*/ 
          }

        

Example 4 & 5: Animation

Opening and closing a device might include animations linked to the value of the angle of the fold. This allows the creation of content that can mimic the effect of a pop-up book.

Another example can be mapping the state of the fold of a device to transformations of a DOM element. With this approach you could rotate an element based on the value of the angle.

diagram of an img element rotating on the center of a webpage
          let fish = document.querySelector('.fish-circle');
          
          ScreenFold.addEventListener('change', function(e) {
            //animation keyframes
            let rotationFish = [
              {transform: `rotate(${e.angle})`, easing: 'ease-out'}
            ];

            fish.animate(rotationFish, 100);
          };
        
          .fish-circle {
            transform: rotate(env(screen-fold-angle));
          }
        

Dependencies

The following concepts and interfaces are defined in [[SCREEN-ORIENTATION]]: current screen orientation as represented by the {{OrientationType}} enum.

The following concepts and interfaces are defined in [[HTML]]: list of the descendant browsing contexts.

The following is defined in [[PAGE-VISIBILITY]]: now visible algorithm.

The following is used but not defined in [[FULLSCREEN]]: animation frame task.

This should now be updated since the animation frame task issue is recently resolved and the timing is now defined.

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, Alexis Menard, Jo Balletti, and Michael Blix for their contributions to this work.