最近在给WebView
前端传递标题栏高度的时候,传递的是实际像素Pixel
,结果前端直接设置这个数值的时候,发现太高了。搜索了一下,发现前端的CSS
样式设置的像素值是逻辑像素,这个逻辑像素跟实际像素是不同的,对于Android
来说,就是设备的dp
数值。
参考文章如下:
前情提要:设计师给的设计稿是1242分辨率的(iPhone6p),标注的字体大小是54px,前端工程师写的H5页面是18px,效果正常且能自适应iPhone6。来调查一下 为什么是标注数值除以3?为什么自动适应iPhone6?css里的px和Android的dp有怎样的关系?
在进行具体的分析之前,首先得知道下面这些关键性基本概念(术语)。
物理像素(physical pixel)
一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。
设备独立像素(density-independent pixel)
设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素),然后由相关系统转换为物理像素。
所以说,物理像素和设备独立像素之间存在着一定的对应关系,这就是接下来要说的设备像素比
。
设备像素比(device pixel ratio)
设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系,它的值可以按如下的公式的得到:
1 |
设备像素比 = 物理像素 / 设备独立像素 // 在某一方向上,x方向或者y方向 |
在javascript中,可以通过window.devicePixelRatio
获取到当前设备的dpr。
在css中,可以通过-webkit-device-pixel-ratio
,-webkit-min-device-pixel-ratio
和 -webkit-max-device-pixel-ratio
进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)。
iPhone6的物理像素是750 x 1334
,设备像素比(devicePixelRatio)是2
,设备独立像素是375 x 667 (750/2 x 1334/2)
iPhone6p的物理像素是1080 x 1920
,但logic pixel是1242 x 2208
, 设备像素比(devicePixelRatio)是3
,设备独立像素是414 x 736 (1242/3 x 2208/3)
css里面有
物理像素
和逻辑像素
的概念,在这里,逻辑像素
可以理解为设备独立像素
其实,logic point
更适合翻译成逻辑点
。无论是逻辑像素还是逻辑点,只需要理解一个逻辑点(逻辑像素)需要一个或一个以上的物理像素来展示就可以了。
那么,为什么iPhone6p是这样奇葩的逻辑点呢?
- 如果逻辑点分辨率用 360x640, 360x640@3x 正好是 1080x1920。但是逻辑pt分辨率 360x640 就会比 iPhone 6的 375x667 还低,也就是说相同字号的情况下,iPhone 6如果一行显示了25个字,而 iPhone 6 Plus按这个逻辑pt方案,一行就会只能显示24 个字了。
- 如果逻辑点分辨率用 540x960,540x960@2x 正好是 1080x1920。但是iOS UI 元素尺寸在屏幕上的实际物理面积一下子就变小了,比如标签栏或导航栏按钮的物理高度只有原来的 81.5% ,点击面积就只有iPhone 6 的0.815*0.815=66.4%,用户点击就困难了。
- 如果物理分辨率做到1242x2208就减少了一个从1242压缩到1080的过程,但是1242的物理分辨率是在1080p和2k屏之前的尺寸,功耗和成本都会提升,而且这样非1440的2k分辨率的屏幕采购也是问题。
至于为什么一定是 414x736,有人估计应该是在 5.5inch 和 ppi=461 这两个前提限定的情况下,按这个 414x736 pt 分辨率,屏幕上 UI 元素操作物理大小最接近 iPhone 6上的表现。
Android世界中更加复杂,这里列举了几款手机的基本数据
Nexus 4 | Nexus 6 | Nexus 6p | LG L24 | Mi 4c | |
---|---|---|---|---|---|
物理像素 | 768 x 1280 | 1440 x 2560 | 1440 x 2560 | 1440 x 2560 | 1080 x 1920 |
设备像素比(dpr) | 2 | 3.5 | 3.3 | 4 | 3 |
设备独立像素(dip/dp) | 384 x 640 | 412 x 732 | 435 x 773 | 360 x 640 | 360 x 640 |
Android提供了获取density
的方法:
1 |
float density = context.getResources().getDisplayMetrics().density; |
density
的官方定义是The logical density of the display
,翻译过来是屏幕的逻辑密度
,其实就是之前提到的设备像素比(dpr)
。
在浏览器中,获取设备像素比就比较简单:
1 |
window.devicePixelRatio |
比如,我写了一个网页,用手机浏览器打开:
1 |
<button onclick="alert('window.devicePixelRatio='+window.devicePixelRatio);">show devicePixelRatio</button> |
结果显示与Android的density
的结果是一致的。
注:<meta name="viewport" content="width=device-width, initial-scale=1">
By specifying width=”device-width”, you are asking the browser to apply a scaling factor to its screen pixels. One css pixel occupies one or more screen pixels. How many more? This value is called the css pixel ratio.
回顾一下
同一台设备,它的设备像素比(dpr)是确定的,无论通过Android api 获取还是浏览器 js/css 获取。
The css px is actually Device Independent Pixel(dip), and it is a common pattern to use px as dp in css.
css中的px具有与Android中的dp等同的效果