Electron 中 100vw/vh 不准因按客户区计算,不含系统标题栏等;需主进程同步窗口尺寸+渲染进程动态设置样式,并配合 zoomFactor 和自定义标题栏偏移修正。

Electron 中的 vw/vh 单位默认按 BrowserWindow 的客户区(client area)计算,不包含系统标题栏、边框或 macOS 的 traffic light 区域——这意味着直接用 100vw 布局会溢出或留白,根本“不完美”。要真正适配视窗比例,必须区分「逻辑视窗」和「物理窗口」,并主动干预缩放与尺寸映射关系。
为什么 100vw 在 Electron 里不准?
Chromium 渲染器只感知 BrowserWindow 内部的可绘制区域(即 webContents 容器尺寸),而系统级窗口装饰(如 Windows 标题栏、macOS 窗口控制按钮)由 OS 绘制,不在 CSS 视口范围内。结果就是:
-
document.documentElement.clientWidth≠BrowserWindow.getBounds().width - 拖拽调整窗口大小时,
vw值跳变,但 DOM 元素未同步重排 - 高 DPI 屏幕下,
devicePixelRatio影响实际像素密度,但vw不自动补偿
用 setBounds() + getBounds() 主动对齐物理尺寸
当需要严格按屏幕像素比例布局(比如全屏图表、视频画布、自定义标题栏延伸),应放弃纯 CSS 视口单位,改用主进程同步窗口尺寸 + 渲染进程动态设置根字体或容器宽高:
- 在主进程中监听
resize事件,调用win.getBounds()获取真实像素尺寸 - 通过 IPC 向渲染进程发送
{ width, height, scale }(含screen.getPrimaryDisplay().scaleFactor) - 渲染进程收到后,用 JS 设置
document.documentElement.style.fontSize或直接修改容器style.width/style.height - 避免用
vw做关键布局,改用%或flex配合 JS 控制的基准值
启用 webPreferences.zoomFactor 统一缩放基准
Electron 默认禁用页面缩放,但桌面端多显示器场景下,各屏 scaleFactor 可能不同(如 1.25 和 2.0)。若 UI 元素需保持视觉一致尺寸,应在创建 BrowserWindow 时显式设置缩放:
立即学习“前端免费学习笔记(深入)”;
new BrowserWindow({
webPreferences: {
zoomFactor: screen.getPrimaryDisplay().scaleFactor
}
})
注意:zoomFactor 会影响所有 CSS 单位(包括 px),但它不改变 vw/vh 的计算基数——所以它适合统一字体/图标大小,但不能修复 100vw 溢出问题。
自定义标题栏时必须重写视口边界
启用 frame: false 后,整个窗口变成无边框,此时 BrowserWindow 的 bounds 就是真正的物理边界,但 document.body 仍默认以客户区为视口。解决方案是:
- 用
win.setMenuBarVisibility(false)和win.setAspectRatio(16/9)锁定比例 - 在 HTML 中添加
<meta name="viewport" content="width=device-width, initial-scale=1.0">(虽非移动端,但能强制 Chromium 使用窗口宽度为视口基准) - CSS 中用
height: 100vh配合body { margin: 0; padding: 0; },再通过 JS 调整body.style.height = win.getBounds().height + 'px'
最易被忽略的是:macOS 下即使 frame: false,traffic light 区域仍占用顶部约 22px(未隐藏时),这部分空间不会反映在 getBounds() 中,但会挤压渲染区域——必须用 win.setWindowButtonPosition({ x: 10, y: 10 }) 手动偏移控制按钮位置,才能真正释放全部高度。


















