关于我对webview的一些看法
最近在研究 webview 应用框架。试了三种方案,记录一下实际体验。
需求
- 移除原生标题栏,用 HTML/CSS 绘制
- 支持拖拽、最小化、最大化/还原、关闭
- 深色主题,风格统一
- 跨平台最好
方案一:C webview
webview/webview 是个很轻量的 C 库,Windows 基于 WebView2,macOS 用 WebKit。
基础用法很简单:
#define WEBVIEW_HEADER
#include "webview.h"
webview_t w = webview_create(0, NULL);
webview_set_html(w, "<h1>Hello</h1>");
webview_run(w);
webview_destroy(w);
但到自定义标题栏就开始折腾了。库本身不提供隐藏标题栏的接口,你得自己创建一个 popup 父窗口把 WebView2 嵌进去,然后手写 WM_NCCALCSIZE、WM_SIZE、拖拽消息处理,大概一百多行 C 代码。而且旧版单头文件还有白屏问题,需要自己改库代码 SetWindowPos 居中。新版虽然好了不少,但还是得自己糊 Win32。
结论:轻量(200KB),适合熟悉 Win32 的人,但自定义标题栏成本不低。
方案二:Tauri(Rust + 前端)
Tauri 2 的做法就省心多了。配置里关掉原生装饰:
{
"app": {
"windows": [{ "decorations": false }]
}
}
HTML 里加个属性就能拖拽:
<div data-tauri-drag-region>
<span>自定义标题栏</span>
<button data-removed="window.__TAURI__.window.getCurrent().minimize()">—</button>
<button data-removed="window.__TAURI__.window.getCurrent().close()">✕</button>
</div>
拖拽、双击最大化全是原生行为,不需要你写任何底层逻辑。按钮调内置 API,一行一个功能。
编译出来 8MB,启动快。跨平台也是原生支持。
结论:开发体验最好,标题栏功能开箱即用。
方案三:pywebview + Nuitka
Python 版 webview,写起来也快:
import webview
window = webview.create_window('标题', html=html, frameless=True, js_api=Api())
webview.start()
标题栏用 CSS -webkit-app-region: drag 拖拽,按钮调 window.minimize() 这些。
但打包坑比较多。Nuitka 的 pywebview 插件会排除 win32 平台模块,编译时得加 --disable-plugin=pywebview。打包出来 13MB exe + 依赖 DLL 总共 28MB,启动也比前两个慢。
结论:Python 开发确实快,但分发体积大、启动慢、打包有坑。
对比
| C webview | Tauri | pywebview+Nuitka | |
|---|---|---|---|
| exe 大小 | 200KB | 8MB | 13MB |
| 分发总大小 | 200KB | 8MB | ~28MB |
| 启动速度 | 最快 | 快 | 较慢 |
| 标题栏实现 | 手写 Win32 API | data-tauri-drag-region |
-webkit-app-region + CSS |
| 拖拽 | WM_NCLBUTTONDOWN | 原生 | CSS 属性 |
| 按钮功能 | ShowWindow | window.__TAURI__ |
pywebview Window API |
| 开发门槛 | 高(需要 Win32 经验) | 低(前端思维) | 低(Python 思维) |
| 打包复杂度 | 无 | 低 | 有坑 |
个人看法
试下来觉得 Tauri 最方便。标题栏这块 Tauri 当基础设施做了,CSS 属性控制拖拽区、JS API 控制窗口行为,不需要跟 Win32 打交道。虽然打包体积比 C 方案大,但开发省的时间值这个差价。