The Screen Orientation specification standardizes the
types and angles for a device's screen orientation, and provides a
means for locking and unlocking it. The API, defined by this
specification, exposes the current type and angle of the device's
screen orientation, and dispatches events when it changes. This enables
web applications to programmatically adapt the user experience for
multiple screen orientations, working alongside CSS. The API also
allows for the screen orientation to be locked under certain
preconditions. This is particularly useful for applications such as
computer games, where users physically rotate the device, but the
screen orientation itself should not change.
This document is a work in progress.
Example of usage
In this example clicking the "Lock" button requests to go into
fullscreen and then locks the screen to the opposite orientation.
clicking the "unlock" button unlocks the screen.
To lock the
screen orientation to an {{OrientationLockType}} |orientation|
means that the screen can only be rotated by the user to a specific
[=screen orientation=] - possibly at the exclusion of other
orientations. The possible orientations to which the screen can be
rotated is determined by the user agent, a user preference, the
operating system's conventions, or the screen itself. For example,
locking the orientation to [=landscape=] means that the screen can be
rotated by the user to [=landscape-primary=] and maybe
[=landscape-secondary=] if the system allows it, but won't change the
orientation to [=portrait-secondary=] orientation.
To unlock the screen
orientation the end user is unrestricted to rotate the screen to
any [=screen orientation=] that the system allows.
Screen orientation types
A screen can be in, or [=locked=] to, one of the following
screen orientations:
Natural
The most natural orientation for the device's display as determined
by the user agent, the user, the operating system, or the screen
itself. For example, a device viewed, or held upright in the user's
hand, with the screen facing the user. A computer monitor are
commonly naturally [=landscape-primary=], while a mobile phones are
commonly naturally [=portrait-primary=].
Landscape
The screen's aspect ratio has a width greater than the height.
Portrait
The screen's aspect ratio has a height greater than the width.
Primary
The device's screen [=natural=] orientation for either [=portrait=]
or [=landscape=].
Secondary
The opposite of the device's screen primary orientation for
[=portrait=] or [=landscape=].
Any
The screen can be rotated by the user to any orientation allowed by
the device's operating system or by the end-user.
Default (unlocked)
The device's default behavior for when the screen is [=unlocked=]
(i.e., the [=Screen/active orientation lock=] is `null`). This
orientation is determined by the device's operating system, or the
user agent, or controlled by the end-user, or possibly set by an
[=installed web application=]. For example, when the screen
orientation is unlocked and the user rotates the device, some
devices will limit orientation changes to [=portrait-primary=],
[=landscape-primary=], and [=landscape-secondary=], but not to
[=portrait-secondary=].
The current screen orientation type and angle
The screen of the output device has the following associated
concepts:
Current orientation type
The [=screen orientation=] of the screen, represented as a
{{OrientationType}}.
Current orientation angle
The angle in degrees that the screen is rotated counter-clockwise
from its [=natural=] orientation as derived by the [=screen
orientation values list=].
Active orientation lock
The [=screen orientation=], represented as a
{{OrientationLockType}}, to which the screen is [=locked=], or
`null` when [=unlocked=].
The screen orientation values lists below standardize the
angles associated with each screen orientation type for screens with
different [=natural=] orientations:
For screens with a [=natural=] [=portrait=] orientation:
[=portrait-primary=]: 0°
[=landscape-primary=]: 90°
[=portrait-secondary=]: 180°
[=landscape-secondary=]: 270°
For screens with a [=natural=] [=landscape=] orientation:
[=landscape-primary=]: 0°
[=portrait-primary=]: 90°
[=landscape-secondary=]: 180°
[=portrait-secondary=]: 270°
Extensions to the `Document` interface
Internal Slots
The {{Document}} interface is extended with the following internal
slots:
Internal Slot
Description
[[\orientationPendingPromise]]
Either `null` or a {{Promise}}. When assigned a {{Promise}},
that promise represents a request to lock the screen
orientation.
The {{Window}} object has an associated `ScreenOrientation`,
which is a {{Screen}}'s {{Screen/orientation}} object (i.e., the
{{ScreenOrientation}} instance at `window.screen.orientation`).
Represents the screen's last known [=Screen/current orientation
angle=] in degrees as an {{unsigned short}} as derived from the
[=screen orientation values lists=].
[[\initialType]]
Represents the screen's [=Screen/current orientation type=]
when the [=browsing context=] was created.
[[\type]]
Represents the screen's last known [=Screen/current orientation
type=] as an {{OrientationType}} enum value.
`lock()` method
When the {{lock()}} method is invoked with {{OrientationLockType}}
|orientation:OrientationLockType|, the [=user agent=] MUST run the
following steps.
The [=user agent=] MAY require a [=document=] and its associated
[=Document/browsing context=] to meet one or more pre-lock
conditions in order to [=lock the screen orientation=]. See
[[[#appmanifest-interaction]]] and [[[#fullscreen-interaction]]].
Let |document:Document| be [=this=]'s [=relevant global
object=]'s [=associated `Document`=].
Run the [=common safety checks=] with |document|. If an
[=exception=] is [=exception/throw|thrown=], return [=a promise
rejected with=] that exception and abort these steps.
If the [=user agent=] does not support locking the screen
orientation to |orientation|, return [=a promise rejected with=] a
{{"NotSupportedError"}} {{DOMException}} and abort these steps.
If |document|'s
{{Document/[[orientationPendingPromise]]}} is not `null`, [=reject
and nullify the current lock promise=] of |document| with an
{{"AbortError"}}.
Set |document|'s
{{Document/[[orientationPendingPromise]]}} to [=a new promise=].
[=Apply orientation lock=] |orientation| to |document|.
When the {{unlock()}} method is invoked, the [=user agent=] MUST run
the following steps:
Let |document:Document| be [=this=]'s [=relevant global
object=]'s [=associated `Document`=].
Run the [=common safety checks=] with |document|. If an
[=exception=] is [=exception/throw|thrown=], re-throw that exception
and abort these steps.
If screen's [=Screen/active orientation lock=] is `null`, return
`undefined`.
If |document|'s {{Document/[[orientationPendingPromise]]}} is not
`null`, [=reject and nullify the current lock promise=] of |document|
with an {{"AbortError"}}.
[=Apply orientation lock=] `null` to |document|.
{{unlock()}} does not return a promise because it is equivalent to
locking to the [=default screen orientation=] which might or might
not be known by the [=user agent=]. Hence, the [=user agent=] can not
predict what the new orientation is going to be and even if it is
going to change at all.
Common Safety Checks
The common safety checks for a {{Document}}
|document:Document| are the following steps:
If |document| is not
[=Document/fully active=], [=exception/throw=] an
{{"InvalidStateError"}} {{DOMException}}.
If |document| has the
[=sandboxed orientation lock browsing context flag=] set,
[=exception/throw=] {{"SecurityError"}} {{DOMException}}.
If |document|'s
[=Document/visibility state=] is "hidden", [=exception/throw=]
{{"SecurityError"}} {{DOMException}}.
`type` attribute
When getting, the {{type}} attribute returns [=this=]'s
{{ScreenOrientation/[[type]]}}.
`angle` attribute
When getting, the {{angle}} attribute returns [=this=]'s
{{ScreenOrientation/[[angle]]}}.
`onchange` event handler attribute
The {{onchange}} attribute is an [=event handler IDL attribute=] for
the {{onchange}} [=event handler=], whose [=event handler event type=]
is change.
When a [=browsing context=] |context| is created, the [=user agent=]
MUST:
Let |screenOrientation| be |context|'s [=associated
`ScreenOrientation`=].
Initialize |screenOrientation|'s
{{ScreenOrientation/[[initialType]]}} internal slot to the screen's
[=Screen/current orientation type=].
Initialize |screenOrientation|'s {{ScreenOrientation/[[type]]}}
internal slot to the screen's [=Screen/current orientation type=].
Initialize |screenOrientation|'s {{ScreenOrientation/[[angle]]}}
internal slot to the screen's [=Screen/current orientation angle=].
Rejecting a document's current lock promise
When steps require to reject and nullify the current lock
promise of {{Document}} |document| with a {{DOMString}}
|exceptionName|, the [=user agent=] MUST:
[=/Assert=]: {{Document/[[orientationPendingPromise]]}} is not
`null`.
Let |promise:Promise| be |document|'s
{{Document/[[orientationPendingPromise]]}}.
[=Queue a global task=] on the [=DOM manipulation task source=]
with |document|'s [=relevant global object=] to [=reject=] |promise|
with a new |exceptionName| {{DOMException}}.
Set |document|'s {{Document/[[orientationPendingPromise]]}} to
`null`.
Applying an orientation lock
When steps require to apply orientation lock of
{{OrientationLockType?}} |orientation| to {{Document}} |document|, the
[=user agent=] MUST perform do the following steps:
If |document| stops being [=Document/fully active=] while [=in
parallel=], and {{Document/[[orientationPendingPromise]]}} is not
`null`, [=reject and nullify the current lock promise=] of |document|
with an {{"AbortError"}}.
Let |topDocument| be |document|'s [=top-level browsing context=]'s
[=navigable/active document=].
Let |descendantDocs| be an [=ordered set=] consisting of
|topDocument|'s [=Document/descendant navigables=]'s [=navigable/active
documents=], if any, in tree order.
[=Set/For each=] |doc:Document| in |descendantDocs|:
If |doc| is |document|, continue.
If |doc| {{Document/[[orientationPendingPromise]]}} is `null`,
continue.
[=Reject and nullify the current lock promise=] of |doc| with
an {{"AbortError"}}.
Run the following sub-steps [=in parallel=]:
If |document| has stopped being [=Document/fully active=], and
if the |document|'s {{Document/[[orientationPendingPromise]]}} is
not `null`, [=reject and nullify the current lock promise=] of
|document| with an {{"AbortError"}} and abort these steps.
If |orientation| is `null`, [=unlock the screen orientation=].
Otherwise, attempt to [=lock the screen orientation=] to
|orientation|. Depending on platform conventions, change how the
viewport is drawn to match |orientation|.
If the attempt fails due to previously-established user
preference, or platform limitation, or any other reason:
Set the screen's [=Screen/active orientation lock=] to
`null`.
[=Queue a task=] on the [=DOM manipulation task source=]
with |document|'s [=relevant global object=] to:
If the |document|'s
{{Document/[[orientationPendingPromise]]}} is not `null`,
[=reject and nullify the current lock promise=] of
|document| with a {{"NotSupportedError"}}.
Abort these steps.
This can happen if the user has set a preference that prevents
web applications from changing the screen orientation, or if
the underlying platform, rather than the user agent, does not
allow locking the screen orientation to the given
|orientation|.
Set the screen's [=Screen/active orientation lock=] to
|orientation| and update the [=Screen/current orientation type=]
and [=Screen/current orientation angle=] to reflect any changes to
the [=screen orientation=].
[=Queue a global task=] on the [=DOM manipulation task source=]
with |document|'s [=relevant global object=] to:
Let |promise:Promise?| be |document|'s
{{Document/[[orientationPendingPromise]]}}.
Set |document|'s {{Document/[[orientationPendingPromise]]}} to
`null`.
Run the [=screen orientation change steps=] with |topDocument|.
If |promise| is not `null`, [=resolve=] |promise| with
`undefined`.
Screen orientation change
When a user-agent determines that the screen's orientation has changed
for a [=top-level browsing context=], or the user moves the [=top-level
browsing context=] to a different screen, then run the [=screen
orientation change steps=] with the [=top-level browsing context=]'s
[=navigable/active document=].
The screen orientation change steps for
{{Document}} |document:Document| are as follows:
If |document|'s [=Document/visibility state=] is "hidden", abort
these steps.
Let |type| and |angle| be the screen's [=Screen/current orientation
type=] and [=Screen/current orientation angle=].
Let |screenOrientation| be |document|'s [=relevant global
object=]'s [=associated `ScreenOrientation`=].
If |type| is equal to |screenOrientation|'s
{{ScreenOrientation/[[type]]}} and |angle| is equal to
|screenOrientation|'s {{ScreenOrientation/[[angle]]}}, abort these
steps.
[=Queue a global task=] on the [=user interaction task source=]
with |document|'s [=relevant global object=] to perform the following
steps:
Set |screenOrientation|'s {{ScreenOrientation/[[angle]]}} to
|angle|.
Set |screenOrientation|'s {{ScreenOrientation/[[type]]}} to
|type|.
[=Fire an event=] named "change" at |screenOrientation|.
Let |descendantDocs| be an [=ordered set=] consisting of
|document|'s [=Document/descendant navigables=]'s [=navigable/active
documents=], if any, in tree order.
[=Set/For each=] |doc:Document| in |descendantDocs|, run the
[=screen orientation change steps=] with |doc|.
Handling page visibility changes
[[HTML]]'s update the visibility state runs the [=screen orientation
change steps=].
Handling unloading documents
Whenever the [=unloading document cleanup steps=] run with a
|document|, the user agent MUST run the following steps:
If |document| is not a [=top-level browsing context=]'s
[=navigable/active document=], abort these steps.
Run the [=fully unlock the screen orientation steps=] with
|document|.
Fully unlocking the orientation
The fully unlock the screen orientation steps
for {{Document}} |document:Document| are as follows:
If |document|'s {{Document/[[orientationPendingPromise]]}} is not
`null`, [=reject and nullify the current lock promise=] of |document|
with an {{"AbortError"}}.
Let |topDocument| be |document|'s [=top-level browsing context=]'s
[=navigable/active document=].
[=Apply orientation lock=] `null` to |topDocument|.
Interaction with Fullscreen API
A user agent SHOULD restrict the use of {{ScreenOrientation/lock()}} to
simple fullscreen documents as a [=pre-lock condition=]. [[fullscreen]]
When a [=document=] exits fullscreen, it also runs the [=fully unlock
the screen orientation steps=]. [[fullscreen]]
Interaction with Web Application Manifest
The [[[appmanifest]]] specification allows web applications to set the
[=default screen orientation=] via the the [=manifest/orientation=]
member.
A user agent SHOULD require [=installed web applications=] to be
presented in the "fullscreen" [=display mode=] as a [=pre-lock
condition=].
Accessibility considerations
As users can have their devices mounted in a fixed orientation (e.g. on
the arm of a wheelchair), developers that expect users to rotate their
device when [=locking the screen orientation=] need to be aware of the
[[[WCAG21]]]'s Orientation Success
Criterion. The criterion makes it essential that content and functionality is
available regardless of the [=screen orientation=]. When a particular
orientation is essential, web
applications must advise the user of the orientation requirements.
Privacy and Security Considerations
A screen's [=Screen/current orientation type|type=] and
[=Screen/current orientation angle|angle=] are a potential
fingerprinting vector. The following mitigation help protect a user's
privacy by not revealing how a device is being held, and also prevents
the [=secondary=] orientation type and associated angles from being
user for fingerprinting purposes.
To resist fingerprinting (e.g., in private browsing), user agents MAY:
For the life of a [=top-level browsing context=], behave as as if
screen's [=natural=] orientation is
{{ScreenOrientation/[[initialType]]}}.
Restrict the possible return values of the
{{ScreenOrientation/type}} getter to
{{OrientationType/"portrait-primary"}} or
{{OrientationType/"landscape-primary"}}. The screen aspect ratio
determines which is returned.
If the [=Screen/current orientation type=] matches
{{ScreenOrientation/[[initialType]]}}, return `0` for the
{{ScreenOrientation/angle}} getter. Otherwise, return `90`.
If the screen orientation changes, only fire the
change event when the
[=Screen/current orientation type=] changes from [=portrait=] to
[=landscape=], or vice versa.
Acknowledgments
Thanks Christophe Dumez, Anne van Kesteren, Chundong Wang, Fuqiao Xue,
and Chaals McCathie Nevile for their useful comments.
Special thanks to Chris Jones and Jonas Sicking for their contributions
to the initial design of this API.