27 寸 4K 在 60cm 看,PPI 是 163.18,肉眼分辨阈值只有 145.53,单个像素根本看不见。
同一块屏开到 125%,1 个 CSS 像素要摊到 1.25 个设备像素上,老程序的位图就被拉出两列灰边。
我把这套换算做成一个离线网页,输入对角线、分辨率、观看距离,PPI、点距、阈值、结论和缩放灰边一次算清。页内 12 条断言,12/12 通过。

在线案例与源码:gitcode.com/OPCTeam/dem... 成品只有一个 index.html,双击就能打开。
一、为什么值得看:4K 的清晰和 125% 的发虚是两件事
PPI 的算法很直白:对角线上的像素总数除以对角线英寸数。
像素总数是宽高的平方和再开方,27 寸 3840×2160 算出来是 4405.8,除以 27 得 163.18 PPI。
点距是它的倒数,25.4 除以 163.18,得到 0.1557 毫米。
我把 24 寸 1080p 也放进去比了一下,91.79 PPI,点距 0.2767 毫米,像素块大了一半多。
真正决定「看不看得出像素」的不是 PPI,是 PPI 和观看距离的比值。
人眼的分辨极限常用 1 弧分来算,换算成屏幕就是 87319 除以距离毫米数。
60cm 时阈值是 145.53 PPI。27 寸 4K 的 163.18 除以 145.53 等于 112%,过了线。
同样 60cm,27 寸 2K 只有 108.79 PPI,比值 75%,结论就变成能看出像素颗粒。
把距离拉到 80cm,阈值降到 109.15 PPI。27 寸 2K 的 108.79 刚好卡在 99.7%,属于临界。
这张表是页面里七种屏幕的实测值,阈值统一按 60cm 算。
| 屏幕 | PPI | 点距 | 60cm 阈值 | 结论 |
|---|---|---|---|---|
| 24 寸 1080p | 91.79 | 0.2767 mm | 145.53 | 能看出颗粒 |
| 24 寸 2K | 122.38 | 0.2075 mm | 145.53 | 接近临界 |
| 27 寸 2K | 108.79 | 0.2335 mm | 145.53 | 能看出颗粒 |
| 27 寸 4K | 163.18 | 0.1557 mm | 145.53 | 看不出像素 |
| 32 寸 4K | 137.68 | 0.1845 mm | 145.53 | 接近临界 |
| 16 寸 2K+ | 188.68 | 0.1346 mm | 145.53 | 看不出像素 |
| 6.1 寸手机 | 457.25 | 0.0555 mm | 145.53 | 看不出像素 |
32 寸 4K 是个容易被忽略的反例:分辨率比 27 寸 2K 高,PPI 却只比它多 28.9,60cm 只是接近临界,还谈不上看不出。
尺寸一大,同样的 3840×2160 被摊薄了。
二、准备环境:进入码道 Web
浏览器打开码道 Web 版:devcloud.cn-north-4.huaweicloud.com/chat?source...
码道有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。本文用 WebUI 版演示。
三、需求原文:把公式和断言写死
这一轮我把所有公式、期望值和 12 条断言都写进了需求,不让模型自己回忆。
断言里最关键的是第 10 条:200% 整数缩放的灰边宽度必须是 0,125% 必须大于等于 1。
第一版交付时页面显示 11/12,第 10 条 FAIL,实测值写着「200%: 2, 125%: 2」。
这不是显示错误,是代码真把 200% 算出了灰边。
四、实测:三张图、两张表、12 条断言
像素对比区固定了 120 毫米的物理宽度,按 91.8 / 108.8 / 163.2 PPI 换算出 434 / 514 / 771 像素。
三张画布先按各自的真实像素宽度画同一段「清晰度测试 Abc123」,再关掉平滑放大到 320 宽。

91.8 PPI 那张的字边缘是整块整块的方格,163.2 PPI 那张已经接近平滑。
缩放区没有用画布插值,改成一条 40 列的一维数组,第 20 列是黑,其余是白。
按 1.0 / 1.25 / 1.5 / 2.0 重采样到 40 / 50 / 60 / 80 列,再逐列数非纯黑非纯白的像素。
| 缩放 | 1 CSS px 对应 | 灰边宽度 | 判断 |
|---|---|---|---|
| 100% | 1.00 设备 px | 0 列 | 整数倍,干净 |
| 125% | 1.25 设备 px | 2 列 | 非整数,发虚 |
| 150% | 1.50 设备 px | 2 列 | 非整数,发虚 |
| 200% | 2.00 设备 px | 0 列 | 整数倍,干净 |

12 条断言跑完是 12/12。A1 到 A3 分别量出 163.18、108.79、91.79 PPI。
A4 量点距 0.1557 mm,A5 量 60cm 阈值 145.53 PPI,A11 量手机 457.25 PPI。
A6 和 A7 判结论,A8 和 A9 判 1 CSS 像素对应几个设备像素,A12 判错误提示。
我把 24 寸 1080p 那组参数改到 40cm 又跑了一遍,PPI 还是 91.79,阈值升到 218.30,比值掉到 42%。
结论直接从「接近临界」翻成「能看出像素颗粒」。

这也解释了为什么同一台显示器,坐远一点觉得细腻,凑近看全是格子。
五、踩坑:200% 也被算出了灰边
第一版的 resampleColumns 只有一套双线性公式,100% 到 200% 全走它。
200% 时采样点落在两个源像素正中间,插值出 0.5 的灰,页面就报「200%: 2」。
真实显示器的整数缩放是复制像素,不是插值。2 倍就是每个像素画成 2×2,边缘不该有灰。
我把整数倍单独分出来,直接取源列复制;非整数倍才走双线性。
改完再跑,200% 的灰边变成 0,125% 仍然是 2,A10 通过,12/12。
第二个坑在像素对比图。第一版字号按画布高度算,434 像素那张写不下整句,左右各被裁掉一截,截图里只剩「度测试 Abc」。
后来加了一个循环,用 measureText 量宽度,超宽就把字号减一,直到塞得进画布减 6 像素。
错误路径也实测了。我把对角线填成 0,参数区下方立刻出现红条「对角线必须大于 0」。
上面的 163.18 PPI、0.1557 mm、145.53 PPI 全部保留,没有变成 NaN,也没有清空。

六、边界:这是换算和模拟,不是显示器实测
页面上的 PPI 和点距是算出来的,前提是像素为正方形,而且屏幕没有做非原生分辨率缩放。
阈值用的是 1 弧分的标准视力,个体差异很大,戴眼镜和不戴眼镜的结果就不一样。
缩放区的灰边是一条一维竖线的重采样结果,只回答「整数倍和分数倍在采样上的区别」。
浏览器里的矢量文字仍然按设备像素重绘,真正发虚的主要是位图素材和老式 GDI 程序。
125% 下现代应用里的文字大多还是清楚的,别把这张图当成「所有界面都会糊」。
七、使用码道体会
- 公式和期望值直接写进需求,模型就没有「大概」「差不多」的空间。
- 断言必须显示实测值,不能只写一个 true。这次 A10 就是靠「200%: 2」这行数字抓到的。
- 自检放在页面里,交付时能当场点开,文章里的 12/12 才有出处。
- 整数倍和分数倍这种边界,提前写成一条断言,比事后手测快得多。
- 截图前把每一张放大看一遍。第一版文字被裁掉一截,就是放大后才发现。
- 错误路径也要给断言:填 0 必须报中文错,而且不能清空上一次的结果。
八、结果与下一步
选显示器时,先量一下平时的观看距离,再拿 PPI 和「87319 除以距离毫米数」的得数比一比。
60cm 桌面前,27 寸 4K 的 112% 很稳,27 寸 2K 的 75% 能看出颗粒,24 寸 1080p 只有 63%。
80cm 沙发距离,27 寸 2K 的 99.7% 刚好够用,再低就该上 4K 了。
缩放优先选 100% 或 200% 这类整数倍。125% 和 150% 不是不能用,是要接受位图素材多出两列灰边。
成品和源码都在这里:gitcode.com/OPCTeam/dem...
下一步想补两块:带鱼屏的等效 PPI,以及 macOS 的 HiDPI 缩放和 Windows 的整数缩放有什么不同。