Notion: ブロックベース革命
Notionが複雑さをコンポーザブルにした方法:ブロックベースアーキテクチャ、プログレッシブディスクロージャー、スラッシュコマンド、無限キャンバス。CSSとTypeScriptの実装パターン付き。
Notion:ブロックベースの革命
「私たちは、誰もが毎日使うソフトウェアを、自分のニーズに合わせて正確にカスタマイズできるようにしたいのです。」— Ivan Zhao、Notion CEO
Notionは、すべてをブロックにすることで生産性ソフトウェアを変革しました。一見シンプルなこの抽象化は、ユーザビリティを維持しながら無限の柔軟性を生み出しました—ほとんどの人が不可能だと考えていたデザイン上の課題です。
Notionが重要な理由
Notionは、複雑さは組み合わせ可能であることを証明しました。固定的な機能の代わりに、デザイナーが予想もしなかった方法でユーザーが組み合わせることができるビルディングブロックを作り出したのです。
主な成果: - 非開発者にもデータベースを身近なものにした - 親しみを感じさせる無限キャンバスを創出 - 柔軟性と使いやすさは相反するものではないことを証明した - 大規模な協調ドキュメント編集を先駆けた
重要なポイント
- すべてがブロック — アトミック単位のアプローチにより、あらゆるコンテンツ(テキスト、画像、データベース)が同一の振る舞いを持つ:ドラッグ可能、変換可能、リンク可能
- 段階的開示が複雑性をスケール — スラッシュコマンドは呼び出された時のみパワー機能を表示;初心者にはシンプルに見え、エキスパートには深さを提供
- 一貫性は巧妙さに勝る — すべてのブロックは同じハンドル、同じドラッグ動作を持ち、他のどのタイプにも変換可能
- 無限キャンバスが制約を取り除く — ページはページを含み、データベースはページを含み、すべてがあらゆる場所にリンク—人工的な階層なし
- 落ち着いたタイポグラフィがコンテンツを輝かせる — 控えめなデザインで、余裕のある行の高さ(1.7)と快適な読み幅(720px)がユーザーコンテンツに焦点を当てる
コアデザイン原則
1. すべてがブロック
Notionのアトミック単位はブロックです。あらゆるコンテンツはブロックであり、以下のことが可能です: - 移動 - 変換 - 参照 - 埋め込み
従来のドキュメント:
┌─────────────────────────────────────┐
│ [固定ヘッダー] │
│ ───────────────────────────────── │
│ テキストはただのテキストで、 │
│ テキストでしかない段落。 │
│ │
│ [固定画像] │
│ │
│ もうひとつの段落、同じこと。 │
└─────────────────────────────────────┘
NOTIONのブロックモデル:
┌─────────────────────────────────────┐
│ ⋮⋮ [見出しブロック - H1] │ ← ドラッグで並べ替え
│ ───────────────────────────────── │
│ ⋮⋮ [テキストブロック] │ ← トグル、コールアウトなどに変換可能
│ 変換可能な段落 │
│ ⋮⋮ [画像ブロック] │ ← サイズ変更、キャプション、リンク
│ [キャプション] │
│ ⋮⋮ [データベースブロック] │ ← フルデータベース、インライン
│ │ タスク │ ステータス │ 期限 │ │
│ ⋮⋮ [テキストブロック] │
│ 別の段落 │
└─────────────────────────────────────┘
その天才性:すべてのブロックが同じハンドル(⋮⋮)、同じドラッグ動作を持ち、他のどのブロックタイプにも変換できます。
CSSパターン(ブロックハンドル):
.block {
position: relative;
padding-left: var(--block-indent);
}
.block-handle {
position: absolute;
left: 0;
opacity: 0;
transition: opacity 0.15s ease;
cursor: grab;
}
.block:hover .block-handle,
.block-handle:focus {
opacity: 1;
}
/* 汎用ブロック間隔 */
.block + .block {
margin-top: var(--space-2);
}
SwiftUIパターン:
struct BlockView: View {
@State private var isHovering = false
let block: Block
var body: some View {
HStack(alignment: .top, spacing: 4) {
// 共通ハンドル
Image(systemName: "line.3.horizontal")
.opacity(isHovering ? 1 : 0)
.animation(.easeOut(duration: 0.15), value: isHovering)
// ブロックコンテンツ(ポリモーフィック)
BlockContentView(block: block)
}
.onHover { isHovering = $0 }
}
}
2. 段階的開示
Notionは必要な時だけ複雑さを表示します。デフォルト状態はクリーンで、高度な機能は必要に応じて現れます。
「/」メニュー:
User types: /
↓
┌────────────────────────────────┐
│ BASIC BLOCKS │
│ [T] Text │
│ [P] Page │
│ [x] To-do list │
│ * Bulleted list │
│ │
│ DATABASE │
│ [=] Table │
│ [#] Board │
│ [D] Calendar │
│ │
│ MEDIA │
│ [I] Image │
│ [V] Video │
│ [@] File │
└────────────────────────────────┘
段階的な複雑性:
レベル1: 入力するだけ(テキストブロック)
レベル2: 「/」でブロックタイプ
レベル3: 「@」でメンションとリンク
レベル4: 「[」でインラインデータベース
レベル5: テンプレートと数式
実装原則:
/* 必要になるまで非表示 */
.property-options,
.advanced-settings,
.formula-builder {
display: none;
}
/* 明示的な操作で表示される */
.block.selected .property-options,
.settings-expanded .advanced-settings,
.formula-mode .formula-builder {
display: block;
animation: fadeSlideIn 0.2s ease-out;
}
3. 無限のキャンバス
ページはページを含む。データベースはページを含む。ページはあらゆる場所にリンクする。ワークスペースには壁がない。
従来の階層構造:
フォルダ → ドキュメント → コンテンツ
│
└── 硬直的、1ドキュメントにつき1つの場所のみ
NOTIONのキャンバス:
すべて → リンクで繋がる → すべて
│
└── ページはどこにでも存在可能
└── 同じデータ、複数のビュー
└── インラインまたはフルページ
重要な洞察:「ファイルシステム」は存在しない。あるのはコンテンツが繋がったグラフ構造だ。
パターン - インライン vs フルページ:
/* Same content, different containers */
.database-inline {
max-height: 400px;
overflow-y: auto;
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
}
.database-fullpage {
height: 100%;
border: none;
}
/* コンテンツはコンテナに適応する */
.database-view {
display: flex;
flex-direction: column;
height: 100%;
}
4. 落ち着いたタイポグラフィ
Notionのタイポグラフィは意図的に控えめです。コンテンツを際立たせます。
サイズとウェイトによる階層構造:
ページタイトル ← 40px、太字、控えめな個性
═══════════════════════════════════════════════
Heading 1 ← 30px, Semibold
───────────────────────────────────────────────
見出し2 ← 24px, Semibold
. . . . . . . . . . . . . . . . . . . . . . .
見出し3 ← 20px, Semibold
本文は16pxで自然に流れ、ゆとりある ← 16px, Regular
行間(1.7)と快適な文字幅で構成。
長文コンテンツも読みやすさを保つ。
タイポグラフィシステム:
:root {
/* Notionにインスパイアされたスケール */
--font-title: 40px;
--font-h1: 30px;
--font-h2: 24px;
--font-h3: 20px;
--font-body: 16px;
--font-small: 14px;
/* 読みやすさのためのゆとりある行間 */
--line-height-tight: 1.3;
--line-height-normal: 1.5;
--line-height-relaxed: 1.7;
/* ニュートラルで読みやすいフォントスタック */
--font-family: -apple-system, BlinkMacSystemFont,
'Segoe UI', 'Roboto', sans-serif;
}
.page-content {
max-width: 720px; /* 読みやすい行幅 */
margin: 0 auto;
font-family: var(--font-family);
line-height: var(--line-height-relaxed);
}
汎用パターン
パターン1:スラッシュコマンド
仕組み:「/」を入力すると、コンテキストに応じたアクションが表示されます。
// スラッシュコマンドレジストリ
interface SlashCommand {
trigger: string;
icon: string;
label: string;
shortcut?: string;
action: () => void;
}
const commands: SlashCommand[] = [
{ trigger: 'h1', icon: 'H1', label: 'Heading 1', action: createH1 },
{ trigger: 'bullet', icon: '•', label: 'Bullet list', action: createBullet },
{ trigger: 'todo', icon: '☐', label: 'To-do', action: createTodo },
];
// ユーザーの入力に応じてフィルタリング
function filterCommands(query: string): SlashCommand[] {
return commands.filter(cmd =>
cmd.trigger.includes(query.toLowerCase()) ||
cmd.label.toLowerCase().includes(query.toLowerCase())
);
}
パターン2:ブロック変換
仕組み:任意のブロックは他のどのブロックにも変換できます。
enum BlockType: CaseIterable {
case text, heading1, heading2, heading3
case bulletList, numberedList, toggleList, todo
case quote, callout, divider
case image, video, embed
var icon: String {
switch self {
case .text: return "text.alignleft"
case .heading1: return "textformat.size.larger"
// ...
}
}
}
struct BlockTransformMenu: View {
let currentBlock: Block
let onTransform: (BlockType) -> Void
var body: some View {
Menu {
ForEach(BlockType.allCases, id: \.self) { type in
Button {
onTransform(type)
} label: {
Label(type.label, systemImage: type.icon)
}
}
} label: {
Image(systemName: "arrow.triangle.turn.up.right.circle")
}
}
}
パターン3:インラインメンション
仕組み:「@」でワークスペース内のあらゆるものにリンク。
.mention {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 6px;
background: var(--bg-mention);
border-radius: var(--radius-sm);
color: var(--text-link);
text-decoration: none;
cursor: pointer;
}
.mention:hover {
background: var(--bg-mention-hover);
}
.mention-icon {
width: 16px;
height: 16px;
}
デザインの教訓
- 機能より構成可能性:モノリシックなツールではなく、組み合わせ可能なブロックを構築する
- 段階的開示:デフォルトはシンプルに、必要に応じてパワフルに
- 一貫したインタラクション:すべてのブロックが同じように動作する
- 落ち着いたインターフェース:装飾ではなくコンテンツを主役にする
- 無限の柔軟性:構造に人為的な制約を設けない
よくある質問
Notionのブロックベースアーキテクチャとは?
Notionのすべてのコンテンツは「ブロック」です—テキスト、画像、データベース、埋め込み、そしてページ自体も含まれます。各ブロックは同一の動作を持ちます:ドラッグ用のハンドル、他のブロックタイプへの変換機能、一貫したスペーシング。このアトミックなアプローチにより、ユーザーは一度覚えたインタラクションパターンをあらゆる場所で適用できます。
Notionのスラッシュコマンドシステムはどのように機能しますか?
「/」を入力すると、利用可能なすべてのブロックタイプのコンテキストメニューが開きます。ユーザーが入力するとメニューがフィルタリングされます(例:「/todo」でToDoリストが表示)。このパターンは発見しやすさ(すべてのオプションを確認できる)とスピード(パワーユーザーは直接ショートカットを入力できる)を両立しています。スラッシュコマンドは業界標準のパターンとなりました。
段階的開示とは何か、Notionはどのように活用しているか?
段階的開示とは、必要な時にのみ複雑さを明らかにすることを意味します。 Notionでは、レベル1は単なるタイピング(テキストブロックを作成)、レベル2はブロックタイプ用の「/」、レベル3はメンション用の「@」、レベル4はデータベース用の「[」、そしてレベル5がテンプレートと数式です。初心者が圧倒されるような選択肢を目にすることはありません。
Notionの無限キャンバスは従来のドキュメント構造とどう違うのか?
従来のアプリは、各ドキュメントが1つの場所に存在するフォルダ階層を使用します。Notionはコンテンツをグラフとして扱います:ページはページを含み、データベースはページを含み、あらゆるものがあらゆるものにリンクできます。同じデータベースが複数のページにインラインで表示でき、ページにはファイルシステム上の固定された「場所」がありません。
なぜNotionはこれほど控えめなタイポグラフィを使用するのか?
Notionの落ち着いたタイポグラフィ(システムフォント、16px本文、1.7の行間、720pxの最大幅)は、意図的に個性を排除しています。ユーザーは会議メモ、Wiki、プロジェクトトラッカーなど、まったく異なるコンテンツを作成するため、インターフェースはあらゆるコンテンツタイプが自然に感じられる中立的なキャンバスでなければなりません。
リソース
- ウェブサイト: notion.so
- デザインブログ: Notionの舞台裏のデザイン決定
- テンプレートギャラリー: コミュニティのパターンとユースケース
- APIドキュメント: Notionのブロックモデルを使った構築