Arc Browser:ブラウザクロームの再発明

Arc Browserのデザインシステムを徹底解説:サイドバーナビゲーション、Spaces、コマンドバー、Boosts、そして革命的なパターン。CSS、SwiftUI、TypeScriptのコード例付き。

6 分で読める 141 語
Arc Browser:ブラウザクロームの再発明 screenshot

Arcブラウザ:ブラウザクロームの再定義

「ブラウザは今やオペレーティングシステムだ。なのになぜ2008年のソフトウェアのように見えるのか?」 — Josh Miller, The Browser Company

Arcは、タブの配置からウィンドウ管理まで、ブラウザのあらゆる前提を問い直した。その結果、ユーティリティアプリケーションというよりも、クリエイティブツールのように感じられるブラウザが生まれた。


主なポイント

  1. 垂直サイドバーは水平タブに勝る - タブタイトルが読みやすく、現代のワイドスクリーンモニターでは垂直方向のスペースが豊富
  2. スペースがメンタルコンテキストを分離 - 仕事、プライベート、プロジェクトのタブが混在せず、認知的な摩擦を軽減
  3. コマンドバー > URLバー - タブ、履歴、アクションを横断するユニバーサル検索により、完璧な整理が不要に
  4. ユーザーカスタマイズがロイヤリティを構築 - Boostsでユーザーが煩わしいサイトを自分で修正でき、個人的な投資が生まれる
  5. タスクに合わせたインターフェースの重さ - Little Arcは、すべてのタスクにフルブラウザクロームが必要ではないことを証明

Arcが重要な理由

Arcは、最も定着したインターフェースでさえ再構築できることを証明した。Chrome、Firefox、Safariはすべて、数十年前に確立された同じ基本レイアウトに従っている。Arcはブラウザをウィンドウマネージャーではなくワークスペースとして扱うことで、その枠組みから脱却した。

主な成果: - 従来のタブバーを完全に廃止 - ブラウザクロームをmacOSネイティブな外観に仕上げた - 仕事とプライベートの意味のある分離を実現 - ブラウザレベルでのサイトカスタマイズを先駆的に実現 - キーボードファーストのナビゲーション向けに設計


コアデザイン原則

1. サイドバー革命

Arcの最も目に見える革新:水平タブを垂直サイドバーに置き換え、最新順ではなくコンテキストでコンテンツを整理。

TRADITIONAL TAB BAR:
┌──────────────────────────────────────────────────────────────┐
│ [←][→][↻] │ Tab 1 │ Tab 2 │ Tab 3 │ Tab 4 │ Tab 5 │ ... │ + │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│                    Page Content                              │
│                                                              │
└──────────────────────────────────────────────────────────────┘
 Problems: Tabs shrink to unreadable, no organization, endless row

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 Browser                          │
├───────────┬───────────┬───────────┬─────────────────────────┤
│  ワーク   │ パーソナル│ プロジェ  │                         │
│  スペース │  スペース │ クト      │    コンテンツエリア     │
│  ─────    │  ─────    │ スペース  │                         │
│  • Slack  │  • Gmail  │  ─────    │                         │
│  • Docs   │  • Reddit │  • GitHub │                         │
│  • Jira   │  • Netflix│  • Figma  │                         │
│           │           │  • Notion │                         │
└───────────┴───────────┴───────────┴─────────────────────────┘

各Spaceには以下の要素があります:
├── 固有のピン留めタブ
├── 独立した「Today」タブ
├── 専用のカラーテーマ/グラデーション
├── 分離されたブラウジングコンテキスト
└── キーボードショートカット(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; // Different cookies, history, etc.
}

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のコマンドバーはURLバー以上の存在です。タブ、履歴、ブックマーク、アクションを横断したユニバーサル検索を提供します。

COMMAND BAR INTERACTION:

┌─────────────────────────────────────────────────────────────┐
│  > タブ、履歴を検索、またはURLを入力...                      │
├─────────────────────────────────────────────────────────────┤
│  開いているタブ                                             │
│    [doc] Notion - プロジェクト計画            Cmd+1         │
│    [doc] GitHub - プルリクエスト #123                       │
│                                                             │
│  履歴                                                       │
│    [>] Figma - デザインシステム(2時間前)                   │
│    [>] MDN - CSSグリッドガイド(昨日)                       │
│                                                             │
│  アクション                                                 │
│    [*] 新規メモ                               Cmd+Shift+N   │
│    [*] 分割表示                               Cmd+Shift+\   │
│    [*] URLをコピー                            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. ブースト:ユーザーレベルのカスタマイズ

ブーストを使用すると、ユーザーは任意のウェブサイトにカスタムCSSやJavaScriptを注入できます:個人用ダークモード、すっきりしたインターフェース、機能の強化などが実現可能です。

BOOST CONCEPT:

Boostなし:                        Boostあり:
┌─────────────────────┐          ┌─────────────────────┐
│ [ヘッダー]          │          │                     │
│ [ナビゲーション]    │          │                     │
│ [サイドバー] [本文] │    →     │     [本文]          │
│ [フッター]          │          │   (クリーンで集中)  │
│ [Cookieバナー]      │          │                     │
└─────────────────────┘          └─────────────────────┘

ユーザー作成のCSS:

- 気を散らす要素を非表示にする

- 色/フォントを変更

可読性を向上

核心的な洞察: すべてのユーザーには毎日訪れるけれど、もっと違う動作をしてほしいと思うサイトがあります。その制御をユーザーに与えましょう。

実装パターン:

interface Boost {
  id: string;
  name: string;
  domain: string; // "github.com" または "*.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は、素早いタスク向けの独立したミニマルウィンドウです。タブは1つだけ、装飾なし、集中を妨げるものがありません。

フルARC:                          リトルARC:
┌────────┬────────────────┐      ┌────────────────────────┐
│サイド  │                │      │ ← google.com/search... │
│バー    │   コンテンツ   │      ├────────────────────────┤
│        │                │      │                        │
│        │                │  →   │       検索結果         │
│        │                │      │   (コンテンツのみ)   │
└────────┴────────────────┘      └────────────────────────┘

ユースケース:

- クイック検索

- 一つのことを確認

- 他のアプリからリンクを開く

重要なインサイト: すべてのタスクにフルブラウザが必要なわけではありません。インターフェースをタスクの重要度に合わせましょう。

CSSパターン(ミニマルChrome):

.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:一時的 vs. 永続的

Arcの「Today」セクションは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のSpacesはブラウザプロファイルとどう違うのか?

Spacesは完全なブラウザプロファイルよりも軽量です。プロファイルは完全に分離されたブラウザインスタンスを作成しますが(異なるCookie、履歴、拡張機能)、Spacesはブラウザ設定を共有しながらコンテキスト別にタブを整理します。キーボードショートカットでSpacesを瞬時に切り替えられますが、プロファイルの切り替えには再起動や新しいウィンドウを開く必要があります。

Arcの「Today」セクションのタブはどうなるのか?

Todayセクションのタブは12時間操作がないと自動的にアーカイブされます。削除されるのではなく、検索可能なアーカイブに移動します。 これにより、タブの溜め込みを防ぎながら、コンテンツを復元可能な状態に保ちます。ピン留めされたタブは自動アーカイブされません。

Arcのデザインパターンを自分のアプリで使用できますか?

はい。ここで解説したパターン(折りたたみ可能なサイドバー、コマンドパレット、Spacesアーキテクチャ、Boostシステム)は転用可能なコンセプトです。コード例ではCSS、SwiftUI、TypeScriptの実装を示しており、適宜カスタマイズできます。サイドバーとコマンドバーのパターンは、コンテンツ量の多いアプリケーションに特に適しています。

ArcのCommand Barは従来のURLバーとどう違いますか?

従来のURLバーは履歴を検索してURLを提案します。ArcのCommand Barは、開いているタブ、履歴、ブックマーク、利用可能なアクションを単一の入力欄から検索できます。開いているタブを見つけたり、コマンドを実行したり、新しい場所に移動したりする際に、コンテキストを切り替えたり、何がどこにあるか覚えておく必要がありません。


参考資料