他以为30分钟能搞定的功能,最后花了整整一个周末。不是代码写得慢,是每一层依赖都在逼他重新思考:颜色到底是什么?
从"改个配色"开始
![]()
作者最初的想法很简单。网站要加暗色模式,他扫了一眼代码:没多少颜色,Tailwind 工具类里硬编码了几个十六进制值,改起来应该很快。
真正动手才发现,每个标题、每段正文的颜色都是写死的。要换主题,得逐个元素手动改。这条路走不通。
他引入了层叠样式表变量(CSS 变量),但第一次命名就踩了坑:hover-dark、hover-darker——字面意思的变量名在暗色模式下完全失效。hover-darker 在深色背景上意味着什么?更深的黑?
问题倒逼他换了一种提问方式。不再是"这个元素用什么颜色",而是"这个颜色承担什么角色"。
变量名从字面描述转向语义描述:text-primary 取代"黑色",background-primary 取代"白色"。颜色与具体色值解耦,主题切换变成变量值的批量替换。
到这里,他以为大局已定。实际上才刚开始。
白字黑底为什么刺眼
他的第一反应是暗色模式等于白字黑底。结果上线一看:刺眼、难读、所有元素糊成一片,像突然得了散光。
暗色模式不是简单的颜色反转。纯白(#FFFFFF)在纯黑(#000000)上产生的对比度过高,屏幕亮度在暗环境下被放大,眼睛疲劳感急剧上升。
他换成浅灰作为背景,文字用更柔和的灰白色。次要文字再用更浅的灰色分层。对比度从极端值下调,阅读舒适度显著提升。
「白字黑底对我的屏幕来说对比度太高,眼睛能直接感受到。」他在复盘时写道。
这个调整很小,但改变了整个视觉系统的逻辑:暗色模式不是"亮色的反面",而是独立的一套对比度层级。
抽象层的崩塌与重建
颜色问题解决了,界面还是不对劲。两个具体场景暴露了他之前埋下的技术债。
第一个是排版。Tailwind 的排版插件(prose)在亮色模式下运行良好,但与他自定义的变量系统冲突。部分样式跟随新变量更新,部分仍固守默认值。修 A 坏 B,隐藏的复杂度全部浮现。
他的应对方式是把排版也纳入变量系统:显式映射 Tailwind 的排版变量到自己的变量集,不再依赖任何默认配置。当所有路径指向同一套变量,行为重新变得可预测。
第二个是代码高亮。他的博客有大量 JavaScript 事件循环系列的技术文章,代码块使用 GitHub 的亮色主题。切到暗色模式后,代码完全无法阅读。
他试过直接换成 GitHub Dark 主题,结果亮色模式下又显得突兀。一度以为只能二选一,最后意识到 obvious solution:两个主题都用,根据当前模式动态切换。
为什么这件事值得技术人关注
这个案例的价值不在于暗色模式本身,而在于它展示了前端系统设计的典型陷阱。
硬编码色值是最直接的债,但真正的成本在认知层面:当你用 black 和 white 命名变量时,已经预设了主题不可变。语义化命名是设计决策,不是代码风格偏好。
对比度的调整说明,用户体验细节往往违反直觉。白字黑底在逻辑上"正确",在生理上错误。技术实现需要对接真实感知,而非抽象规则。
排版插件和代码高亮的冲突则指向一个更普遍的问题:第三方工具的抽象层何时会背叛你?当工具的设计假设与你的系统目标分歧,封装的优势变成调试的噩梦。显式映射是笨办法,但是可靠的办法。
如果你正在维护一个界面系统,现在可以检查三件事:颜色是语义命名还是字面命名;暗色模式的对比度是否经过真实环境测试;第三方工具的默认配置有多少被隐式依赖。作者用整个周末换来的教训,你可以用十分钟排查。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.