不知道大家用没用过手机上的"暗黑模式",我这两天算是让这玩意儿折磨的够呛,晚上寻思黑乎的浏览点儿东西,我眼差点儿没瞎。
尤其是某宝的暗黑模式,我可以毫不客气地说:简直拉完了。

某宝里面的XX超市,大家可以试试自己的手机,这个超市里面的购物车页面、结算页面,暗黑模式下还是白的,关键背景白的也就算了,字也是白的...
除了代码层面的一些BUG,我还发现了一个所有App暗黑模式的通病:白色图片。
适配
其实现在市面上绝大多数App、网页的暗黑模式都做了UI适配,深色界面看着护眼又高级,尤其我们干程序的,大多数人的IDEA、VsCode都是黑色主题。
但唯独白底图片、截图、文档素材格格不入。
深夜开启暗黑模式,整个界面都是静谧的深色,突然纯白底图片,晃得人差点儿没"失明"。
其实这个事儿真怪不得程序员,程序员大多是"执行者",真正的"决策者"是产品经理。
目前暗黑模式的适配方案业内通用的大多是:只针对页面UI、文字、背景等元素生效,可以自动反转颜色、降低亮度。
但因为图片属于静态资源 ,系统和App无法自动识别,也不能去修改图片颜色,这就导致深色页面 和纯白底图片出现强烈对比。
更麻烦的是,图片场景极其复杂:有官方内置的素材、用户上传的截图、生活照片、彩色海报...,全局一刀切变暗,只会毁掉正常图片的观感,这也是很多产品不敢随便适配的关键原因。
解决方案
下面我简单整理了5套分级的优化方案,所有方案按「开发成本从低到高、适配效果从通用到极致」排序,大家自行"选购"。
1. 全局亮度降噪(零成本、快速兜底)
这是应该算是入门级最优兜底方案,无需修改图片资源,仅通过一行滤镜代码,在暗黑模式下统一降低图片亮度。
同步系统暗黑模式,弱化白底的刺眼感,基本能够适配所有图片场景。
原理是通过主题媒体查询,监听暗黑模式状态,对所有图片生效亮度滤镜。
css
/* 仅暗黑模式下降低图片亮度 */
@media (prefers-color-scheme: dark) {
img {
/* 数据根据实际情况调整 */
filter: brightness(0.8);
}
}
优点:实现零成本、全局一键生效、兼容性拉满,全端通用。
缺点:全局统一生效,但是对于深色系照片、彩色的配图会存在轻微发灰的现象,细节可能略有丢失。
适用场景:快速迭代项目、小型工具类App、对图片画质要求不高的产品。
2. 颜色反转(针对白底截图/文档)
针对最刺眼的白底黑字截图、文档、图表素材 这种情况,可以通过颜色反转+色相微调。
来让白底变黑底、黑字变浅字,完美适配暗黑阅读场景。
原理是使用CSS的反转滤镜,搭配180度色相矫正,避免色彩失真。
css
/* 暗黑模式下白底文档/截图反转适配 */
@media (prefers-color-scheme: dark) {
.img-doc, .img-screenshot {
filter: invert(0.9) hue-rotate(180deg);
}
}
优点:文档类内容阅读体验质变,彻底解决白底反光问题。
缺点:仅适配白底纯色素材,彩色照片、插画禁用,否则会严重偏色。
适用场景:仅适合知识库、办公类、资讯类、工具类产品(截图文档内容居多),别的不行,只要牵扯到别的颜色的图片,尽量都不要用这个方案。
3. 双素材适配(官方素材)
这个是主流大厂产品的终极适配方案,从源头解决问题,也是体验最完美的方案。
让设计那边提前输出两套素材,分别适配浅色、暗黑模式。
浅色模式的时候加载原图,暗黑模式自动切换深色配图,无任何突兀感。
js
// 监听系统暗黑模式状态
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
// 根据主题切换图片资源
imgSrc = isDark ? '/images/banner-dark.png' : '/images/banner-light.png'
优点:视觉统一、零失真、无滤镜磨损,用户体验极致。
缺点:人力成本高,需要设计配合出图,仅支持官方内置素材,无法适配用户上传图片。
适用场景:精品App、大厂产品、UI要求高的商业化项目,而且仅适合官方素材,用户上传的不可能。
4. 智能图片识别
这个方案属于是兼顾低成本+高体验的方案了。也是我个人比较推荐的方案,基本完美解决前三种方案的短板:不用两套素材、不影响正常照片,最关键不用太多功夫,全自动识别适配。
核心思路是通过Canvas轻量像素采样,自动判断图片是否为白底图片,精准区分素材类型,只对刺眼的白底图生效优化滤镜,正常照片、彩色图保持原样。
核心实现逻辑:
-
图片加载完成后,通过Canvas截取图片像素信息。
-
仅采样图片四周边缘像素(这样能达到性能最优,无需遍历整张图)。
-
统计白色像素占比,超过阈值(70%左右)就判定为白色底图图片。
-
暗黑模式下,仅对判定成功的白底图自动降亮度,其余图片无改动。
js
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, width, height)
// 采样边缘像素、统计白色占比
let whiteCount = 0
// 采样上下左右边缘像素(步长采样,保障性能)
// 判定白色像素:RGB 均大于 240
const isWhite = (r, g, b) => r > 240 && g > 240 && b > 240
// 阈值判断 + 动态加滤镜
const whiteRatio = whiteCount / totalSample
if (whiteRatio > 0.7 && isDarkMode) {
img.style.filter = 'brightness(0.78)'
}
优点:全自动智能化适配、无需人工标记、不损伤正常图片的画质,能够适配用户上传的图片,性价比极高。
缺点:存在小概率的识别误差,并且需要处理图片跨域的问题。
适用场景:绝大多数C端产品、UGC内容平台、图文社区、通用型项目。
5. 视觉过渡
这是我从一个UI那儿听来的方案,属于一种"取巧"的UI设计。
在暗黑模式下,给所有图片统一添加圆角+深色的柔光阴影,在深色背景和白底图片之间形成一种视觉过渡,来缓解对比度冲击。
也就是说,白图还是白,但是看起来没这么刺眼了。
css
@media (prefers-color-scheme: dark) {
img {
border-radius: 8px;
box-shadow: 0 0 12px rgba(0, 0, 0, 0.6);
}
}
给用户最终选择权
除了上面说的从技术层面解决问题,还有就是从"产品设计"方面说话。
因为技术方案总有"适配边界",最完善的产品设计,是把选择权交给用户,建议产品经理可以考虑在项目中增加两个配置:
-
全局设置开关:增加「暗黑模式自动优化白底图片」选项,默认开启,支持用户手动关闭。
-
夜间强化模式:在普通暗黑模式基础上,新增深夜模式,进一步收紧图片亮度阈值,极致护眼。
结语
之前我也真没用过这种模式,最近晚上看手机多,才发现这个问题。
回头还得说一个模式,更膈应人,就是"长辈模式",各家App做的简直一坨答辩,尤其重点批评某地图,我妈那个手机打开这个功能以后,我都没找到咋弄。
说一句显得高大上的话:暗黑模式从来不是简单的"变白为黑",真正优质的深色适配,应该是是兼顾UI、文字、图片、动画的全方位体验优化。
如果你有更好的方案,欢迎留言。