Design system

Swiss Ledger 与 Ledger Motion

九个 App 和这个网站共用的一套设计语言。下面每个 token 都能看到、重播,旁边是 SwiftUI 与 CSS 两种写法,数值一一对应。

模拟「减弱动态效果」打开后,本页所有示例按降级表运行

Principles

  1. 01纸与墨页面与面板同色,层级只靠 1px 发丝描边和留白。不用浮起的卡片、阴影、毛玻璃、渐变底。
  2. 02只有一种颜色会说话全家族唯一强调色是印刷红。一屏之内有颜色的元素通常只有墨与红两种。
  3. 03直角面板与控件 2pt,标签与进度条 0pt,开关是方形滑块。
  4. 04数字是英雄所有数字等宽,最重要的那个数字是全屏最大最重的元素。
  5. 05动效是确认,不是表演每个动效都回答「我的操作生效了吗」或「它从哪来、到哪去」。

Color

Token浅色深色对比度(纸 / 墨)用途
paperpageBackground#FAFAF7#0B0B0A—页面底,面板与页面同色
inkink#0B0B0A#F5F4F018.83 / 17.89正文、主图形、选中态、主按钮
ink-softinkSoft#6E6E68#9E9E994.91 / 7.32次要文本、元信息、分组标题
ink-faintinkFaint#74736D#7A7A754.55 / 4.56禁用、占位符、装饰图形
accentaccent#C4321F#E2503A5.25 / 5.10全家族唯一强调色:当前选中、需要处理的一项
successsuccess#2F7A63#3F9E824.92 / 6.02描边标签、收入金额
warningwarning#8A6100#C9962A5.30 / 7.39待处理、偏高
dangerdanger#9E1B12#F2684F7.67 / 6.44只用于不可逆操作
borderpanelBorder黑 14%白 14%1.38面板与控件的 1px 描边,只负责分组
dividerdivider黑 10%白 10%—面板内的行分隔线

强调色预算:每屏强调色区块 ≤ 1 处、标签与小字 ≤ 3 处、图标 0。支出永远不用红色,红色留给「超支」这个判断。

Type

  1. displayclamp(44px → 96px) · 800 · −0.02em

    ¥3,222

  2. pageTitle · H1clamp(36px → 64px) · 800

    一眼看清本月还剩多少。

  3. H2clamp(24px → 36px) · 800

    账单导入

  4. H320px · 700

    把过去几个月的账一次带进来

  5. body17px · 400 · 行高 1.75

    最少路径只要金额和分类,其余字段收进「更多选项」。

  6. small14px · 400

    统计于 2026-10-02,只计入 git 已跟踪的文件。

  7. sectionLabel11px · 700 · 全大写 · 0.12em

    Budget left · 9 月

Archivo 400 / 700 / 800,与 App 打包的是同一份字体文件;中文回落到苹方。所有数字等宽:1,111.11 / 8,888.88。

Shape

面板与控件 2px 圆角 · 1px 描边
Cleared
状态标签 0 圆角 · 描边不填色
进度线 4px · 0 圆角 · 方头
阴影 无

Five actions

账本上只会发生五种事,所以界面上只允许五种动效。

午餐 · 沙县小吃−¥38.00
落笔 enter · 透明度 0→1,上移 6
地铁−¥4.00
咖啡−¥22.00
午餐 · 沙县小吃−¥38.00
超市−¥64.50
房租−¥2,820.00
逐行 stagger · 每行晚 32ms,最多 8 行
¥3,222
刻度 tick · 0.40s,绝不冲过头
Cleared
盖章 stamp · 0.92 → 1
已删除 午餐 ¥38撤销
收笔 exit · 比入场更快

Motion tokens

instant0Tab 内容切换、减弱动态降级
SwiftUI
AppMotion.instant 无动画
CSS
--ledger-instant 0ms
press100ms按下态
SwiftUI
AppMotion.press .easeOut(duration: 0.10)
CSS
--ledger-press 100ms cubic-bezier(0, 0, .58, 1)
quick120ms数值交叉淡化、含义变化
SwiftUI
AppMotion.quick .easeInOut(duration: 0.12)
CSS
--ledger-quick 120ms cubic-bezier(.42, 0, .58, 1)
standard180ms展开收起、选中、筛选、开关
SwiftUI
AppMotion.standard .easeInOut(duration: 0.18)
CSS
--ledger-standard 180ms cubic-bezier(.42, 0, .58, 1)
exit180ms收笔
SwiftUI
AppMotion.exit .easeOut(duration: 0.18)
CSS
--ledger-exit 180ms cubic-bezier(0, 0, .58, 1)
enter240ms落笔
SwiftUI
AppMotion.enter .timingCurve(0.2, 0, 0, 1, duration: 0.24)
CSS
--ledger-enter 240ms cubic-bezier(.2, 0, 0, 1)
tick400ms刻度
SwiftUI
AppMotion.tick .timingCurve(0.2, 0, 0, 1, duration: 0.40)
CSS
--ledger-tick 400ms cubic-bezier(.2, 0, 0, 1)
stamp220ms盖章(临界阻尼,零过冲)
SwiftUI
AppMotion.stamp .spring(response: 0.22, dampingFraction: 1.0)
CSS
--ledger-stamp 220ms cubic-bezier(.2, 0, 0, 1)
banner320ms横幅入场,唯一允许轻微过冲
SwiftUI
AppMotion.banner .spring(response: 0.35, dampingFraction: 0.74)
CSS
--ledger-banner 320ms cubic-bezier(.3, 1.1, .6, 1)

上面的示例放慢 4 倍播放,便于看清曲线。编排常量:落笔上移 6,逐行间隔 32ms,最多 8 行参与;单个动效 ≤ 0.5s,一段编排 ≤ 0.9s。例外只有三个:开篇 ≤ 1.0s、FOOTY 点亮 ≤ 2.6s、网站签名演示 ≤ 1.6s。

Reduced motion

动作正常减弱动态效果
enter / 逐行淡入 + 上移 6,逐行120ms 淡入,不逐行
tick数字滚动、线生长直接显示最终值
stamp0.92 → 1 缩放120ms 淡入
banner从顶部滑入120ms 淡入
standard / exit / press不变不变
签名演示完整编排直接显示终态

位移和缩放消失,只保留最短的淡化,信息一项不少。网站读取 prefers-reduced-motion,App 读取系统的同名设置。

App icons

纯黑底 #0B0B0A 加一个 #E2503A 实心图形。统一红色以后,九个图标只靠轮廓区分,所以每个轮廓在 29pt 下都要一眼可辨。

ESC

输入关键词,例如「账单导入」「API Key」「iCloud」。