Skip to main content

窗口定制

¥Window Customization

BrowserWindow 模块是 Electron 应用的基础,它公开了许多可以更改浏览器窗口的外观和行为的 API。在本教程中,我们将介绍 macOS、Windows 和 Linux 上窗口自定义的各种用例。

¥The BrowserWindow module is the foundation of your Electron application, and it exposes many APIs that can change the look and behavior of your browser windows. In this tutorial, we will be going over the various use-cases for window customization on macOS, Windows, and Linux.

创建无框窗户

¥Create frameless windows

无框窗是没有 chrome 的窗。不要与 Google Chrome 浏览器混淆,窗口镶边是指窗口中不属于网页的部分(例如工具栏、控件)。

¥A frameless window is a window that has no chrome. Not to be confused with the Google Chrome browser, window chrome refers to the parts of the window (e.g. toolbars, controls) that are not a part of the web page.

要创建无框窗口,需要在 BrowserWindow 构造函数中将 frame 设置为 false

¥To create a frameless window, you need to set frame to false in the BrowserWindow constructor.

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ frame: false })

应用自定义标题栏样式 macOS Windows

¥Apply custom title bar styles macOS Windows

标题栏样式允许你隐藏 BrowserWindow 的大部分镶边,同时保持系统原生窗口控件完整,并且可以使用 BrowserWindow 构造函数中的 titleBarStyle 选项进行配置。

¥Title bar styles allow you to hide most of a BrowserWindow's chrome while keeping the system's native window controls intact and can be configured with the titleBarStyle option in the BrowserWindow constructor.

应用 hidden 标题栏样式会产生隐藏的标题栏和全尺寸的内容窗口。

¥Applying the hidden title bar style results in a hidden title bar and a full-size content window.

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'hidden' })

控制交通灯 macOS

¥Control the traffic lights macOS

在 macOS 上,应用 hidden 标题栏样式仍会在左上角显示标准窗口控件(“红绿灯”)。

¥On macOS, applying the hidden title bar style will still expose the standard window controls (“traffic lights”) in the top left.

自定义交通灯 macOS 的外观

¥Customize the look of your traffic lights macOS

customButtonsOnHover 标题栏样式将隐藏交通灯,直到你将鼠标悬停在它们上方。如果你想在 HTML 中创建自定义交通灯,但仍使用原生 UI 来控制窗口,这非常有用。

¥The customButtonsOnHover title bar style will hide the traffic lights until you hover over them. This is useful if you want to create custom traffic lights in your HTML but still use the native UI to control the window.

const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover' })

自定义交通灯位置 macOS

¥Customize the traffic light position macOS

要修改交通灯窗口控件的位置,有两个配置选项可用。

¥To modify the position of the traffic light window controls, there are two configuration options available.

应用 hiddenInset 标题栏样式会将交通信号灯的垂直插入移动固定量。

¥Applying hiddenInset title bar style will shift the vertical inset of the traffic lights by a fixed amount.

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })

如果需要对交通灯的位置进行更精细的控制,可以将一组坐标传递给 BrowserWindow 构造函数中的 trafficLightPosition 选项。

¥If you need more granular control over the positioning of the traffic lights, you can pass a set of coordinates to the trafficLightPosition option in the BrowserWindow constructor.

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
trafficLightPosition: { x: 10, y: 10 }
})

以编程方式显示和隐藏交通灯 macOS

¥Show and hide the traffic lights programmatically macOS

你还可以在主进程中以编程方式显示和隐藏交通信号灯。win.setWindowButtonVisibility 根据其布尔参数的值强制显示或隐藏交通灯。

¥You can also show and hide the traffic lights programmatically from the main process. The win.setWindowButtonVisibility forces traffic lights to be show or hidden depending on the value of its boolean parameter.

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
// hides the traffic lights
win.setWindowButtonVisibility(false)

注意:考虑到可用 API 的数量,有很多方法可以实现这一目标。例如,将 frame: falsewin.setWindowButtonVisibility(true) 组合将产生与设置 titleBarStyle: 'hidden' 相同的布局结果。

¥Note: Given the number of APIs available, there are many ways of achieving this. For instance, combining frame: false with win.setWindowButtonVisibility(true) will yield the same layout outcome as setting titleBarStyle: 'hidden'.

窗口控件覆盖

¥Window Controls Overlay

窗口控件覆盖 API 是一种 Web 标准,使 Web 应用能够在安装在桌面上时自定义其标题栏区域。Electron 通过 BrowserWindow 构造函数选项 titleBarOverlay 公开此 API。

¥The Window Controls Overlay API is a web standard that gives web apps the ability to customize their title bar region when installed on desktop. Electron exposes this API through the BrowserWindow constructor option titleBarOverlay.

此选项仅在应用自定义 titlebarStyle 时有效。当启用 titleBarOverlay 时,窗口控件将在其默认位置公开,并且 DOM 元素无法使用该区域下方的区域。

¥This option only works whenever a custom titlebarStyle is applied. When titleBarOverlay is enabled, the window controls become exposed in their default position, and DOM elements cannot use the area underneath this region.

titleBarOverlay 选项接受两种不同的值格式。

¥The titleBarOverlay option accepts two different value formats.

在任一平台上指定 true 将导致具有默认系统颜色的覆盖区域:

¥Specifying true on either platform will result in an overlay region with default system colors:

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: true
})

在任一平台上 titleBarOverlay 也可以是一个对象。可以使用 height 属性指定覆盖层的高度。在 Windows 和 Linux 上,可以使用 color 属性指定覆盖的颜色。在 Windows 和 Linux 上,可以分别使用 colorsymbolColor 属性指定覆盖的颜色及其符号。支持 rgba()hsla()#RRGGBBAA 颜色格式以应用透明度。

¥On either platform titleBarOverlay can also be an object. The height of the overlay can be specified with the height property. On Windows and Linux, the color of the overlay and can be specified using the color property. On Windows and Linux, the color of the overlay and its symbols can be specified using the color and symbolColor properties respectively. The rgba(), hsla(), and #RRGGBBAA color formats are supported to apply transparency.

如果未指定颜色选项,则窗口控制按钮的颜色将默认为其系统颜色。同样,如果未指定 height 选项,它将默认为默认高度:

¥If a color option is not specified, the color will default to its system color for the window control buttons. Similarly, if the height option is not specified it will default to the default height:

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: {
color: '#2f3241',
symbolColor: '#74b1be',
height: 60
}
})

注意:从主进程启用标题栏覆盖后,你可以使用一组只读 JavaScript APICSS 环境变量 从渲染器访问覆盖的颜色和尺寸值。

¥Note: Once your title bar overlay is enabled from the main process, you can access the overlay's color and dimension values from a renderer using a set of readonly JavaScript APIs and CSS Environment Variables.

创建透明窗口

¥Create transparent windows

通过将 transparent 选项设置为 true,你可以制作一个完全透明的窗口。

¥By setting the transparent option to true, you can make a fully transparent window.

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ transparent: true })

局限性

¥Limitations

  • 你无法单击透明区域。详情请参见 #1335

    ¥You cannot click through the transparent area. See #1335 for details.

  • 透明窗口不可调整大小。将 resizable 设置为 true 可能会使透明窗口在某些平台上停止工作。

    ¥Transparent windows are not resizable. Setting resizable to true may make a transparent window stop working on some platforms.

  • CSS blur() 过滤器仅适用于窗口的网页内容,因此无法对窗口下方的内容(即用户系统上打开的其他应用)应用模糊效果。

    ¥The CSS blur() filter only applies to the window's web contents, so there is no way to apply blur effect to the content below the window (i.e. other applications open on the user's system).

  • 打开 DevTools 时,窗口不会是透明的。

    ¥The window will not be transparent when DevTools is opened.

  • 在 Windows 上:

    ¥On Windows:

    • 禁用 DWM 时,透明窗口将不起作用。

      ¥Transparent windows will not work when DWM is disabled.

    • 无法使用 Windows 系统菜单或双击标题栏来最大化透明窗口。其背后的原因可以在 PR #28207 上看到。

      ¥Transparent windows can not be maximized using the Windows system menu or by double clicking the title bar. The reasoning behind this can be seen on PR #28207.

  • 在 macOS 上:

    ¥On macOS:

    • 原生窗口阴影不会显示在透明窗口上。

      ¥The native window shadow will not be shown on a transparent window.

创建点击窗口

¥Create click-through windows

要创建点击窗口,即使窗口忽略所有鼠标事件,你可以调用 win.setIgnoreMouseEvents(ignore) API:

¥To create a click-through window, i.e. making the window ignore all mouse events, you can call the win.setIgnoreMouseEvents(ignore) API:

main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.setIgnoreMouseEvents(true)

转发鼠标事件 macOS Windows

¥Forward mouse events macOS Windows

忽略鼠标消息会使 Web 内容忽略鼠标移动,这意味着不会发出鼠标移动事件。在 Windows 和 macOS 上,可以使用可选参数将鼠标移动消息转发到网页,从而允许发出诸如 mouseleave 之类的事件:

¥Ignoring mouse messages makes the web contents oblivious to mouse movement, meaning that mouse movement events will not be emitted. On Windows and macOS, an optional parameter can be used to forward mouse move messages to the web page, allowing events such as mouseleave to be emitted:

main.js
const { BrowserWindow, ipcMain } = require('electron')
const path = require('node:path')

const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

ipcMain.on('set-ignore-mouse-events', (event, ignore, options) => {
const win = BrowserWindow.fromWebContents(event.sender)
win.setIgnoreMouseEvents(ignore, options)
})
preload.js
window.addEventListener('DOMContentLoaded', () => {
const el = document.getElementById('clickThroughElement')
el.addEventListener('mouseenter', () => {
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
})
el.addEventListener('mouseleave', () => {
ipcRenderer.send('set-ignore-mouse-events', false)
})
})

这使得网页在 #clickThroughElement 元素上方时可以点击,并在其外部恢复正常。

¥This makes the web page click-through when over the #clickThroughElement element, and returns to normal outside it.

设置自定义可拖动区域

¥Set custom draggable region

默认情况下,无框窗口是不可拖动的。应用需要在 CSS 中指定 -webkit-app-region: drag 来告诉 Electron 哪些区域是可拖动的(例如操作系统的标准标题栏),并且应用还可以使用 -webkit-app-region: no-drag 从可拖动区域中排除不可拖动的区域。请注意,当前仅支持矩形。

¥By default, the frameless window is non-draggable. Apps need to specify -webkit-app-region: drag in CSS to tell Electron which regions are draggable (like the OS's standard titlebar), and apps can also use -webkit-app-region: no-drag to exclude the non-draggable area from the draggable region. Note that only rectangular shapes are currently supported.

要使整个窗口可拖动,你可以添加 -webkit-app-region: drag 作为 body 的样式:

¥To make the whole window draggable, you can add -webkit-app-region: drag as body's style:

styles.css
body {
-webkit-app-region: drag;
}

请注意,如果你已将整个窗口设置为可拖动,则还必须将按钮标记为不可拖动,否则用户将无法单击它们:

¥And note that if you have made the whole window draggable, you must also mark buttons as non-draggable, otherwise it would be impossible for users to click on them:

styles.css
button {
-webkit-app-region: no-drag;
}

如果你仅将自定义标题栏设置为可拖动,则还需要将标题栏中的所有按钮设置为不可拖动。

¥If you're only setting a custom titlebar as draggable, you also need to make all buttons in titlebar non-draggable.

提示:禁用文本选择

¥Tip: disable text selection

创建可拖动区域时,拖动行为可能会与文本选择发生冲突。例如,当你拖动标题栏时,你可能会意外选择其文本内容。为了防止这种情况,你需要在可拖动区域中禁用文本选择,如下所示:

¥When creating a draggable region, the dragging behavior may conflict with text selection. For example, when you drag the titlebar, you may accidentally select its text contents. To prevent this, you need to disable text selection within a draggable area like this:

.titlebar {
-webkit-user-select: none;
-webkit-app-region: drag;
}

提示:禁用上下文菜单

¥Tip: disable context menus

在某些平台上,可拖动区域将被视为非客户端框架,因此当你右键单击它时,会弹出系统菜单。为了使上下文菜单在所有平台上正常运行,你永远不应该在可拖动区域上使用自定义上下文菜单。

¥On some platforms, the draggable area will be treated as a non-client frame, so when you right click on it, a system menu will pop up. To make the context menu behave correctly on all platforms, you should never use a custom context menu on draggable areas.