“这一行的分割线高了一点。”
好的,减小行高, 加点上下内边距。

“这几个元素要两端对齐。”
好的,flex没有解决不了的布局,justify-content: space-between;搞定。

……

“这个图标颜色不对,应该是#999。”
好的,我改…等等,明明就是 #999 啊,这分明是想被打脸的节奏。打开页面,右键图标,审查元素,截图。
是不是 999 ?是不是 999 ??是不是 999 ???

“所有的下边框都应该是1px。”
我看到这个问题的瞬间,感觉像在侮辱我的智商。边框 1px 这么常用的样式,我还会写错不成?

正当准备继续“打脸”时,突然我的好奇心上来了。关于 1px 边框在移动设备上看起来比较粗 这个问题,我也曾经想过。
因为页面其他内容看起来都是正常的,所以我一直觉得这是移动设备浏览器的渲染问题,属于外部原因。
也曾设置过 .5px ,但显然浏览器并不买账。

搜索关键字1px border,找到了问题所在。

devicePixelRatio

说来惭愧,关于 devicePixelRatio,我也算是有使用经验的人了,怎么就没有想到呢。

简单举例一下,我的 MX5 分辨率是 1920*1080,但是实际屏幕物理像素是 640*360,换算得出 devicePixelRatio = 3。
也就是说屏幕中的1点 = 3px

设计师提出的图标颜色不对的问题也在于此,因为颜色也受益于分辨率。

viewport

这一切都是 viewport 在作怪!

我们在开发手机页面时,都会这样设置。

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  • width=device-width: 设置浏览器内容宽度为设备物理像素宽度。
  • initial-scale=1: 缩放比为1,后面两个属性为最大和最小缩放比。
  • user-scalable=no: 禁止用户手动缩放。

用 1920*1080 分辨率的手机打开一个没有添加 viewport 的PC站点,横屏状态是可以完整的出页面内容的。因为这个时候的 1px 就是 1px。

还原分辨率

知道了问题的原因就对症下药了。

可以根据window.devicePixelRatio来动态修改屏幕缩放比,还原真实分辨率。
还有一个问题。

分辨率还原了,那岂不是所有元素的尺寸数值都需要重新计算了?
如果你的 css 没有使用 em 和 rem 为单位的话,那么恭喜你,一个一个慢慢改吧。
而使用 em 和 rem 为单位就简单多了,只需要动态修改根元素字体大小就行了。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%=title %></title>
<meta id="vp" name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<script>
(function () {
var vp = document.getElementById('vp');
dpr = window.devicePixelRatio,
html = document.getElementsByTagName('html')[0],
vpVlue = 'width=device-width, initial-scale=X, maximum-scale=X, minimum-scale=X, user-scalable=no';
if(dpr) {
vp.content = vpVlue.replace(/X/g, (1 / dpr));
html.style.fontSize = (14 * dpr) + 'px';
}
})();
</script>
<head>

这可以直接加到头部模版中。

关于修改根元素字体大小也可以使用 css媒体查询的方式。

@media (-webkit-min-device-pixel-ratio: 2) {
html {
font-size: 28px;
}
}
@media (-webkit-min-device-pixel-ratio: 3) {
html {
font-size: 42px;
}
}

彩蛋

本来 js 代码我是放到 body 闭合前的。
viewport 初始缩放值是 1 ,根元素初始字体大小是 14px,我的手机 devicePixelRatio 是 3。按照浏览器加载顺序,等执行到 js 前,页面内容应该 1/3 的大小;执行完 js 后,页面恢复实际大小,整个页面居然出现了类似于transform: scale(1)般的过渡效果。

为了让用户更早的看到页面内容,我还是决定放到头部了。

问题更新

以上的思路和代码确实解决了问题,至少我在手机浏览器上测试是OK的。之后在 APP 中嵌入后发现没有效果,页面内容都因为字号修改被放大了。
我怀疑是安卓端的某些配置的原因,但是不了解的事又不好乱发言。

最后抽了一个闲工夫,把安卓环境搭了起来,看着 WebView 的API,自己写了个测试DEMO。
问题解决了。

webview.getSettings().setUseWideViewPort(true); // 自适应手机屏幕

从方法名就很容易理解这个配置项与 viewport 存在着关系。
问题解决了,我要去安卓那边装逼了。