Tauri 2 macOS 拖拽放大窗口闪出灰黑条纹:backgroundColor 才是真正的修法
做一个深色全出血 UI 的 Tauri 2 桌面 App,强制了 NSAppearance = darkAqua,一切看起来都很好——直到把窗口往右下拖大。拖动期间,右边缘和下边缘会闪出一道约 1~2px 宽、灰黑色(~#1e1e1e)的条纹,松手后立刻消失,内容回弹对齐。看起来像撕裂,像闪烁,像没写完——但代码一行都没有错。
现象
- 仅在 拖拽放大(或最大化)时出现,缩小或静止不触发。
- 条纹颜色是 macOS dark mode 默认窗口底色(约
#1e1e1e灰黑),而非应用的深色主题色。 - 若未强制 dark appearance,条纹可能是白色(light mode 窗口底色)。
- 松手后内容「弹回」对齐,慢半拍,像掉帧。
根因
这是一个 WebKit 的已知局限,不是代码写错了。
macOS 原生窗口在 live resize 时,NSWindow 的尺寸变化频率是原生帧率(60/120fps)。但 WKWebView 的重绘要跟着走 WebKit 的渲染管线,而 WebKit 跟不上这个速度。结果:
窗口已经变大了,WebView 还没画完新区域 → 新区域暂时显示窗口/WebView 的背景色。
Tauri 官方维护者在 GitHub Discussion #2970 里明确承认:"That's webkit being not so perfect (again)." 重绘延迟本身无法消除(Issue #14288 至今未关)。
条纹的颜色来自 NSWindow 和 WKWebView 的原生背景色,不是 HTML/CSS 的 background 属性。你把 html, body { background: #060a12 } 写得再精准,CSS 也只作用于 WebView 已渲染的内容区域,对尚未完成重绘的「新增边缘」无能为力。
Tauri 1 时代确实有"设 backgroundColor 没用"的说法——那是因为 Tauri 1 只对 NSWindow 设背景色,WebView 层还是系统默认。Tauri 2 已修复:backgroundColor 会同时调用 window_builder.background_color() 和 webview_builder.background_color(),两层都覆盖到。
正解
无法消除重绘延迟,但可以让那道条纹变得肉眼不可见——把窗口/WebView 的背景色设成与应用边缘完全一致的颜色。
在 src-tauri/tauri.conf.json 的 window 配置里加:
{
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"theme": "Dark",
"backgroundColor": "#060a12"
}backgroundColor 接受 #rgb、#rrggbb、#rrggbbaa 十六进制,或 [r, g, b]/[r, g, b, a] 数组。选的颜色要和应用的边缘/底板色一致,让 transient 条纹与内容「视觉上同色」,用户根本看不出来。
同时在 CSS 加一层防御(成本极低):
html, body, #root {
height: 100%;
margin: 0;
background: #060a12;
}Tauri 2 的 backgroundColor 才是真正作用于原生背景的入口。填入与应用边缘匹配的深色,resize 期间暴露的区域和内容颜色融为一体,条纹消失。
验证
- 改完后必须完整重建(
cargo tauri dev或cargo tauri build),backgroundColor在窗口创建时应用,不支持热重载。 cargo check会通过generate_context!校验tauri.conf.jsonschema,无效 hex 直接编译报错,失败就能发现写错颜色值。- 往各方向拖大窗口:边缘条纹应与应用底色一致,不再有视觉割裂感;内容仍会晚一帧到位,但已不刺眼。
踩坑备注
transparent: true也能让条纹「消失」,但副作用是失去原生窗口阴影和边框,桌面壁纸会透进来——不要为了解决这个 bug 引入 transparent。resizable: false则是用禁掉 resize 来回避问题,不是修复。- 强制 dark appearance(
NSApp.appearance = darkAqua)后,条纹从白色变成灰黑色,但修法完全一样。
一句话外卖
Tauri 2 macOS live resize 的边缘闪色,根子在 WKWebView 重绘跟不上原生窗口,唯一有效的遮盖手段是用
tauri.conf.json的backgroundColor把原生背景色对齐应用底色,CSS 改不到那一层。