---
url: /dev/8zoti5ag/index.md
description: 基于 Tauri 2 实现隐藏原生标题栏、自绘 macOS 风格交通灯按钮、可拖拽 Titlebar 及圆角窗体的完整指南。
---
# Tauri 自定义 Titlebar 与窗体圆角实现指南

## 概述

基于 Tauri 2 + 前端框架（Vue / React / Svelte 等）实现 macOS 风格的自定义窗口外观：隐藏原生标题栏，自绘红黄绿交通灯按钮，可拖拽 Titlebar，以及圆角窗体。**所有窗口样式逻辑均在前端完成，Rust 后端无窗口相关代码。**

## 一、架构总览

```
tauri.conf.json          → 禁用原生装饰 + 透明窗口
Cargo.toml               → 启用 macOS 私有 API feature
capabilities/default.json → 授权前端窗口操作权限
Titlebar 组件             → 交通灯按钮 + 拖拽区域
全局样式                  → Titlebar 样式 + 窗体圆角
```

## 二、Tauri 配置层

### 2.1 `tauri.conf.json` 关键配置

```json
{
  "app": {
    "macOSPrivateApi": true,
    "windows": [{
      "decorations": false,
      "transparent": true,
      "resizable": true,
      "fullscreen": false,
      "center": true
    }]
  }
}
```

三个配置缺一不可：

| 配置项 | 作用 | 缺失后果 |
|---|---|---|
| `macOSPrivateApi: true` | 允许使用 macOS 私有窗口 API | `transparent` 在 macOS 上不生效 |
| `decorations: false` | 移除原生标题栏 | 自定义 Titlebar 会被原生栏遮挡 |
| `transparent: true` | 窗口背景透明 | 圆角处露出矩形窗口底色 |

### 2.2 `Cargo.toml` Feature Flag

```toml
tauri = { version = "2.0", features = ["macos-private-api"] }
```

与 `tauri.conf.json` 中的 `macOSPrivateApi: true` 配对，是 Rust 侧的等效开关。

### 2.3 `capabilities/default.json` 权限声明

```json
"permissions": [
    "core:window:allow-start-dragging",
    "core:window:allow-close",
    "core:window:allow-minimize",
    "core:window:allow-toggle-maximize",
    "core:window:allow-set-size",
    "core:window:allow-set-position",
    "core:window:allow-center",
    "core:window:allow-is-maximized"
]
```

> `allow-start-dragging` 是 `data-tauri-drag-region` 属性生效的必要权限，缺少则拖拽失效。

## 三、自定义 Titlebar

### 3.1 组件结构

以下以 HTML 结构为例，适配任意前端框架：

```html
<header class="app-titlebar" data-tauri-drag-region ondblclick="handleTitlebarDblClick">
  <div class="titlebar-left">
    <div class="traffic-lights">
      <button class="traffic-light traffic-close" onclick="handleClose()">
        <!-- 关闭图标 SVG -->
      </button>
      <button class="traffic-light traffic-minimize" onclick="handleMinimize()">
        <!-- 最小化图标 SVG -->
      </button>
      <button class="traffic-light traffic-maximize" onclick="handleMaximize()">
        <!-- 最大化图标 SVG -->
      </button>
    </div>
    <div class="titlebar-brand">
      <span class="app-title">应用名称</span>
    </div>
  </div>
  <div class="titlebar-right">
    <!-- 放置自定义按钮：设置、搜索等 -->
  </div>
</header>
```

> `data-tauri-drag-region` 声明在 `<header>` 上，使整个标题栏区域可拖拽移动窗口。

### 3.2 窗口控制逻辑

```typescript
import { getCurrentWindow } from '@tauri-apps/api/window'

const appWindow = getCurrentWindow()

function handleTitlebarDblClick() { appWindow.toggleMaximize() }
function handleMinimize()         { appWindow.minimize() }
function handleMaximize()         { appWindow.toggleMaximize() }
function handleClose()            { appWindow.close() }
```

* 双击 Titlebar 区域触发最大化/还原（模拟 macOS 原生行为）
* 按钮各自调用 Tauri Window API

### 3.3 拖拽区域实现

**两种方式并存（双重保障）：**

| 方式 | 属性 | 说明 |
|---|---|---|
| Tauri 原生 | `data-tauri-drag-region` | Tauri 识别此属性后自动处理窗口拖拽 |
| Webkit CSS | `-webkit-app-region: drag` | Webview 兼容层，确保在各平台生效 |

交互元素（按钮、链接）需要排除在拖拽区域外：

```css
.app-titlebar {
  -webkit-app-region: drag;        /* 整个 header 可拖拽 */
}
.app-titlebar button,
.app-titlebar a {
  -webkit-app-region: no-drag;     /* 子元素不参与拖拽 */
}
```

### 3.4 交通灯按钮样式

**尺寸与布局：**

```css
.traffic-lights {
  display: flex;
  align-items: center;
  gap: 8px;
}
.traffic-light {
  width: 12px;           /* 圆形直径 12px */
  height: 12px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
}
```

**颜色系统：**

| 按钮 | 默认色 | Hover 色 |
|---|---|---|
| 关闭（红） | `#ff5f57` | `#ff3b30` |
| 最小化（黄） | `#febc2e` | `#f5a623` |
| 最大化（绿） | `#28c840` | `#20b835` |

**Hover 交互（模拟 macOS 原生行为）：**

```css
.traffic-light {
  color: transparent;               /* SVG 图标默认隐藏 */
}
.traffic-light svg {
  opacity: 0;
}
.traffic-lights:hover .traffic-light svg {
  opacity: 1;                       /* hover 整组时所有图标同时显现 */
}
.traffic-light:hover {
  color: rgba(0, 0, 0, 0.6);       /* 图标变为深色 */
}
```

> 图标使用 `currentColor` 继承 `color`，`opacity` 控制显隐。当鼠标 hover 任意一个交通灯按钮时，**三个图标同时显示**（通过父级 `.traffic-lights:hover` 触发），与 macOS 原生行为完全一致。

### 3.5 Titlebar 整体尺寸

```css
.app-titlebar {
  height: 42px;
  padding: 0 12px;
  background: var(--color-bg-white);
  border-bottom: 1px solid var(--color-border-light);
  user-select: none;
  flex-shrink: 0;
}
```

## 四、窗体圆角

### 4.1 实现原理

```
┌─ Tauri 原生窗口（透明，无装饰）──────────────────┐
│                                                     │
│  ┌─ .app-container (border-radius: 10px) ──────┐   │
│  │                                              │   │
│  │   所有可见 UI 内容                             │   │
│  │                                              │   │
│  └──────────────────────────────────────────────┘   │
│                                                     │
└─────────────────────────────────────────────────────┘
```

* Tauri 窗口本身是**透明无边框的矩形**
* `.app-container` 是唯一可见的内容层，设置了圆角
* `overflow: hidden` 裁切掉圆角外的内容

### 4.2 CSS 实现

```css
html, body {
  background: transparent;    /* webview 背景透明 */
}

.app-container {
  height: 100vh;
  background: var(--color-bg-light);
  border-radius: 10px;
  overflow: hidden;
}
```

### 4.3 注意事项

| 要点 | 说明 |
|---|---|
| `transparent: true` 必须 | 否则原生窗口的矩形底色会露出，圆角无效 |
| `overflow: hidden` 必须 | 否则子元素会溢出圆角区域 |
| `html, body` 必须透明 | 否则 webview 层的背景色会遮挡圆角效果 |
| 全屏模式 | `fullscreen: false` 默认关闭；全屏时圆角无意义 |

## 五、常见问题排查

| 问题 | 排查方向 |
|---|---|
| 窗口不透明 / 圆角无效 | 检查 `macOSPrivateApi`、`transparent`、`Cargo.toml` feature 三处是否全部启用 |
| 标题栏无法拖拽 | 检查 `capabilities/default.json` 是否声明 `allow-start-dragging` |
| 按钮点击无效 | 检查是否有 `-webkit-app-region: no-drag` 排除按钮 |
| 交通灯颜色不对 | 暗色主题下需要额外覆盖交通灯颜色 |
| 窗口闪烁 / 白边 | `html, body { background: transparent }` 是否在最顶层 CSS 生效 |
