Archipelago

Lec 14视觉设计

讲义完成更新于 2026-09-16

Lec 14 视觉设计

官方课件:Visual Design。

本节 Lec 的目标:

  • 理解 视觉设计的核心要素——如何通过布局让界面易于理解; 如何运用字体排版,让界面兼具美感和逻辑清晰; 色彩如何影响界面的可用性和审美体验
  • 实践 学会在视觉设计中识别并综合运用这三大要素

TL;DR

  • 视觉设计首先承担引导和节奏功能:布局、尺寸、对齐与留白应让层级和下一步行动能够被快速扫描,而不只是装饰界面。
  • 字体排印通过字号、x 高度、字重、对齐和行间关系建立信息层级;大段正文应优先保证稳定起点和连续阅读。
  • 颜色同时受媒介、周边颜色和人眼感知影响;调色不能只操作 RGB 数值,还要检查对比度、语义一致性与使用情境。
  • 设计批评应描述目标、观察和影响,再提出可执行改进;组件库能提高一致性与速度,但不能替代有意图的视觉判断。

理论篇

什么是好的视觉设计

好的视觉设计不仅仅是让界面"看起来漂亮",更重要的是:

  • 引导(Guiding): 通过传达结构、表达元素的相对重要性、建立元素之间的关系来引导用户。
  • 节奏(Pacing):吸引用户进入应用, 帮助用户定位当前位置,指示下一步操作路径。

⚠ 视觉设计的挑战:它是主观的,涉及权衡取舍,不可能让每位用户都完全满意。但至少应做到:让用户清楚知道如何完成他们需要做的事。

🎯 **核心目标:**使界面自解释(self-explanatory)——在设计所用元素的前提下,清晰传达用户如何最好地实现他们的目标。

缺少清晰操作线索的自动门示例

上图又是自动门,都是拉门的、但是又没有拉环的设计,让人有点摸不着头脑。

布局

布局的核心原则:

  • 对于网格系统,将元素对齐到网格,常用 12 列网格,配合页边距(margin)和列间距(gutter/alley)保证结构一致
  • 尺寸= 层级: 元素大小传达重要性。大区域 = 主要操作(如搜索栏);小区域 = 同等级的次要内容(如浏览网格)。
  • 空白区分组: 留白可在视觉上区分不同的内容组,无需边框或分隔线,减少视觉噪音。

Margin: 页面两侧的外边距,保护内容不贴边;

Gutter / Alley: 列与列之间的间距;

标准 12 列:可灵活组合(1+11、4+8、6+6 等),适配多种布局需求

十二列网格中的边距与列间距


用留白区分内容组

通过留白区分两组内容的布局对比

不加留白:两组内容视觉上融合,用户难以区分边界,认知负担增加。

加入留白后: 无需边框,两组内容(Group 1 / Group 2)自然分离,结构清晰。


用户如何浏览布局(Navigation)

F 型扫描模式(F-Pattern): 用户不会逐字阅读页面,而是优先扫描。

研究表明:

起点 从页面左上角开始,向右水平扫描第一行
第二行 向下移动,再次向右扫描,但范围通常比第一行短
竖向扫描 沿左边缘垂直向下浏览,形成「F」形轨迹
设计建议 重要内容放左侧;避免居中对齐大段文字(左对齐更易扫描)

举几个例子:

页面内容的 F 型扫描布局示例一

页面内容的 F 型扫描布局示例二

字体排印

字体排印(Typography)的几个术语

术语定义设计建议
字号(font size / point size)字体的整体大小,从顶部到底部的测量值不同字体相同字号,视觉大小不同
x 高度(x-height)小写字母"x"的高度,衡量字体的视觉大小小屏幕/低分辨率场景,优先选 x 高度大的字体(如 Lucida Grande)
字重(Weight)字体笔画的粗细light / regular / semi-bold / bold / extra-bold / black,通过字重建立层级
衬线 vs 无衬线Serif(如 Baskerville)有装饰性笔画;Sans-serif(如 Gill Sans)无装饰两者可读性差异极小,选择主要影响风格和调性

字号、字重与 x 高度形成的字体排印差异


文字对齐与空白

左对齐(推荐):符合 F 型扫描习惯,易于快速扫读;课程名等列表信息的最佳对齐方式

居中对齐(谨慎使用): 每行起点不固定,扫描困难;适合标题、短文字、对称布局;大段正文避免使用

排版中的层级示例(课程列表)

第一种,无层级, 课程号 + 课程名 + 教授名全部挤在一行,难以扫描

课程信息缺少视觉层级的排版示例

第二种, 教授名换行,但课程号和名称仍混在一起

只通过换行区分课程信息的排版示例

第三种, 课程号加大加粗,课程名用正常字重,教授名用浅色字重,三层信息一目了然

用字号、字重和颜色建立课程信息层级

色彩

加色混合 vs 减色混合

  • 加色混合(Additive):用于数字显示屏。使用红、绿、蓝(RGB)三原色叠加,颜色相加变亮。 例:红 + 蓝 = 紫
  • 减色混合(Subtractive):用于印刷、电子纸。使用 CMYK 颜料,颜色相加变暗(吸收光线)

RGB 加色混合与 CMYK 减色混合对比

✕ RGB 有两大缺陷: ① 不符合我们自然表达颜色的方式; ② 并非感知均匀(perceptually uniform)——数值变化相同,但人眼感受到的变化不一致。

颜色感知效应

同步对比(Simultaneous Contrast): 两种颜色并排时会相互影响感知。Josef Albers 实验证明:同一颜色在不同背景下看起来完全不同。设计时需考虑颜色的上下文环境。

相同颜色在不同背景下产生的同步对比

贝佐德效应(Bezold Effect): 在颜色周围加深色边框,会使该颜色看起来更深。相同的颜色值,因边框不同而产生不同的视觉感受。

边框改变中心颜色感知的贝佐德效应

颜色三属性

  • 色调(Hue): 我们通常所说的"颜色"本身:红、绿、蓝、黄等
  • 饱和度(Saturation): 颜色的"纯度"——含灰程度。饱和度越低,越接近灰色。
  • 明度(Lightness): 颜色的明暗程度。从暗到亮的连续变化。
色温:暖色 vs 冷色

暖色与冷色的色温对比示例一

暖色与冷色的色温对比示例二

色彩和谐

色彩和谐(Color Harmonies)

  • 互补色(Complementary)
    • ✓高对比度,视觉冲击强
    • ✓吸引注意力
    • ✗不适合正文,阅读疲劳
  • 类似色(Analogous)
    • ✓ 自然和谐,在自然界中常见
    • 选一个主色,其余为辅助/点缀色
    • 注意保证足够对比度
  • 分裂互补(Split Complementary)
    • ✓ 类似互补色效果
    • ↑ 相邻颜色张力更小,更好驾驭
  • 三角色 / 矩形色(Triadic / Tetradic)
    • 三角色:色环上均匀分布的三色
    • 矩形/正方形:四色组合
    • 更复杂,需控制好主次关系

设计批评框架

用这三个问题框架,进行建设性而非破坏性的设计反馈:

  • I like: 指出设计中有效的部分,肯定已有的成功决策
  • I wish:以期望而非批评的口吻,指出可以改进的方向
  • What if ? :提出探索性建议,激发设计者思考新的可能性

视觉设计速查表

Visual Design Cheatsheet — 界面自解释目标

布局(Layout)

视觉组件如何组织和分组

  • 将元素对齐到网格
  • 尺寸大小传达层级重要性
  • 留白区区分内容组
  • 用户优先扫描,从左上角开始
  • 遵循 F 型扫描路径

字体排印(Typography)

编排文字使语言易读且美观

  • 字号因字体而异;小屏可用较大 x 高度
  • 衬线 vs 无衬线对可读性影响极小
  • 左对齐比居中更容易扫描
  • 留白区区分文字段落
  • 字重建立信息层级

色彩(Color)

提升美感、建立氛围、传达分组

  • 相邻颜色会相互影响感知
  • 颜色由色调、饱和度、明度定义
  • 数字界面用 RGB 或 hex 表达
  • 利用色轮定义调色板(Color Harmonies)

实践篇

我的理解

视觉层级本质上是把产品的优先级编码进空间:尺寸、位置、留白和对比度都在替用户决定先看什么。因而“看起来统一”不是终点;如果最显眼的元素与用户的首要任务不一致,再精致的组件库也只是在稳定地放大错误优先级。

Vue 进阶

官方教程入口:https://vuejs.org/tutorial

核心指令速查表

指令简写用途Tutorial 步骤
ref / reactive—创建响应式变量。ref 用于基本类型;reactive 用于对象Step 2
v-bind:attr:attr将 HTML 属性绑定到动态 JS 变量,实现运行时赋值Step 3
v-on:event@event绑定事件监听器,触发时调用对应函数Step 4
v-if / v-else—条件渲染:根据变量值决定渲染哪个区块Step 5
组件嵌套—父子组件构成层级树结构,类似 DOM 树Step 11
defineProps—父组件向子组件传递数据(Props)Step 12
defineEmits—子组件向父组件发送数据(Emits)Step 13

视觉设计分析

前端设计库

代表性工具:Vuetify(Vue 生态中最流行的 Material Design 组件库)。

当我们知道什么是好的视觉设计之后,下一个问题是: 如何在代码中实现它? 前端设计

Rec 8:Visual Design Study 与前端设计库

官方课件:More Vue + Visual Design Study + Visual Design Libraries(2025 年 10 月 23 日)。

什么是"视觉设计研究"(Visual Design Study)

定义:一份视觉设计研究,探索色彩、布局、字体排印、图像等视觉选择,如何影响人们"看到什么、理解什么、感受到什么"。

为什么要做:目的是训练"设计师之眼"(designer's eye)——把前面讲的布局/字体/色彩这些抽象原则,放进具体案例里检验"什么有效、什么无效"。做完之后你会获得:

  • 视觉素养:学会分析字体、色彩、布局是如何共同起作用的
  • 设计词汇:能用"高对比度调色板""高 x 高度""强对齐"这类具体语言描述"为什么好看",而不是只会说"好看"
  • 灵感素材库:收集可供自己设计时参考的视觉资料
  • 有意图的设计选择:能为自己选的颜色、字体说出理由,而不是凭直觉
  • 模式识别能力:在不同媒介、不同风格中发现反复出现的设计策略

三步做法

  1. 收集灵感素材:从海报、游戏、音乐专辑封面等任意视觉媒介中收集参考图(课件示例用了乐队 Parquet Courts 几张专辑封面:Wide Awake! 的鲜艳撞色插画风、Human Performance 的蓝色几何构图、Neo-Politans 的自然主题拼贴)
  2. 组织成拼贴图并做批注:把收集到的素材拼在一起,针对色彩标注主色、色彩关系与调色板选择(例如"冷蓝配三级色的绿与黄,营造都市自然感");针对字体排印标注字体、字号、位置、内容传达的情绪(例如"全大写、字距紧密,传递兴奋与混乱感,呼应封面内容";"文字被切块打散分布在封面各处,传递失落感")
  3. 反思:综合笔记,写出你学到了什么。课件示例的反思是:Wide Awake! 用大胆的互补色营造出适合朋克乐队的强烈能量感;转向 Human Performance 更冷的蓝绿黄色调,情绪随之软化为更安静的都市氛围;两张专辑的字体排印手法(紧凑大写 vs. 疏离破碎)恰好分别呼应了各自的情绪基调。

这个流程也正是 Assignment 4b/期末项目里"Visual Design Study"交付物(两页带标注的参考图收集)所要求的做法。

前端设计库(UI Component Libraries)

知道了什么是好的视觉设计之后,下一个问题是:怎么在代码里实现它?答案之一是使用前端设计库——预先写好、可直接复用的 UI 组件集合。Vue 生态里最常用的是 Vuetify(一个"不需要设计技能"的开源 UI 库,提供大量精心设计好的 Vue 组件:按钮、卡片、列表、芯片标签、分割线、折叠面板等),此外还有 Chakra UI、MUI、Ant Design、React-Bootstrap 等(多数面向 React 生态)。

优点:

  • 开箱即用大量样式和组件,减少从零造轮子的工作量
  • 可复用组件保证界面视觉一致性(同一个 v-btn 在全站表现一致)
  • 生成的代码更"可移植",方便自己和协作者维护

缺点:

  • 定制化可能很麻烦:想要"按钮不是灰色的",往往要一路深入到主题配置(如 Material Design 的 md.sys.color.primary token)才能改动,改一个小细节可能牵涉一整套设计系统
  • 组件默认样式可能和布局冲突(例如某些组件默认 width: 100%,在 flex 容器里会导致溢出问题,需要额外覆盖)
  • 库本身可能过时或与所用框架版本不兼容(社区里常见"Vuetify 2 升级到 3 几乎没法迁移"这类抱怨)

选择是否使用设计库,本质上是"开发速度与视觉一致性"和"精细控制与长期维护成本"之间的权衡。

Vue 补充:组件通信(Props 与 Emits)

延续 Lec 13 的响应式基础,这次习题课补充了父子组件之间双向传递数据的两种机制:

  • Props(父传子):父组件通过属性绑定把数据传给子组件,子组件用 defineProps 声明要接收的字段:
    <!-- Parent.vue -->
    <ChildComp :msg="greeting" />
    
    <!-- Child.vue -->
    <script setup>
    const props = defineProps({ msg: String })
    </script>
  • Emits(子传父):子组件通过 defineEmits 声明自己会触发哪些事件,调用 emit(...) 把数据"发射"回父组件;父组件用 @事件名 监听:
    <!-- Child.vue -->
    <script setup>
    const emit = defineEmits(['response'])
    emit('response', 'hello from child')
    </script>
    
    <!-- Parent.vue -->
    <ChildComp @response="(msg) => childMsg = msg" />

组件树的通信原则是:数据只能沿父子关系流动——父到子用 props,子到父用 emits,不存在跨层级的隐式共享状态;这与本课程"概念之间不共享状态、只能通过显式 Sync 通信"的设计哲学是一致的道理,只是发生在前端组件树这个更小的尺度上。