Arc Browser: 브라우저 크롬을 재상상하다
Arc Browser의 디자인 시스템 심층 분석: 사이드바 내비게이션, Spaces, 명령 바, Boosts, 그리고 혁명적인 패턴들. CSS, SwiftUI, TypeScript 코드 예제 포함.
Arc 브라우저: 브라우저 크롬의 재해석
"브라우저는 이제 운영체제나 다름없습니다. 그런데 왜 아직도 2008년 소프트웨어처럼 생겼을까요?" — Josh Miller, The Browser Company
Arc는 탭 배치부터 윈도우 관리까지 브라우저의 모든 가정에 의문을 제기했습니다. 그 결과물은 유틸리티 애플리케이션이라기보다 창작 도구에 가까운 브라우저입니다.
핵심 요점
- 수직 사이드바가 수평 탭을 이긴다 - 탭 제목이 읽기 쉽게 유지되고, 현대의 와이드스크린 모니터에서 수직 공간은 풍부합니다
- 스페이스가 정신적 맥락을 분리한다 - 업무, 개인, 프로젝트 탭이 섞이지 않아 인지적 마찰이 줄어듭니다
- Command Bar > URL 바 - 탭, 히스토리, 액션 전체를 검색할 수 있어 완벽한 정리가 필요 없습니다
- 사용자 커스터마이징이 충성도를 만든다 - Boosts로 사용자가 직접 불편한 사이트를 수정할 수 있어 개인적 투자가 생깁니다
- 인터페이스 무게를 작업에 맞춘다 - 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'S SIDEBAR MODEL:
┌────────────────┬─────────────────────────────────────────────┐
│ [*] Space │ │
│ ───────────── │ │
│ Pinned │ │
│ Gmail │ │
│ Calendar │ Page Content │
│ Notion │ (full width) │
│ │ │
│ ───────────── │ │
│ Today │ │
│ Tab 1 │ │
│ Tab 2 │ │
│ Tab 3 │ │
│ │ │
│ [+ New Tab] │ │
└────────────────┴─────────────────────────────────────────────┘
Benefits: Readable titles, pinned favorites, organized by purpose
핵심 통찰: 수평 공간은 프리미엄이고, 수직 공간은 풍부합니다. 사이드바를 사용하면 탭 제목에 여유가 생깁니다.
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;
}
/* Hover to peek */
.sidebar.collapsed:hover {
width: var(--sidebar-width);
}
.sidebar.collapsed:hover .tab-title {
opacity: 1;
transition: opacity 0.15s ease-in 0.1s; /* Delay for smooth reveal */
}
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. 스페이스: 맥락 기반 정리
스페이스는 업무와 개인, 프로젝트와 프로젝트를 분리합니다. 각 스페이스는 자체 탭, 고정 사이트, 심지어 테마까지 갖춘 완전한 브라우저 컨텍스트입니다.
SPACE ARCHITECTURE:
┌─────────────────────────────────────────────────────────────┐
│ Arc Browser │
├───────────┬───────────┬───────────┬─────────────────────────┤
│ Work │ Personal │ Project │ │
│ Space │ Space │ Space │ Content Area │
│ ───── │ ───── │ ───── │ │
│ • Slack │ • Gmail │ • GitHub │ │
│ • Docs │ • Reddit │ • Figma │ │
│ • Jira │ • Netflix│ • Notion │ │
└───────────┴───────────┴───────────┴─────────────────────────┘
Each Space has:
├── Unique pinned tabs
├── Separate "Today" tabs
├── Own color theme/gradient
├── Isolated browsing context
└── Keyboard shortcut (Cmd+1, Cmd+2, etc.)
핵심 통찰: 정신적 맥락은 섞이면 안 됩니다. 개인 시간에 업무 탭이 보이면 인지적 마찰이 발생합니다.
데이터 모델:
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. Command Bar: 브라우저를 위한 Spotlight
Arc의 Command Bar(Cmd+T)는 단순한 URL 입력창 이상의 기능을 제공합니다. 탭, 히스토리, 북마크, 그리고 액션 전반에 걸친 통합 검색 기능을 제공합니다.
COMMAND BAR 인터랙션:
┌─────────────────────────────────────────────────────────────┐
│ > 탭, 히스토리를 검색하거나 URL을 입력하세요... │
├─────────────────────────────────────────────────────────────┤
│ 열린 탭 │
│ [doc] Notion - Project Planning Cmd+1 │
│ [doc] GitHub - Pull Request #123 │
│ │
│ 히스토리 │
│ [>] Figma - Design System (2시간 전) │
│ [>] MDN - CSS Grid Guide (어제) │
│ │
│ 액션 │
│ [*] 새 노트 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. Boosts: 사용자 수준 커스터마이제이션
Boosts는 사용자가 어떤 웹사이트에든 커스텀 CSS와 JavaScript를 삽입할 수 있게 해줍니다: 개인화된 다크 모드, 깔끔하게 정리된 인터페이스, 또는 향상된 기능 등을 적용할 수 있습니다.
BOOST 개념:
Boost 미적용: Boost 적용:
┌─────────────────────┐ ┌─────────────────────┐
│ [Header] │ │ │
│ [Navigation] │ │ │
│ [Sidebar] [Content] │ → │ [Content] │
│ [Footer] │ │ (깔끔하고 집중됨)│
│ [Cookie Banner] │ │ │
└─────────────────────┘ └─────────────────────┘
사용자 제작 CSS:
- 방해 요소 숨기기
- 색상/폰트 변경
- 가독성 향상
핵심 통찰: 모든 사용자에게는 매일 방문하지만 다르게 작동했으면 하는 사이트가 있습니다. 그 제어권을 사용자에게 주세요.
구현 패턴:
interface Boost {
id: string;
name: string;
domain: string; // "github.com" or "*.google.com"
enabled: boolean;
css?: string;
js?: string;
createdAt: Date;
}
// Example Boost: Clean YouTube
const youtubeBoost: Boost = {
id: 'youtube-clean',
name: 'Clean YouTube',
domain: 'youtube.com',
enabled: true,
css: `
/* Hide recommendations */
#secondary,
ytd-browse[page-subtype="home"] ytd-rich-grid-renderer {
display: none !important;
}
/* Hide comments */
#comments {
display: none !important;
}
/* Expand video */
#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) {
// Domain selector
HStack {
Image(systemName: "globe")
TextField("Domain (e.g., github.com)", text: $boost.domain)
.textFieldStyle(.plain)
}
.padding()
.background(.ultraThinMaterial)
// Tab selector
Picker("", selection: $activeTab) {
ForEach(BoostTab.allCases, id: \.self) { tab in
Text(tab.rawValue).tag(tab)
}
}
.pickerStyle(.segmented)
.padding()
// Code editor
CodeEditor(
text: activeTab == .css ? $boost.css : $boost.js,
language: activeTab == .css ? .css : .javascript
)
}
}
}
5. Little Arc: 미니멀을 위한 설계
Little Arc는 빠른 작업을 위한 별도의 미니멀 창입니다: 탭 하나, 크롬 없음, 방해 요소 제로.
FULL ARC: LITTLE ARC:
┌────────┬────────────────┐ ┌────────────────────────┐
│Sidebar │ │ │ ← google.com/search... │
│ │ Content │ ├────────────────────────┤
│ │ │ │ │
│ │ │ → │ Search Results │
│ │ │ │ (just the content) │
└────────┴────────────────┘ └────────────────────────┘
사용 사례:
- 빠른 검색
- 하나만 확인할 때
- 다른 앱에서 링크 열기
핵심 통찰: 모든 작업에 전체 브라우저가 필요한 것은 아닙니다. 인터페이스를 작업의 무게에 맞추세요.
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: 일시적 vs. 영구적
Arc의 "Today" 섹션은 12시간 후 탭을 자동으로 보관합니다. 영구 항목은 명시적으로 고정해야 합니다.
interface EphemeralityConfig {
defaultLifetime: number; // milliseconds
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)
// Draggable divider
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;
}
디자인 교훈
- 가정에 도전하기: 탭 바는 신성불가침이 아닙니다; 어떤 것도 마찬가지입니다
- 맥락 분리: 다른 작업은 다른 환경을 필요로 합니다
- 키보드 우선: 파워 유저는 마우스 없이 탐색합니다
- 점진적 복잡성: 기본은 단순하게, 필요할 때 강력하게
- 사용자 커스터마이징: 사람들이 소프트웨어를 자신만의 것으로 만들 수 있게 합니다
- 적절한 무게감: 인터페이스 복잡성을 작업 복잡성에 맞춥니다
자주 묻는 질문
Arc는 왜 수평 탭 대신 수직 사이드바를 사용했나요?
수평 탭은 많은 페이지를 열면 읽을 수 없을 정도로 좁아집니다. 수직 사이드바는 현대 와이드스크린 모니터에서 풍부한 화면 높이를 활용하여 탭 제목을 완전히 표시할 수 있습니다. 또한 사이드바는 고정 섹션이나 폴더와 같이 수평으로는 잘 작동하지 않는 정리 기능을 가능하게 합니다.
Arc의 Spaces는 브라우저 프로필과 어떻게 다른가요?
Spaces는 완전한 브라우저 프로필보다 가볍습니다. 프로필은 완전히 분리된 브라우저 인스턴스를 생성하지만(다른 쿠키, 기록, 확장 프로그램), Spaces는 브라우저 설정을 공유하면서 맥락별로 탭을 정리합니다. 키보드 단축키로 Spaces를 즉시 전환할 수 있지만, 프로필 전환은 재실행하거나 새 창을 열어야 합니다.
Arc의 "오늘" 섹션에 있는 탭은 어떻게 되나요?
오늘 섹션의 탭은 12시간 동안 비활성 상태이면 자동으로 아카이브됩니다. 삭제되는 것이 아니라 검색 가능한 아카이브로 이동합니다. 이는 콘텐츠를 복구 가능하게 유지하면서 탭 쌓아두기를 방지합니다. 고정된 탭은 절대 자동 아카이브되지 않습니다.
Arc의 디자인 패턴을 내 앱에서 사용할 수 있나요?
네. 여기에 문서화된 패턴들(접을 수 있는 사이드바, 커맨드 팔레트, Spaces 아키텍처, Boost 시스템)은 전이 가능한 개념입니다. 코드 예제는 적용할 수 있는 CSS, SwiftUI, TypeScript 구현을 보여줍니다. 사이드바와 커맨드 바 패턴은 특히 콘텐츠 중심 애플리케이션에서 잘 작동합니다.
Arc의 커맨드 바는 기존 URL 바보다 어떻게 개선되었나요?
기존 URL 바는 기록을 검색하고 URL을 제안합니다. Arc의 커맨드 바는 단일 입력으로 열린 탭, 기록, 북마크, 사용 가능한 액션을 검색합니다. 맥락을 전환하거나 무언가가 어디에 있는지 기억할 필요 없이 열린 탭을 찾거나, 명령을 실행하거나, 새로운 곳으로 이동할 수 있습니다.
참고 자료
- Josh Miller(The Browser Company CEO)의 Arc 디자인 철학: The Browser Company Blog
- 브라우저 인터페이스 진화와 탭 바의 지속성: Nielsen Norman Group - Browser UX
- 키보드 우선 인터페이스 디자인 패턴: Human Interface Guidelines - Keyboard Navigation
- 현대 소프트웨어의 커맨드 팔레트 패턴: Superhuman, Linear, Raycast 구현