发布于

前端应该了解的设计原则:格式塔七大法则

作者
  • avatar
    姓名
    Terry
    Twitter

前言:作为前端开发者,我们每天都在与界面打交道。有时候一个简单的CSS调整,就能让用户体验发生质的改变。这背后其实都有心理学原理在起作用,其中最重要的就是格式塔心理学。

一、什么是格式塔

格式塔(Gestalt)是德文音译,意思是"形式"或"整体"。20世纪初,三位德国心理学家威特海默、考夫卡和科勒创立了这个学派。

它的核心观点很简单:整体大于部分之和

举个例子:

⚫️ ⚫️  ⚫️ ⚫️
 ⚫️ ⚫️ ⚫️ ⚫️
⚫️ ⚫️  ⚫️ ⚫️
 ⚫️ ⚫️ ⚫️ ⚫️

单独看每个圆点,没什么意义。但当它们按一定方式排列时,我们的大脑会自动补全,认出这是一个笑脸。这就是格式塔的力量——我们会自动对元素进行组合、脑补缺失,让它们呈现为简单完整的整体。

格式塔原理告诉我们:眼睛和大脑在观察事物时,会有特定的倾向帮助我们快速辨别事物。这些倾向就是下面要讲的七大原则。

二、简单原则(Pragnanz)

核心思想:大脑倾向于把复杂物体解析成简单形态,以降低认知负荷。

这是格式塔的基石。我们看画面时,不会把它们拆解为独立的点线面,而是会自动组合成完整的整体。

前端应用场景

1. 扁平化设计

/* 复杂的拟物化按钮(高视觉负荷) */
.button-vintage {
  background: linear-gradient(to bottom, #fff 0%, #e0e0e0 50%, #ccc 100%);
  border: 1px solid #999;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.8),
    inset 0 2px 3px rgba(255, 255, 255, 0.4),
    0 4px 6px rgba(0, 0, 0, 0.3);
}

/* 简洁的扁平按钮(低视觉负荷) */
.button-flat {
  background: #007bff;
  border: none;
  border-radius: 4px;
}

苹果和星巴克的Logo演进史,就是简化视觉负荷的典型案例。从复杂的渐变阴影到简洁的扁平设计,识别速度更快,传达效率更高。

2. 减少三种负荷

设计师经常提到三种负荷:

  • 认知负荷:烧脑程度(最重要)
  • 操作负荷:操作复杂度
  • 视觉负荷:信息复杂度

优先级:认知负荷 > 操作负荷 > 视觉负荷

所以"Don't make me think"是设计真理。如果认知负荷小,多一两步操作也是值得的。

场景案例:注册流程

// ❌ 糟糕的设计:一页塞满所有信息
function BadRegistration() {
  return (
    <form>
      <input name="phone" placeholder="手机号" />
      <input name="code" placeholder="验证码" />
      <input name="password" placeholder="密码" />
      <input name="confirm" placeholder="确认密码" />
      <input name="email" placeholder="邮箱" />
      <input name="avatar" placeholder="头像" />
      <button>提交</button>
    </form>
  )
}

// ✅ 好的设计:分步骤,每页一个焦点
function GoodRegistration() {
  const [step, setStep] = useState(1)

  return (
    <>
      {step === 1 && <PhoneForm onNext={() => setStep(2)} />}
      {step === 2 && <PasswordForm onNext={() => setStep(3)} />}
      {step === 3 && <ProfileForm onFinish={handleSubmit} />}
    </>
  )
}

操作步数差不多,但认知负担大大降低——用户一次只需关注一件事。

三、接近性原则(Proximity)

核心思想:彼此靠近的元素会被视为一个组。

前端应用场景

1.间距规范

字间距 < 行间距 < 组间距 < 模块间距 < 页边距

Material Design建议使用8的倍数做间距,我们常用6的倍数:

/* 间距系统 */
--space-1: 6px; /* 字间距 */
--space-2: 12px; /* 行间距 */
--space-3: 18px; /* 组间距 */
--space-4: 24px; /* 模块间距 */
--space-5: 30px; /* 页边距 */

实战案例:卡片设计

// ❌ 间距混乱,关系不清
function BadCard() {
  return (
    <div className="p-6">
      <img src="cover.jpg" className="mb-2" />
      <h3 className="mb-4">标题</h3>
      <p className="mb-1">作者</p>
      <p className="mb-3">日期</p>
      <div className="mb-2">标签1</div>
      <div>标签2</div>
    </div>
  )
}

// ✅ 利用接近性,信息分组清晰
function GoodCard() {
  return (
    <div className="p-6">
      {/* 封面组:图片+标题紧密关联 */}
      <div className="mb-4">
        <img src="cover.jpg" className="mb-2" />
        <h3>标题</h3>
      </div>

      {/* 元信息组:作者+日期 */}
      <div className="mb-3 text-sm text-gray-500">
        <span>作者</span>
        <span className="mx-2">·</span>
        <span>日期</span>
      </div>

      {/* 标签组 */}
      <div className="flex gap-2">
        <span>标签1</span>
        <span>标签2</span>
      </div>
    </div>
  )
}

关键规则:当有一个明显的大间距作为对照时,小间距之间的元素就会形成一个组。

2. 表单布局

// ✅ 利用接近性,让标签与输入框成组
<Form>
  <FormItem>
    <label>用户名</label>
    <input />
  </FormItem>

  <FormItem className="mt-4">
    {' '}
    {/* 组间距 */}
    <label>密码</label>
    <input type="password" />
  </FormItem>
</Form>

四、相似性原则(Similarity)

核心思想:具有相同属性的元素会被视为一组。

前端应用场景

1. 颜色编码

// 成功状态统一用绿色
<div className="flex items-center gap-2">
  <CheckCircle className="text-green-500" />
  <span className="text-green-600">操作成功</span>
</div>

// 警告状态统一用黄色
<div className="flex items-center gap-2">
  <AlertTriangle className="text-yellow-500" />
  <span className="text-yellow-600">请注意</span>
</div>

// 错误状态统一用红色
<div className="flex items-center gap-2">
  <XCircle className="text-red-500" />
  <span className="text-red-600">操作失败</span>
</div>

2. 列表项状态

/* 已读项目:灰色 */
.list-item.read {
  opacity: 0.6;
}

/* 未读项目:黑色+加粗 */
.list-item.unread {
  font-weight: bold;
  opacity: 1;
}

重要原则:当"接近性"和"相似性"冲突时,接近性胜出

// 虽然左侧图标彼此相似,但因为距离近,
// 用户会把图标+右侧文字视为一组
<div className="flex items-center gap-2">
  <Icon className="text-blue-500" />
  <span>设置</span>
</div>

五、连续性原则(Continuity)

核心思想:视觉倾向于感知连续的形式,而不是离散的碎片。

前端应用场景

1. 断点图标设计

// 即使图标有断点,用户也能脑补完整
<Svg viewBox="0 0 24 24">
  <path d="M4 12h6m6 0h6" /> {/* 断开的线条 */}
</Svg>

2. 导航指示器

// 进度条:即使分段,也感知为连续进度
<div className="h-2 rounded bg-gray-200">
  <div className="h-full rounded bg-blue-500" style={{ width: '60%' }} />
</div>

3. IBM风格Logo

/* 虽然线条分离,但视觉上连成字母 */
.ibm-logo {
  /* 利用连续性原则,断开的线条被脑补连接 */
}

六、闭合性原则(Closure)

核心思想:视觉会自动将敞开的图形关闭,感知为完整物体。

前端应用场景

1. 九宫格图片

// 虽然图片有缺失,但不影响识别整体
<div className="grid grid-cols-3 gap-1">
  <img src="part1.jpg" />
  <img src="part2.jpg" />
  <img src="part3.jpg" />
  {/* 用户会脑补完整图像 */}
</div>

2. 部分显示的内容

// 热点精选:右侧显示半张图
<div className="flex gap-2 overflow-hidden">
  <Card className="flex-shrink-0" />
  <Card className="flex-shrink-0" />
  <Card className="w-32 flex-shrink-0">
    {' '}
    {/* 只显示一部分 */}
    用户知道右侧还有内容
  </Card>
</div>

3. 三种闭合类型

  • 形状闭合:脑补几何形状(如三角形、圆形)
  • 负形闭合:把负空间也纳入理解(如大象例子)
  • 经验闭合:需要经验积累(如无边界线的Tab)
/* 经验闭合:Tab没有边框,靠位置和激活状态识别 */
.tab-active {
  border-bottom: 2px solid blue; /* 仅底部有边 */
}
.tab-inactive {
  /* 完全没有边框,靠用户经验理解 */
}

七、主体与背景(Figure-Ground)

核心思想:有些对象突现成主体,有些退居成背景。

前端应用场景

1. 模态框

// 遮罩层让背景变暗,模态框成为主体
<Modal>
  <Overlay className="bg-black/50" /> {/* 背景 */}
  <Content className="bg-white">
    {' '}
    {/* 主体 */}
    <h2>确认删除?</h2>
    <button>取消</button>
    <button>删除</button>
  </Content>
</Modal>

2. 卡片设计

// 灰色背景上的白色卡片成为主体
<div className="bg-gray-100 p-4">
  <Card className="bg-white shadow">主体内容</Card>
</div>

3. 层级管理

/* 运营设计的三层结构 */
.z-focus {
  z-index: 30;
} /* 焦点层 */
.z-atmosphere {
  z-index: 20;
} /* 氛围层 */
.z-background {
  z-index: 10;
} /* 背景层 */

关键启示:设计时要充分考虑元素优先级,凸显核心,弱化次要。

八、共同命运(Common Fate)

核心思想:一起运动或变化的元素会被视为相关。

前端应用场景

1. Loading状态

// ❌ 只有图标动,文字静止,感觉割裂
function BadLoading() {
  return (
    <div>
      <Spinner className="animate-spin" />
      <span>加载中...</span> {/* 静态文字 */}
    </div>
  )
}

// ✅ 图标和文字同步动,形成整体
function GoodLoading() {
  return (
    <div className="animate-pulse">
      <Spinner className="animate-spin" />
      <span>加载中...</span> {/* 一起跳动 */}
    </div>
  )
}

2. 手风琴组件

// 折叠项同步展开/收起,形成组
<Accordion>
  <AccordionItem isOpen>内容1</AccordionItem>
  <AccordionItem isOpen>内容2</AccordionItem>
  <AccordionItem>内容3</AccordionItem>
</Accordion>

3. 列表项hover

/* 整行高亮,而不是只高亮文字 */
.list-item:hover {
  background: #f5f5f5; /* 整体变化 */
}

优先级排序

共同命运 > 接近性 > 相似性

九、其他推荐给前端的设计原则

1. 菲茨定律(Fitts's Law)

核心:到达目标的时间,取决于距离和目标大小。

前端应用

/* ❌ 小按钮难以点击 */
.button-small {
  width: 20px;
  height: 20px;
}

/* ✅ 足够大的点击区域 */
.button-large {
  width: 44px; /* 移动端建议最小44x44px */
  height: 44px;
}

/* 技巧:视觉小,热区大 */
.button-icon {
  width: 24px; /* 视觉尺寸 */
  padding: 10px; /* 扩大热区 */
  margin: -10px; /* 保持布局 */
}

2. 希克定律(Hick's Law)

核心:选择越多,决策时间越长。

前端应用

// ❌ 15个选项一次性展示
<select>
  <option>选项1</option>
  <option>选项2</option>
  {/* ...13个选项 */}
</select>

// ✅ 分层级,逐步筛选
<CategorySelect>
  <Category level={1}>一级分类</Category>
  <Category level={2}>二级分类</Category>
  <Category level={3}>三级分类</Category>
</CategorySelect>

3. 米勒定律(Miller's Law)

核心:普通人短期记忆只能保持7±2个项目。

前端应用

// ❌ 一次显示太多步骤
<Stepper total={15} current={3} />

// ✅ 分组显示
<Stepper total={5} current={2} />
<span className="text-gray-500">/ 15</span>

// 或者用进度条代替步骤
<ProgressBar percent={20} />

4. 色彩对比度(WCAG)

核心:确保文本和背景有足够对比度。

前端应用

/* 使用工具检查对比度:https://contrast-ratio.com/ */

/* ✅ 符合WCAG AA标准(4.5:1) */
.text-high-contrast {
  color: #1a1a1a; /* 深色文字 */
  background: #ffffff; /* 白色背景 */
  /* 对比度:16.1:1 */
}

/* ❌ 对比度不足(2.1:1) */
.text-low-contrast {
  color: #cccccc;
  background: #ffffff;
}

5. 2秒原则

核心:用户对2秒以内的延迟感知不明显。

前端应用

// 性能优化目标
- 首次内容绘制(FCP):< 1.8- 最大内容绘制(LCP):< 2.5- 首次输入延迟(FID):< 100毫秒
- 累积布局偏移(CLS):< 0.1

6. 奥卡姆剃刀原理

核心:如无必要,勿增实体。

前端应用

// ❌ 过度设计
function OverEngineered({ count }) {
  const [state, setState] = useState()
  const memoized = useMemo(() => compute(count), [count])
  const callback = useCallback(() => {}, [])

  return <div>{count}</div>
}

// ✅ 简单直接
function Simple({ count }) {
  return <div>{count}</div>
}

7. 雅各布定律(Jakob's Law)

核心:用户花大部分时间在其他网站,所以希望你的网站和其他网站操作一致。

前端应用

// ✅ 遵循惯例,不重新发明轮子
<nav className="flex gap-4">
  <Link href="/">首页</Link>
  <Link href="/products">产品</Link>
  <Link href="/about">关于</Link>
  <Link href="/contact">联系</Link>  {/* 标准位置 */}
</nav>

// 购物车在右上角
<button className="fixed top-4 right-4">
  🛒 购物车
</button>

8. 多赫蒂阈值(Doherty Threshold)

核心:生产力在系统响应时间小于400ms时达到最大化。

前端应用

// 优化响应速度
const handleSubmit = async () => {
  // 1. 立即给用户反馈
  setSaving(true)

  // 2. 后台异步提交
  await api.save(data)

  // 3. 完成后更新UI
  setSaving(false)
  showToast('保存成功')
}

// 或使用乐观更新
const handleLike = () => {
  // 立即更新UI
  setLiked(true)

  // 后台同步
  api.like(postId).catch(() => {
    setLiked(false) // 失败则回滚
  })
}

十、总结

格式塔七大原则的优先级:

共同命运 > 接近性 > 相似性 > 连续性 > 闭合性 > 简单原则 > 主体与背景

记住这些原则,能让你的界面设计更符合用户认知习惯:

  1. 简单原则:降低视觉、操作、认知三种负荷
  2. 接近性:用间距建立信息层级
  3. 相似性:用颜色、形状建立关联
  4. 连续性:保持视觉流的连贯
  5. 闭合性:利用用户脑补能力
  6. 主体与背景:明确信息优先级
  7. 共同命运:用运动建立关联

理解这些心理学原理,不仅能让你做出更好的设计,还能在与设计师协作时更有共同语言。

参考资源


原文链接超深度解析「格式塔7大原则」,一起涨芝士啦

作者:悦有所思 - 人人都是产品经理专栏作家

说明:本文基于原作内容改写,从前端开发视角重新组织,并结合实际代码示例进行说明。