屏幕方向

W3C工作草案

关于本文档的更多详细信息
此版本:
https://www.w3.org/TR/2023/WD-screen-orientation-20230809/
最新发布版本:
https://www.w3.org/TR/screen-orientation/
最新编辑草案:
https://w3c.github.io/screen-orientation/
历史记录:
https://www.w3.org/standards/history/screen-orientation/
提交历史
测试套件:
https://wpt.live/screen-orientation/
编辑:
Marcos Cáceres (Apple公司)
前任编辑:
Mounir Lamouri (Google公司)
Johanna Herman (受邀专家)
反馈:
GitHub w3c/screen-orientation (拉取请求新问题开放问题)
浏览器支持:
caniuse.com

摘要

屏幕方向规范标准化了设备屏幕方向的类型和角度,并提供了锁定和解锁屏幕方向的方式。该规范定义的API暴露了设备屏幕方向的当前类型和角度,并在变化时触发事件。这使得Web应用程序能够以编程方式适应多种屏幕方向的用户体验,与CSS协同工作。该API还允许在某些前提条件下锁定屏幕方向。这对于用户物理旋转设备但屏幕方向不应改变的应用程序(例如电脑游戏)特别有用。

本文档的状态

本节描述了本文档在发布时的状态。当前W3C出版物和此技术报告的最新修订版列表可在 W3C技术报告索引 中找到 https://www.w3.org/TR/。

本文档是一个正在进行的工作。

本文档由Web应用程序工作组发布为工作草案,使用 推荐轨道

发布为工作草案并不意味着W3C及其成员的认可。

这是一个草案文件,可能会随时更新、替换或由其他文件取代。因此,不适合将本文档引用为其他用途,除非作为正在进行的工作。

本文档由一个在 W3C 专利政策下运作的团体制作。 W3C维护了 与该团体交付物相关的任何专利披露的公共列表; 该页面还包括披露专利的说明。知晓含有必要专利声明的个人必须根据 W3C专利政策第6节披露信息。

本文档受2023年6月12日W3C流程文档管辖。

1. 使用示例

本节为非规范性内容。

在此示例中,点击“锁定”按钮请求进入全屏模式,然后将屏幕锁定为相反方向。点击“解锁”按钮则解锁屏幕。

示例 1:锁定为特定方向并解锁
<script>
    function updateLockButton() {
      const lockButton = document.getElementById("button");
      const newOrientation = getOppositeOrientation();
      lockButton.textContent = `锁定为 ${newOrientation}`;
    }
    
    function getOppositeOrientation() {
      return screen
        .orientation
        .type
        .startsWith("portrait") ? "landscape" : "portrait";
    }
    
    async function rotate(lockButton) {
      if (!document.fullscreenElement) {
        await document.documentElement.requestFullscreen();
      }
      const newOrientation = getOppositeOrientation();
      await screen.orientation.lock(newOrientation);
      updateLockButton(lockButton);
    }
    
    screen.orientation.addEventListener("change", updateLockButton);
    
    window.addEventListener("load", updateLockButton);
    </script>
    
    <button onclick="rotate(this)" id="button">
      锁定为...
    </button>
    <button onclick="screen.orientation.unlock()">
      解锁
    </button>

2. 概念

将屏幕方向锁定为某个 OrientationLockType 方向 意味着用户只能将屏幕旋转到特定的 屏幕方向,可能会排除其他方向。可以旋转屏幕的可能方向由用户代理、用户偏好、操作系统的惯例或屏幕本身决定。例如,将方向锁定为 横向意味着用户可以将屏幕旋转到 横向-主方向,系统允许的情况下,可能还可以旋转到 横向-次方向,但不会变为 纵向-次方向

解锁屏幕方向 后,最终用户可以根据系统允许的任何 屏幕方向自由旋转屏幕。

2.1 屏幕方向类型

屏幕可以处于以下任意 屏幕方向之一,或锁定在其中一种:

任意
用户可以将屏幕旋转到设备操作系统或最终用户允许的任何方向。
默认(未锁定)
设备在屏幕 解锁时的默认行为 (即,活动方向锁null)。该方向由设备操作系统、用户代理或最终用户决定,或由 已安装的Web应用程序设置。例如, 当屏幕方向未锁定且用户旋转设备时,一些设备将方向限制为 纵向-主方向横向-主方向,以及 横向-次方向,但不会旋转到 纵向-次方向
横向
屏幕的宽高比宽度大于高度。
自然
由用户代理、用户、操作系统或屏幕本身决定的设备显示屏的最自然方向。例如,设备处于用户手中并垂直拿着,屏幕朝向用户。电脑显示器通常为自然的 横向-主方向,而手机通常为自然的 纵向-主方向
纵向
屏幕的宽高比高度大于宽度。
主方向
设备屏幕的自然方向,可以是 纵向横向
次方向
设备屏幕主方向的相反方向,可以是 纵向横向

2.2 当前屏幕方向类型和角度

输出设备的屏幕具有以下相关概念:

活动方向锁定
屏幕的屏幕方向,表示为 OrientationLockType, 即屏幕被锁定到的方向,或者在 解锁时为 null
当前方向角度
屏幕相对于其自然方向逆时针旋转的角度,以 屏幕方向值列表为准。
当前方向类型
屏幕的屏幕方向,表示为 OrientationType

下面的屏幕方向值列表标准化了具有不同 自然方向的屏幕与每种屏幕方向类型相关联的角度:

对于具有自然 纵向方向的屏幕:
对于具有自然 横向方向的屏幕:

3. Document 接口的扩展

3.1 内部槽

Document 接口扩展了以下内部槽:

内部槽 描述
[[orientationPendingPromise]] 可能是nullPromise。当分配给一个 Promise时, 该Promise表示请求锁定屏幕方向。

4. Screen 接口的扩展

WebIDLpartial interface Screen {
      [SameObject] readonly attribute ScreenOrientation orientation;
    };

Window 对象具有一个关联的 ScreenOrientation, 它是Screenorientation对象(即 window.screen.orientation处的 ScreenOrientation实例)。

5. ScreenOrientation 接口

WebIDL[Exposed=Window]
    interface ScreenOrientation : EventTarget {
      Promise<undefined> lock(OrientationLockType orientation);
      undefined unlock();
      readonly attribute OrientationType type;
      readonly attribute unsigned short angle;
      attribute EventHandler onchange;
    };

5.1 内部槽

内部槽 描述
[[angle]] unsigned short表示屏幕的最后已知当前方向角度,该角度来源于 屏幕方向值列表
[[initialType]] 浏览上下文创建时,表示屏幕的当前方向类型
[[type]] 表示屏幕的最后已知当前方向类型,以OrientationType 枚举值表示。

5.2 lock() 方法

当调用lock()方法并传递 OrientationLockType orientation时,用户代理 必须执行以下步骤。

用户代理 可以要求 文档 及其关联的 浏览上下文满足一个或多个 预锁定条件,以便 锁定屏幕方向。参见 10. 与Web应用程序清单的交互9. 与全屏API的交互

  1. document设置为this相关全局对象关联Document
  2. document运行常见安全检查。如果抛出 异常,返回 一个被拒绝的promise,并中止这些步骤。
  3. 如果用户代理 不支持将屏幕方向锁定为 orientation,返回 一个被拒绝的promise,并抛出 "NotSupportedError" DOMException,中止这些步骤。
  4. 如果document[[orientationPendingPromise]] 不为null,则拒绝并清除当前的锁定promise, 并抛出 "AbortError"。
  5. document[[orientationPendingPromise]] 设置为 一个新的promise
  6. 应用方向锁定 orientationdocument
  7. 返回document [[orientationPendingPromise]]

5.3 unlock() 方法

当调用 unlock()方法时,用户代理 必须执行以下步骤:

  1. document设置为this相关全局对象关联Document
  2. document运行常见安全检查。如果抛出 异常,重新抛出该异常并中止这些步骤。
  3. 如果屏幕的活动方向锁定null,返回undefined
  4. 如果document [[orientationPendingPromise]]不为null拒绝并清除当前的锁定promise, 并抛出 "AbortError"。
  5. 应用方向锁定 nulldocument
注意:为什么 unlock() 不返回 promise?

unlock()不返回 promise,因为它等同于锁定为默认屏幕方向, 用户代理可能知道也可能不知道该方向。因此,用户代理 无法预测新方向将是什么,甚至无法预测方向是否会改变。

5.4 常见安全检查

对于Document document常见安全检查包括以下步骤:

  1. 如果document不是 完全活跃的,抛出 "InvalidStateError" DOMException
  2. 如果document设置了 沙盒方向锁定浏览上下文标志抛出 "SecurityError" DOMException
  3. 如果document可见性状态为"hidden",抛出 "SecurityError" DOMException

5.5 type 属性

获取时,type属性返回 this[[type]]

5.6 angle 属性

获取时,angle属性返回 this[[angle]]

注意:角度值代表什么?

5.7 onchange 事件处理程序属性

onchange属性是 事件处理程序IDL属性, 对应于onchange事件处理程序, 其事件处理程序的事件类型change

6. OrientationLockType 枚举

WebIDLenum OrientationLockType {
      "any",
      "natural",
      "landscape",
      "portrait",
      "portrait-primary",
      "portrait-secondary",
      "landscape-primary",
      "landscape-secondary"
    };

OrientationLockType 枚举 表示可以将屏幕锁定的屏幕方向。

注意:方向支持

7. OrientationType 枚举

WebIDLenum OrientationType {
      "portrait-primary",
      "portrait-secondary",
      "landscape-primary",
      "landscape-secondary"
    };

OrientationType 枚举值用于表示屏幕的 当前方向类型

8. 算法

8.1 初始化ScreenOrientation对象

当创建一个浏览上下文context时, 用户代理必须执行以下步骤:

  1. screenOrientation成为context关联的ScreenOrientation
  2. 初始化screenOrientation[[initialType]]内部槽为屏幕的当前方向类型
  3. 初始化screenOrientation[[type]]内部槽为屏幕的当前方向类型
  4. 初始化screenOrientation[[angle]]内部槽为屏幕的当前方向角度

8.2 拒绝文档的当前锁定承诺

当需要执行步骤来拒绝并使当前的锁定承诺无效时, 对于Documentdocument使用DOMStringexceptionName用户代理必须

  1. 断言[[orientationPendingPromise]]不为null
  2. promise成为document[[orientationPendingPromise]]
  3. 排队一个全局任务DOM操作任务源中, 使用document相关全局对象拒绝promise, 使用一个新的exceptionNameDOMException
  4. document[[orientationPendingPromise]]设置为null

8.3 应用屏幕方向锁定

当步骤要求对OrientationLockType?orientation的屏幕锁定应用于Documentdocument时, 用户代理必须执行以下步骤:

  1. 如果document并行处理中停止成为完全活跃状态,并且[[orientationPendingPromise]]不为null, 则拒绝并使当前的锁定承诺无效,并抛出"AbortError"。
  2. topDocumentdocument顶级浏览上下文活动文档
  3. descendantDocs为一个由topDocument子孙导航项活动文档组成的有序集合,如果有的话,按树顺序排列。
  4. 对于每个 docdescendantDocs中:
    1. 如果docdocument,则继续。
    2. 如果doc[[orientationPendingPromise]]null,则继续。
    3. 拒绝并使当前的锁定承诺无效,并抛出"AbortError"。
  5. 并行运行以下子步骤:
    1. 如果document停止成为完全活跃状态,并且document[[orientationPendingPromise]]不为null,则拒绝并使当前的锁定承诺无效,并抛出"AbortError",并终止这些步骤。
    2. 如果orientationnull,则解锁屏幕方向
    3. 否则,尝试锁定屏幕方向orientation。根据平台约定,更改视口的绘制方式以匹配orientation
    4. 如果由于先前建立的用户偏好、平台限制或其他原因尝试失败:
      1. 将屏幕的活动方向锁定设置为null
      2. 排队任务DOM操作任务源中,使用document相关全局对象,执行以下步骤:
        1. 如果document[[orientationPendingPromise]]不为null,则拒绝并使当前的锁定承诺无效,并抛出"NotSupportedError"。
        2. 终止这些步骤。
      注意

      如果用户设置了阻止Web应用程序更改屏幕方向的偏好,或底层平台而不是用户代理不允许锁定屏幕方向到指定的orientation,这种情况可能发生。

    5. 将屏幕的活动方向锁定设置为orientation,并更新当前方向类型当前方向角度以反映对屏幕方向的任何更改。
  6. 排队一个全局任务DOM操作任务源中,使用document相关全局对象,执行以下步骤:
    1. promisedocument[[orientationPendingPromise]]
      注意
    2. document[[orientationPendingPromise]]设置为null
    3. 运行屏幕方向更改步骤,与topDocument一起执行。
    4. 如果promise不为null,则解析promiseundefined

8.4 屏幕方向更改

当用户代理确定屏幕方向已针对顶级浏览上下文更改,或用户将顶级浏览上下文移动到不同屏幕时, 执行屏幕方向更改步骤,与顶级浏览上下文活动文档一起。

针对Document document屏幕方向更改步骤如下:

  1. 如果document可见性状态为“隐藏”,则中止这些步骤。
  2. typeangle分别为屏幕的当前方向类型当前方向角度
  3. screenOrientationdocument相关全局对象关联ScreenOrientation
  4. 如果type等于screenOrientation[[type]],并且angle等于screenOrientation[[angle]],则中止这些步骤。
  5. 排队一个全局任务,在用户交互任务源中,使用document相关全局对象执行以下步骤:
    1. screenOrientation[[angle]]设置为angle
    2. screenOrientation[[type]]设置为type
    3. 触发一个事件,事件名称为"change",目标是screenOrientation
  6. descendantDocs为一个有序集合,由document子孙导航项活动文档组成,按树顺序排列(如果有)。
  7. 对于每个 docdescendantDocs中,运行屏幕方向更改步骤,与doc一起执行。

8.5 处理页面可见性更改

[HTML]的更新可见性状态会执行屏幕方向更改步骤

注意

8.6 处理卸载文档

每当卸载文档清理步骤在一个document上执行时,用户代理必须执行以下步骤:

  1. 如果document不是顶级浏览上下文活动文档,中止这些步骤。
  2. 使用document执行完全解锁屏幕方向步骤

8.7 完全解锁方向

针对Document document完全解锁屏幕方向步骤如下:

  1. 如果document[[orientationPendingPromise]]不为null,则使用"AbortError"拒绝并将当前锁定的承诺置空
  2. document顶级浏览上下文活动文档设置为topDocument
  3. topDocument应用方向锁定 null

9. 与全屏 API 的交互

用户代理应该lock()的使用限制为简单的全屏文档,作为预锁定条件。[fullscreen]

文档退出全屏时,它还会运行完全解锁屏幕方向步骤。[fullscreen]

10. 与 Web 应用清单的交互

Web 应用清单规范允许 Web 应用通过默认屏幕方向设置方向成员。

用户代理应该要求已安装的 Web 应用以“全屏”显示模式呈现,作为预锁定条件

11. 可访问性考虑

由于用户的设备可能固定在一个方向上(例如安装在轮椅的扶手上),当开发人员希望用户在锁定屏幕方向时旋转设备时,开发人员需要了解Web 内容无障碍指南 (WCAG) 2.1中的方向成功标准。该标准要求无论屏幕方向如何,内容和功能必须可用。如果特定方向是必需的,Web 应用必须告知用户方向要求。

12. 隐私和安全考虑

屏幕的类型角度是潜在的指纹识别向量。以下缓解措施有助于保护用户的隐私,防止透露设备的持握方式,并防止使用次要方向类型及其相关角度进行指纹识别。

为抵制指纹识别(例如在隐私浏览中),用户代理可以

  1. 顶级浏览上下文的生命周期内,表现得好像屏幕的自然方向是[[initialType]]
  2. type获取器的返回值限制为"portrait-primary"或"landscape-primary"。屏幕的宽高比决定返回哪个值。
  3. 如果当前方向类型[[initialType]]匹配,则angle获取器返回0,否则返回90
  4. 如果屏幕方向发生变化,仅在当前方向类型纵向变为横向时(或反之),触发change事件。

13. 一致性

除了标记为非规范性的章节外,本规范中的所有作者指南、图表、示例和注释均为非规范性。 本规范中的其他内容均为规范性。

本文档中的关键字MAYMUSTSHOULD 按照 BCP 14 [RFC2119] [RFC8174] 中的说明进行解释, 且仅当这些词全部大写时才按照这里所示的解释。

A. IDL 索引

WebIDLpartial interface Screen {
      [SameObject] readonly attribute ScreenOrientation orientation;
    };
    
    [Exposed=Window]
    interface ScreenOrientation : EventTarget {
      Promise<undefined> lock(OrientationLockType orientation);
      undefined unlock();
      readonly attribute OrientationType type;
      readonly attribute unsigned short angle;
      attribute EventHandler onchange;
    };
    
    enum OrientationLockType {
      "any",
      "natural",
      "landscape",
      "portrait",
      "portrait-primary",
      "portrait-secondary",
      "landscape-primary",
      "landscape-secondary"
    };
    
    enum OrientationType {
      "portrait-primary",
      "portrait-secondary",
      "landscape-primary",
      "landscape-secondary"
    };

B. 索引

B.1 本规范定义的术语

B.2 引用中定义的术语

C. 致谢

感谢 Christophe Dumez、Anne van Kesteren、Chundong Wang、Fuqiao Xue 和 Chaals McCathie Nevile 提出的有用意见。

特别感谢 Chris Jones 和 Jonas Sicking 对该 API 最初设计的贡献。

D. 参考文献

D.1 规范性引用

[appmanifest]
Web Application Manifest. Marcos Caceres; Kenneth Christiansen; Matt Giuca; Aaron Gustafson; Daniel Murphy; Anssi Kostiainen. W3C. 2 May 2023. W3C Working Draft. URL: https://www.w3.org/TR/appmanifest/
[cssom-view]
CSSOM View Module. Simon Pieters. W3C. 17 March 2016. W3C Working Draft. URL: https://www.w3.org/TR/cssom-view-1/
[dom]
DOM Standard. Anne van Kesteren. WHATWG. 现行标准. URL: https://dom.spec.whatwg.org/
[fullscreen]
Fullscreen API Standard. Philip Jägenstedt. WHATWG. 现行标准. URL: https://fullscreen.spec.whatwg.org/
[HTML]
HTML Standard. Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. 现行标准. URL: https://infra.spec.whatwg.org/
[mediaqueries-5]
Media Queries Level 5. Dean Jackson; Florian Rivoal; Tab Atkins Jr.; Daniel Libby. W3C. 18 December 2021. W3C Working Draft. URL: https://www.w3.org/TR/mediaqueries-5/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[WCAG21]
Web Content Accessibility Guidelines (WCAG) 2.1. Andrew Kirkpatrick; Joshue O'Connor; Alastair Campbell; Michael Cooper. W3C. 5 June 2018. W3C Recommendation. URL: https://www.w3.org/TR/WCAG21/
[WEBIDL]
Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. 现行标准. URL: https://webidl.spec.whatwg.org/