Arc 浏览器:重新想象浏览器界面

深入剖析Arc Browser的设计系统:侧边栏导航、Spaces、命令栏、Boosts,以及革命性的设计模式。包含CSS、SwiftUI和TypeScript代码示例。

4 分钟阅读 198 字
Arc 浏览器:重新想象浏览器界面 screenshot

Arc 浏览器:重新构想浏览器界面

"浏览器现在就是操作系统。那为什么它看起来还像 2008 年的软件?" — Josh Miller,The Browser Company

Arc 质疑了每一个浏览器的既有假设,从标签页位置到窗口管理。最终呈现的是一款更像创意工具而非实用程序的浏览器。


核心要点

  1. 垂直侧边栏胜过水平标签栏 - 标签标题保持可读,现代宽屏显示器上垂直空间充裕
  2. 空间分离心理情境 - 工作、个人和项目标签页互不混淆,减少认知负担
  3. 命令栏 > 地址栏 - 跨标签页、历史记录和操作的全局搜索,无需完美的整理归类
  4. 用户自定义培养忠诚度 - Boosts 让用户自行修复恼人的网站,建立个人投入感
  5. 界面复杂度匹配任务需求 - Little Arc 证明并非每个任务都需要完整的浏览器界面

Arc 的重要意义

Arc 证明了即使是最根深蒂固的界面也能被重新构想。Chrome、Firefox、Safari 都遵循着几十年前确立的相同基本布局。Arc 通过将浏览器视为工作空间而非窗口管理器,打破了这一桎梏。

核心成就: - 彻底取消了传统的标签栏 - 让浏览器界面与 macOS 浑然一体 - 实现了真正有意义的个人与工作分离 - 开创了浏览器级别的网站自定义功能 - 专为键盘优先导航而打造


核心设计原则

1. 侧边栏革命

Arc 最引人注目的创新:用垂直侧边栏取代水平标签页,按上下文而非时间顺序组织内容。

传统标签栏:
┌──────────────────────────────────────────────────────────────┐
│ [←][→][↻] │ Tab 1 │ Tab 2 │ Tab 3 │ Tab 4 │ Tab 5 │ ... │ + │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│                    页面内容                                   │
│                                                              │
└──────────────────────────────────────────────────────────────┘
 问题:标签缩小至无法阅读、缺乏组织、无尽的横向排列

ARC 侧边栏模型:
┌────────────────┬─────────────────────────────────────────────┐
│  [*] 空间      │                                             │
│  ───────────── │                                             │
│  固定          │                                             │
│    Gmail       │                                             │
│    日历        │          页面内容                           │
│    Notion      │          (全宽)                           │
│                │                                             │
│  ───────────── │                                             │
│  今日          │                                             │
│    标签页 1    │                                             │
│    标签页 2    │                                             │
│    标签页 3    │                                             │
│                │                                             │
│  [+ 新建标签页]│                                             │
└────────────────┴─────────────────────────────────────────────┘
 优势:可读的标题、固定收藏夹、按用途整理

核心洞察:水平空间是稀缺的;垂直空间是充裕的。使用侧边栏让标签标题有呼吸空间。

CSS 模式(可折叠侧边栏):

.sidebar {
  --sidebar-width: 240px;
  --sidebar-collapsed: 48px;

  width: var(--sidebar-width);
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
  transition: width 0.2s ease-out;
}

.sidebar.collapsed {
  width: var(--sidebar-collapsed);
}

.sidebar.collapsed .tab-title {
  opacity: 0;
  pointer-events: none;
}

/* 悬停预览 */
.sidebar.collapsed:hover {
  width: var(--sidebar-width);
}

.sidebar.collapsed:hover .tab-title {
  opacity: 1;
  transition: opacity 0.15s ease-in 0.1s; /* 延迟以实现平滑展现 */
}

SwiftUI 模式:

struct SidebarView: View {
    @State private var isCollapsed = false
    @State private var isHovering = false

    private var effectiveWidth: CGFloat {
        isCollapsed && !isHovering ? 48 : 240
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            PinnedSection()
            Divider()
            TodaySection()
            Spacer()
            NewTabButton()
        }
        .frame(width: effectiveWidth)
        .animation(.easeOut(duration: 0.2), value: effectiveWidth)
        .onHover { isHovering = $0 }
    }
}

2. 空间:基于情境的组织方式

空间将工作与个人内容分开,将不同项目彼此隔离。每个空间都是一个完整的浏览器上下文,拥有独立的标签页、固定网站,甚至独立的主题。

空间架构:

┌─────────────────────────────────────────────────────────────┐
│                        Arc 浏览器                           │
├───────────┬───────────┬───────────┬─────────────────────────┤
│  工作     │  个人     │  项目     │                         │
│  空间     │  空间     │  空间     │    内容区域             │
│  ─────    │  ─────    │  ─────    │                         │
│  • Slack  │  • Gmail  │  • GitHub │                         │
│  • Docs   │  • Reddit │  • Figma  │                         │
│  • Jira   │  • Netflix│  • Notion │                         │
└───────────┴───────────┴───────────┴─────────────────────────┘

Each Space has:
├── 独立的固定标签页
├── 独立的「今日」标签页
├── 专属颜色主题/渐变
├── 隔离的浏览上下文
└── 键盘快捷键 (Cmd+1, Cmd+2, 等)

核心洞察:心理场景不应相互渗透。在个人时间看到工作标签页会产生认知摩擦。

数据模型:

interface Space {
  id: string;
  name: string;
  icon?: string;
  gradient: {
    from: string;
    to: string;
    angle: number;
  };
  pinnedTabs: Tab[];
  todayTabs: Tab[];
  archivedTabs: Tab[];
  profile?: BrowserProfile; // 不同的 cookies、历史记录等
}

interface Tab {
  id: string;
  url: string;
  title: string;
  favicon?: string;
  isPinned: boolean;
  lastAccessed: Date;
  parentFolderId?: string;
}

SwiftUI 实现:

struct SpaceSwitcher: View {
    @Binding var currentSpace: Space
    let spaces: [Space]

    var body: some View {
        HStack(spacing: 8) {
            ForEach(spaces) { space in
                SpaceButton(
                    space: space,
                    isActive: space.id == currentSpace.id
                ) {
                    withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) {
                        currentSpace = space
                    }
                }
            }
        }
        .padding(.horizontal, 12)
    }
}

struct SpaceButton: View {
    let space: Space
    let isActive: Bool
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            Circle()
                .fill(
                    LinearGradient(
                        colors: [space.gradient.from, space.gradient.to],
                        startPoint: .topLeading,
                        endPoint: .bottomTrailing
                    )
                )
                .frame(width: 24, height: 24)
                .overlay {
                    if isActive {
                        Circle()
                            .strokeBorder(.white, lineWidth: 2)
                    }
                }
        }
        .buttonStyle(.plain)
        .keyboardShortcut(space.keyboardShortcut)
    }
}

3. 命令栏:浏览器中的 Spotlight

Arc 的命令栏(Cmd+T)不仅仅是一个地址栏,它提供跨标签页、历史记录、书签和操作的全局搜索。

命令栏交互:

┌─────────────────────────────────────────────────────────────┐
│  > 搜索标签页、历史记录或输入网址...                        │
├─────────────────────────────────────────────────────────────┤
│  打开的标签页                                               │
│    [doc] Notion - 项目规划                    Cmd+1         │
│    [doc] GitHub - Pull Request #123                         │
│                                                             │
│  历史记录                                                   │
│    [>] Figma - 设计系统(2小时前)                          │
│    [>] MDN - CSS Grid 指南(昨天)                          │
│                                                             │
│  操作                                                       │
│    [*] 新建笔记                               Cmd+Shift+N   │
│    [*] 分屏视图                               Cmd+Shift+\   │
│    [*] 复制网址                               Cmd+Shift+C   │
└─────────────────────────────────────────────────────────────┘

核心洞见:查找应该比整理更快。优秀的搜索功能消除了对完美整理的需求。

CSS 模式:

.command-bar {
  --bar-width: min(600px, 90vw);

  position: fixed;
  top: 20%;
  left: 50%;
  transform: translateX(-50%);
  width: var(--bar-width);
  background: var(--surface-elevated);
  border-radius: var(--radius-lg);
  box-shadow:
    0 4px 24px rgba(0, 0, 0, 0.2),
    0 0 0 1px rgba(255, 255, 255, 0.1);
  overflow: hidden;
}

.command-input {
  width: 100%;
  padding: 16px 20px;
  font-size: 18px;
  background: transparent;
  border: none;
  color: var(--text-primary);
}

.command-results {
  max-height: 400px;
  overflow-y: auto;
  border-top: 1px solid var(--border-subtle);
}

.command-result {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 20px;
  cursor: pointer;
}

.command-result:hover,
.command-result.selected {
  background: var(--surface-hover);
}

.command-result-shortcut {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-secondary);
  font-family: var(--font-mono);
}

4. Boosts:用户级自定义

Boosts 允许用户向任何网站注入自定义 CSS 和 JavaScript:个人深色模式、简洁界面或增强功能。

BOOST 概念:

无 Boost:                        有 Boost:
┌─────────────────────┐          ┌─────────────────────┐
│ [页眉]              │          │                     │
│ [导航]              │          │                     │
│ [侧边栏] [内容]     │    →     │     [内容]          │
│ [页脚]              │          │     (简洁、专注)  │
│ [Cookie 横幅]       │          │                     │
└─────────────────────┘          └─────────────────────┘

用户自定义 CSS:

- 隐藏干扰元素

- 更改颜色/字体

- 改善可读性

关键洞察:每个用户都有每天访问但希望能有不同体验的网站。让他们掌握控制权。

实现模式:

interface Boost {
  id: string;
  name: string;
  domain: string; // "github.com" or "*.google.com"
  enabled: boolean;
  css?: string;
  js?: string;
  createdAt: Date;
}

// 示例 Boost:简洁 YouTube
const youtubeBoost: Boost = {
  id: 'youtube-clean',
  name: 'Clean YouTube',
  domain: 'youtube.com',
  enabled: true,
  css: `
    /* 隐藏推荐内容 */
    #secondary,
    ytd-browse[page-subtype="home"] ytd-rich-grid-renderer {
      display: none !important;
    }

    /* 隐藏评论 */
    #comments {
      display: none !important;
    }

    /* 扩展视频 */
    #primary {
      max-width: 100% !important;
    }
  `
};

SwiftUI Boost 编辑器:

struct BoostEditor: View {
    @Binding var boost: Boost
    @State private var activeTab: BoostTab = .css

    enum BoostTab: String, CaseIterable {
        case css = "CSS"
        case javascript = "JavaScript"
    }

    var body: some View {
        VStack(spacing: 0) {
            // 域名选择器
            HStack {
                Image(systemName: "globe")
                TextField("域名(例如:github.com)", text: $boost.domain)
                    .textFieldStyle(.plain)
            }
            .padding()
            .background(.ultraThinMaterial)

            // 选项卡选择器
            Picker("", selection: $activeTab) {
                ForEach(BoostTab.allCases, id: \.self) { tab in
                    Text(tab.rawValue).tag(tab)
                }
            }
            .pickerStyle(.segmented)
            .padding()

            // 代码编辑器
            CodeEditor(
                text: activeTab == .css ? $boost.css : $boost.js,
                language: activeTab == .css ? .css : .javascript
            )
        }
    }
}

5. Little Arc:极简设计

Little Arc 是一个独立的极简窗口,专为快速任务设计:单标签页、无界面元素、无干扰。

完整版 ARC:                        LITTLE ARC:
┌────────┬────────────────┐      ┌────────────────────────┐
│侧边栏  │                │      │ ← google.com/search... │
│        │    内容        │      ├────────────────────────┤
│        │                │      │                        │
│        │                │  →   │    搜索结果            │
│        │                │      │    (仅显示内容)      │
└────────┴────────────────┘      └────────────────────────┘

使用场景:

- 快速搜索

- 快速查看某项内容

- 从其他应用打开链接

关键洞察:并非每个任务都需要完整的浏览器界面。应根据任务的复杂程度匹配相应的界面。

CSS 模式(极简边框):

.mini-browser {
  --chrome-height: 36px;

  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}

.mini-chrome {
  height: var(--chrome-height);
  display: flex;
  align-items: center;
  padding: 0 12px;
  background: var(--surface-1);
  gap: 8px;
}

.mini-url-bar {
  flex: 1;
  padding: 4px 8px;
  font-size: 13px;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
}

.mini-content {
  height: calc(100% - var(--chrome-height));
}

可迁移模式

模式 1:临时性与持久性

Arc 的"今日"区域会在 12 小时后自动归档标签页。持久项必须显式固定。

interface EphemeralityConfig {
  defaultLifetime: number; // 毫秒
  onExpire: 'archive' | 'close' | 'prompt';
  exceptions: string[]; // 永不过期的域名
}

function shouldArchive(tab: Tab, config: EphemeralityConfig): boolean {
  const age = Date.now() - tab.lastAccessed.getTime();
  if (config.exceptions.includes(new URL(tab.url).hostname)) {
    return false;
  }
  return age > config.defaultLifetime;
}

模式 2:分屏视图

无需管理多个窗口即可实现并排浏览。

struct SplitView: View {
    @State private var splitRatio: CGFloat = 0.5
    let leftTab: Tab
    let rightTab: Tab

    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: 1) {
                WebView(tab: leftTab)
                    .frame(width: geometry.size.width * splitRatio)

                // 可拖动分隔条
                Rectangle()
                    .fill(.quaternary)
                    .frame(width: 4)
                    .gesture(
                        DragGesture()
                            .onChanged { value in
                                let newRatio = value.location.x / geometry.size.width
                                splitRatio = max(0.2, min(0.8, newRatio))
                            }
                    )

                WebView(tab: rightTab)
            }
        }
    }
}

模式 3:渐变标识

每个 Space 都有独特的渐变效果,提供即时的视觉识别。

.space-gradient {
  --gradient-work: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  --gradient-personal: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  --gradient-project: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}

.space-indicator {
  width: 100%;
  height: 4px;
  background: var(--current-gradient);
}

.space-badge {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--current-gradient);
  display: flex;
  align-items: center;
  justify-content: center;
}

设计启示

  1. 挑战既有假设:标签栏并非神圣不可侵犯,任何事物皆可重新审视
  2. 情境分离:不同任务值得拥有不同的工作环境
  3. 键盘优先:高效用户无需依赖鼠标即可完成导航
  4. 渐进式复杂度:默认保持简洁,需要时展现强大功能
  5. 用户自定义:让用户能够打造属于自己的软件体验
  6. 适度的界面分量:界面复杂度应与任务复杂度相匹配

常见问题

为什么 Arc 使用垂直侧边栏而非水平标签栏?

当打开大量页面时,水平标签会缩小到难以辨认的宽度。而垂直侧边栏充分利用了现代宽屏显示器充裕的屏幕高度,使标签标题始终完整可见。侧边栏还支持固定区域和文件夹等组织功能,这些在水平布局中难以实现。

Arc 的空间功能与浏览器配置文件有何不同?

空间功能比完整的浏览器配置文件更加轻量。配置文件会创建完全独立的浏览器实例(拥有不同的 Cookie、历史记录和扩展程序),而空间共享您的浏览器设置,仅按情境组织标签页。您可以通过键盘快捷键即时切换空间,而切换配置文件则需要重新启动或打开新窗口。

Arc「今日」区域中的标签页会怎样?

今日区域中的标签页在 12 小时无活动后会自动归档。它们不会被删除,而是移至可搜索的归档区域。 这防止了标签页囤积,同时保持内容可恢复。固定的标签页永远不会被自动归档。

我可以在自己的应用中使用 Arc 的设计模式吗?

可以。这里记录的模式(可折叠侧边栏、命令面板、Spaces 架构、Boost 系统)都是可迁移的概念。代码示例展示了 CSS、SwiftUI 和 TypeScript 实现,你可以进行调整。侧边栏和命令栏模式特别适合任何内容密集型应用。

Arc 的 Command Bar 如何改进传统地址栏?

传统地址栏搜索历史记录并建议 URL。Arc 的 Command Bar 通过单一输入搜索打开的标签页、历史记录、书签和可用操作。你可以找到打开的标签页、运行命令或导航到新位置,无需切换上下文或记住某些内容的位置。


参考资料