开篇小故事:做按钮设计时,我把默认态颜色定好后,开始处理交互状态。hover 用了一个颜色,pressed 用了一个颜色,disabled 用了另外一个颜色。
我常用的取色方法是打开设计软件的取色器,通过把默认色向深浅两个方向拖拽,找到符合需要的即可。比如把 hover 拉深一点,pressed 再深一点,disabled 把透明度降到 50%。三个状态各花了两分钟,很快就做完了。
然后我开始做卡片组件。卡片也有 hover,pressed,和 disabled。同样的方法,我又打开取色器,重新拉了一遍。拉完之后发现卡片的 hover 态颜色深度和按钮的 hover 态颜色深度不太一样,但说不清楚该不该一样。
再然后是做图标按钮、文字链接、标签页、列表项的三态设计。我继续用同一种方法,每一个组件都有自己的一套交互状态颜色,每一套都是单独调的。等做到第五个组件的时候,我已经不记得第一个组件的 hover 加深了多少?所以只能回去对照,但对照完也没什么用,因为当初并没有建构一个可以对照的标准。每次做完一个新组件,都是在重新创造一遍交互状态的颜色,而这些颜色本来应该从一个统一的规则中推导出来。
一、三种状态各自代表什么
hover、pressed、disabled 看起来只是"颜色深浅不同",但它们传递的信息完全不一样。在定颜色之前,最好先搞清楚每个状态都在向用户传递什么。

hover 传递的信息是"这里可以交互"。当用户的光标移到一个元素上方,元素发生了视觉变化,用户由此获得的感知是:这个东西不是静态的,我可以对它做点什么。hover 是一个邀请信号,像门开了一条缝,让人知道可以推开,但人还没推进去。
pressed 传递的信息是"你的操作已经被接收了"。用户按下了鼠标或手指触碰了屏幕,元素立刻给出反馈,告诉用户:收到了,正在响应。pressed 是一个确认信号,反馈力度比 hover 强一个等级。但用户松手之后,这个状态就结束了。
disabled 传递的信息是"这里现在不能操作"。和前两个状态不同,disabled 不是交互过程中的一个环节,而是一个结论:这个元素当前不在可用范围内。disabled 是一个阻止信号,它不想吸引用户的注意力,而是希望用户的视线跳过这里,去找真正能操作的地方。
hover 和 pressed 都在"活跃"的方向上递进,颜色变深、视觉权重变重,传递的是"正在参与交互"的信息。disabled 则在相反的方向上移动,颜色变淡、视觉权重变轻,传递的是"退出交互"的信息。
二、状态变化的核心原则
知道了 hover 和 pressed 要变深、disabled 要变淡,那么接下来的问题就是:深多少?淡多少?这个变化幅度受两个互相矛盾的要求共同约束。
第一个条件是变化量要足够被感知。用户把光标移到按钮上,如果颜色几乎没变,用户会怀疑这个按钮是不是真的可以点击。用户按下了按钮,如果颜色和 hover 一样,用户会怀疑自己到底有没有按到。每一级状态的颜色变化都需要超过人眼的感知阈值,否则状态反馈也就失效了。
第二个条件是变化后的视觉权重不能超过组件在界面层级中的位置。一个次要按钮 hover 之后,颜色变得比主按钮的默认态还深,整个界面的视觉层级就被打乱了。一个列表项 pressed 之后,颜色比页面标题还重,用户的注意力会被错误地拉走。状态变化是在组件自身范围内发生的事,不应该影响到界面整体的视觉秩序。
变化要够大,用户才能感知到反馈;变化又不能太大,组件不能因为状态变化而越级。
这个原则解释了为什么交互状态的颜色变化通常是温和的。hover 的明度变化只有 10-15%,pressed 再多 5-8%,都不是大幅度的跳变。设计师在日常工作中凭感觉调深调浅,调出来的合适范围往往也在这个区间附近。
三、Hover
hover 状态下,用户还没有点击,只是把光标移了过来,元素需要给出一个轻微的视觉反馈,告诉用户:这里有响应,你可以继续。
hover 的颜色变化主要发生在明度这个维度上。在 HSL 色彩模型里,H(色相)和 S(饱和度)保持不变,L(明度)降低 10-15%。色相不变是因为 hover 不改变组件的身份——一个蓝色按钮 hover 之后还是蓝色按钮,不应该变成另一种蓝。饱和度不变是因为 hover 不改变组件的功能语义——主按钮 hover 之后不应该看起来比默认态更鲜艳或更灰暗。只有明度在动,而且只动一小步。
为什么是加深(降低明度)而不是变浅(提高明度)?试想一下,如果 hover 让颜色变浅,用户正在把光标移过来,元素反而在视觉上"退远"了,和靠近的动作方向相反,认知上会很别扭。加深的方向则和物理世界的经验一致:当手指靠近一个物体表面,手指投下的阴影会让物体局部变暗。屏幕上的 hover 效果模拟的就是这种"有东西靠近了"的感觉。加深意味着"有接触的倾向",用户直觉上理解为:我正在接近这个元素,准备和它互动。
具体加深多少取决于组件的默认态颜色。一个中等明度的蓝色按钮(比如 HSL 220, 80%, 55%),hover 态把明度降到 45% 左右,变化量大约 10 个百分点,视觉上是从"蓝色"变成"稍微深一些的蓝色",用户能感知到变化,但不会觉得按钮突然变了一种颜色。

但这个 10-15% 不是所有情况都适用的固定数字。浅色组件和深色组件的处理方式不同。
浅色背景的按钮(比如一个白底蓝字的次要按钮)hover 时不适合直接加深背景色,因为它本身就是浅色的,加深 10% 的效果可能不明显。这类组件的 hover 通常采用另一种方式:叠加一层极浅的背景色。比如在白色背景上叠一层 5-8% 不透明度的主色,形成一个若有若无的色调变化。用户的感知是"这个区域有点不一样了",而不是"颜色变深了"。
深色实心按钮(比如深蓝底白字的主按钮)hover 时直接降低明度就够了。从 HSL 的 L 值 45% 降到 35-38%,变化清晰,和默认态的层级也不冲突。
还有一类元素需要说明:卡片、列表项这类容器元素。它们的 hover 通常不是改变自身颜色,而是在底部叠加一层浅灰色或极低不透明度的黑色蒙层。原因是容器内部有文字、图标等子元素,如果容器本身颜色变化太大,子元素的对比度也会跟着变,阅读体验会受影响。叠加一层淡淡的蒙层作为 hover 反馈,容器的视觉变化足够被感知,内部内容的可读性也不会受影响。
还有一个细节会影响 hover 的感受:过渡动画的速度。hover 颜色变化通常配合 150-200ms 的 ease-in-out 过渡。太快(50ms 以下)会让变化看起来像界面闪烁,太慢(400ms 以上)会让用户觉得界面迟钝。速度不改变颜色本身,但会改变用户对 hover 反馈的整体感知。








