探究移动端 viewpoint 本质

1,665 阅读6分钟

科普前端尺寸系列,推荐按顺序阅读

  1. px 与像素是如何换算的
  2. 探究移动端 viewpoint 本质
  3. 移动端页面的三种尺寸

前置名词

  • 物理分辨率、物理像素
  • 逻辑分辨率、逻辑像素
  • clientWidth

如何设置移动端 viewpoint?本质是问,如何让页面在移动端更好的展示,适配更多的尺寸

电脑端 clientWidth

我们不妨先从电脑端入手,在适配不同逻辑分辨率的电脑端时,一定少不了使用媒体查询来实现自适应布局。

**自适应:**屏幕适配有粒度区分,原则上不做过渡态的 UI 设计,同一设备上做宽度变化时,内容布局卡顿式梯级变化;

原理是:

@media only screen 会查询浏览器的逻辑分辨率宽 document.documentElement.clientWidth。然后根据 clientWidth 值匹配不同样式,实现各自分辨率下的页面布局、样式。

移动端 clientWidth

通过 alert(document.documentElement.clientWidth) ,可以得知 iPhone6s 的 clientWidth,也就是逻辑分辨率等于 980。

这是因为 iPhone 刚推出的时候,还没有专门给手机设计的网页,而当时电脑的主流逻辑分辨率宽就是 980。乔布斯心想,那就指定 iPhone 的逻辑分辨率宽为 980 吧,这样在手机上访问网页,也能保证页面的正常布局了。

现在市面上的大部分手机、平板,基本也沿用的这个设定。不过,这种方法,虽然能让人把页面看个大概,却无法细读,原因是字实在是太小了。

修改 clientWidth

如果你接触过移动端设计,一定见过这条 viewpoint 相关的 meta 标签

<meta name="viewport" content="width=device-width, initial-scale=1.0">

为了减小干扰,我们先取前半部分给页面加上

<meta name="viewport" content="width=device-width">

页面看起来正常多了。所以原理到底是什么?

如果两个逻辑分辨率宽度分别为 10、20 的屏幕上都有一条长 10px 的线。那么第一个屏幕里的线一定显得更大。相同尺寸的屏幕,逻辑像素越小,内容显示得越大

对比增加 meta 标签的两个页面,后者内容显得更大。在未修改样式的前提下,只可能是逻辑像素变小了。输出当前页面的 clientWidth ,等于 375,说明现在页面的 逻辑分辨率 宽度 375,远小于默认值 980。

所以 meta 标签中的 width=device-width ,其含义是: 设置浏览器的逻辑分辨率宽(width)等于设备的 device-width(对于 iPhone6s,值为 375)

总的来说  device-width 取决于手机屏幕大小和物理分辨率,大致与屏幕大小成正相关。这也会导致相同 px 在不同设备上表现不同,比如 iPhone6s 上 width: 375px 的线,在 iPhone 6 plus 上会无法铺满屏幕,在 iPhone 5 上会撑出屏幕。

机型device-width
iPhone 5320
iPhone 6,iPhone 6s375
Galaxy S5360
iPhone 6 plus414
iPad mini768

同理,只要让 width 等于定值,样式在不同尺寸屏幕上就会等比放大缩小,可以保证一套设计适配所有移动端设备。

还是刚才的页面,修改 meta 代码。也就是说,我们只需按照 375px 来设计、编写页面,就可以把在 iPhone 6s 上的布局缩放到任意设备上。

 <meta name="viewport" content="width=375">

上图是 iPad mini 和 iPhone6s 的效果对比。等比缩放也意味着,连文字换行的地方都一模一样,好像很完美的样子。但是细究起来,有如下缺陷:

  • 设备差距过大,导致缩放太多。例如图中的 iPhone 6s 与 iPad mini
  • 无法准确绘制最小物理像素
  • 375 只是 iPhone6s 的 device-width,px 可以很好与物理像素拟合上,对于其他设备则不是,容易内容导致模糊

总得来说,如果要求不高,算是一种粗糙的响应式布局

响应式:屏幕适配无粒度区分,同一设备上做宽度变化时,内容布局无缝圆滑变化;技术实现通常为,一套代码适配所有屏幕

device-width

重新思考一下为什么 iPhone6s 的 device-width 等于 375。除开与自身物理分辨率 750 有倍数关系外,还有一个最重要的原因,能让 px 对应最恰当的尺寸

比如一个 12px 的文字, 虽然 px 是逻辑像素、相对尺寸。但是这个相对也是有范围的,重新看上面的对比图,iPhone6s 里的正文大小,和浏览器地址栏里的内容是差不多大。考虑更多的情况,12px 文字的大小可以和桌面的图标、下拉菜单栏等手机系统里的各种 UI 产生相对关系。

在 iPhone6s 里,逻辑分辨率为 375 时,1px、逻辑像素的实际尺寸为屏幕 1/375  0.016cm 的情况下,是最恰当的。

而各个设备的物理像素大小不同,硬件性能不同,这个值也不尽相同。所以设置 width=device-width 总能保证这个值是最恰当的 

 <meta name="viewport" content="width=device-width">

initial-scale

单独对页面设置如下 meta,效果等同于 width=device-width

 <meta name="viewport" content="initial-scale=1.0">

代码实际效果是:设置页面的逻辑分辨率宽等于 device-width / initial-scale = 375 / 1 = 375 ,如果设置成 0.5,则逻辑分辨率宽等于 device-width / initial-scale = 375 / 0.5 = 750

至于为什么需要同时设置 width 和 initial-scale,网上的结论是 iPhone 横屏状态下 width 依然等于竖屏的 device-width,windows phone 里的 IE 浏览器横屏状态下...(谁关心呢,这个设备已经绝版了)。

反正我通过自测验证,iPhone6s 里已经没有这个问题了,完全可以只使用其中任意一个即可。

viewpoint

业界通常认为移动端浏览器有三种 viewpoint,通过此文,我们可以更加简明的对应上这三种 

  • layoutviewport 页面的实际宽度,也就是 clientWidth,默认 980,可以通过设置 width、initial-scale 来改变,如果两者冲突,取其中更大的。layoutviewport =Math(width, device-width / initial-scale)as 阿萨德
  • idealviewport 为浏览器定义的可完美适配移动端的理想 viewport,与设备绑定、固定不变。其实就是 device-width,基本与屏幕实际宽度成正相关
  • visualviewport: 当前显示在屏幕上的页面,即浏览器可视区域的宽度,正常情况下等同于 layoutviewport。如何改变呢,如果当前逻辑分辨率是 375,你使用两个手指放大一倍之后,浏览器里展示的内容只剩下一半。此时新的 visualviewport 187.5,layoutviewport 依旧是 375

参考: