在标题栏中显示内容

PWA 可以使用 Web 应用清单文件中的显示成员来定义在移动平台上的 显示 方式。 但是,若要创建类似于本机的沉浸式体验, 桌面 PWA 可以使用另一种方法。

默认情况下,安装在桌面上的 PWA 可以在紧邻保留标题栏区域下方的区域中显示内容:

Windows 上的 PWA 应用,显示应用内容显示在保留标题栏区域下方

显示标题栏通常所在的内容可以帮助 PWA 感觉更原生。 许多桌面应用程序(例如Visual Studio Code、Microsoft Teams 和 Microsoft Edge)都已执行此操作:

Visual Studio Code标题栏区域中显示内容

窗口控件覆盖 API 执行以下操作:

  • 允许在应用的整个外围应用上显示 Web 内容。
  • 将系统所需的关键窗口控件移动到覆盖层中。
  • 使内容能够远离此覆盖。

在应用中启用窗口控件覆盖

首先,在应用的 Web 应用清单文件中启用窗口控件覆盖功能。 为此,请在清单文件中设置 display_override 属性:

{
  "display_override": ["window-controls-overlay"]
}

切换标题栏

启用“窗口控件覆盖”功能后,用户可以通过单击标题栏切换按钮来选择是否拥有标题栏:

选择标题栏切换按钮

代码不能假定窗口控件覆盖已显示,因为:

  • 用户可以选择是否显示标题栏。
  • 你的应用还可以在 Web 浏览器或移动设备中运行,以及作为桌面应用运行。

因此,代码需要对标题栏几何图形更改做出反应。 若要了解详细信息,请参阅覆盖更改React

使用 CSS 环境变量来清除覆盖层

env() CSS 函数可用于访问用户代理定义的环境变量。

窗口控件覆盖功能添加了四个环境变量:

变量 说明
titlebar-area-x 通常由标题栏从窗口左侧占用的区域的距离(以 为单位 px
titlebar-area-y 通常由标题栏从窗口顶部占用的区域的距离(以 为单位 px
titlebar-area-width 标题栏区域的宽度,in px
titlebar-area-height 标题栏区域的高度,in px

当禁用窗口控件覆盖功能时,可以使用这些环境变量来定位和调整自己的内容(通常显示标题栏的位置):

#title-bar {
  position: fixed;
  left: env(titlebar-area-x, 0);
  top: env(titlebar-area-y, 0);
  height: env(titlebar-area-height, 50px);
  width: env(titlebar-area-width, 100%);
}

使用 position: fixed; 可确保标题栏不会随其余内容滚动,而是与窗口控件覆盖保持一致。

了解覆盖层的位置及其有多大非常重要。 覆盖层可能并不总是位于窗口的同一侧;在 macOS 上,覆盖层位于左侧,但在 Windows 上,覆盖层位于右侧。 此外,覆盖层可能并不总是相同的大小。

env() CSS 函数采用第二个参数,当缺少或禁用窗口控件覆盖功能时,该参数可用于定义应用内容的位置。

为窗口创建应用区域拖动处理程序

隐藏标题栏时,只有系统关键窗口控件 (“最大化”、“ 最小化”、“ 关闭”和 “应用信息 ”图标) 保持可见。 这意味着用户几乎没有什么空间可供用户四处移动应用程序窗口。

可以使用 -webkit-app-region CSS 属性为用户提供更多拖动应用的方法。 例如,如果应用有自己的标题栏,则可以将其标题栏转换为窗口拖动处理程序:

#title-bar {
  position: fixed;
  left: env(titlebar-area-x, 0);
  top: env(titlebar-area-y, 0);
  height: env(titlebar-area-height, 50px);
  width: env(titlebar-area-width, 100%);
  -webkit-app-region: drag;
}

覆盖更改React

用户可以在应用运行时切换标题栏或更改窗口尺寸。 了解这些事情何时发生对于你的应用非常重要。 你的应用可能需要重新排列标题栏中显示的某些内容,或重新排列页面上其他位置的布局。

若要侦听更改,请在 geometrychange 对象上使用 navigator.windowControlsOverlay 事件。 若要检测标题栏是否可见,请在 对象上使用 visiblenavigator.windowControlsOverlay 属性。

请注意, geometrychange 当用户调整窗口大小时,会频繁触发 。 若要避免过于频繁地运行布局更改代码并导致应用中的性能问题,请使用 debounce 函数来限制事件的处理次数。 请参阅 限制和取消启动之间的差异

const debounce = (func, wait) => {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};

if ('windowControlsOverlay' in navigator) {
  navigator.windowControlsOverlay.addEventListener('geometrychange', debounce(e => {
    // Detect if the Window Controls Overlay is visible.
    const isOverlayVisible = navigator.windowControlsOverlay.visible;

    // Get the size and position of the title bar area.
    const titleBarRect = e.titlebarAreaRect;

    console.log(`The overlay is ${isOverlayVisible ? 'visible' : 'hidden'}, the title bar width is ${titleBarRect.width}px`);
  }, 200));
}

演示应用

1DIV 是使用窗口控件覆盖功能的 PWA 演示应用。

  1. 在 Microsoft Edge 中,转到 1DIV 并安装应用。

  2. 单击应用 标题栏中 的“隐藏标题栏”。

    应用现在一直将内容一直显示到窗口框架的顶部,其中标题栏曾经位于其中。 应用的顶部区域是拖动处理程序,可让用户移动窗口。

    地图的顶部区域可用于移动窗口

此演示应用的源代码位于 1DIV 存储库中。

  • manifest.json 源文件声明应用使用窗口控件覆盖功能。

  • app.js源文件使用 navigator.windowControlsOverlay 对象。

  • app.css 源文件使用 titlebar-area-* CSS 环境变量。

另请参阅