/ devicePixelRatio

devicePixelRatio

本文说的devicePixelRatio指的是window.devicePixelRatio,WebKit浏览器及Opera支持这个属性。

定义

window.devicePixelRatio指的是设备物理像素和设备独立像素(device-independent pixels, dips)的比例 on the device. window.devicePixelRatio = 物理像素 / 设备独立像素(dips)
Dips被用来向media query宽/高、meta视口(viewport)device-width传递设备信息。以Retina和非Retina设备之间的差异为例来说明直观一些。

非Retina iPhone纵向的物理分辨率宽为320px,使用<meta name="viewport" content="width=device-width">可以将布局视口设置为320px, 页面自然地适应屏幕。也就是说,非Retina iPhone的物理像素和设备独立像素都是320,因此<window.devicePixelRatio>等于1。

Retina iPhone物理像素宽度为640,但是网站视口宽度不会变成640px,仍然是320——iPhone的最佳阅读尺寸。因此Retina iPhone的window.devicePixelRatio等于2。

浏览器支持

大多数浏览器都能支持 window.devicePixelRatio 属性,下面是不支持的浏览器列表:
  • IE及Firefox完全不支持(经测试,Firefox 19已经支持,从那个版本开始支持未知;IE 10桌面版仍然不支持
  • Opera桌面版在Retina设备上返回1,实际上应该是2(PPK没有说是哪个版本的Opera,没有Retina Mac暂无法测试)
  • Opera Mobile 10不支持,但12正确支持
  • UC总是返回1,传递给UC的viewport属性很令人困惑
  • 最近的Chrome才支持这一属性,Chrome 19错误返回1,Chrome 22正确返回2
  • MeeGo WebKit (Nokia N9/N950) 有点恶心的问题:应用meta viewport后值会从1变到1.5
喜忧参半,Safari、Android WebKit、Chrome 22+桌面版及Android版、Opera Mobile、BlackBerry WebKit、QQ、Palm WebKit、Dolfin都能正确支持这个属性。

不过,这些浏览器目前多数都运行在<window.devicePixelRatio>为1的设备上,以后在Retina设备上就可能出现问题。

不同设备的devicePixelRatio

PPK创建了一个测试页面,用来显示访问者的devicePixelRatio。目前绝大多数桌面电脑和笔记本的devicePixelRatio都是1,Retina笔记本在Safari、Chrome 22及Opera中返回2,IE和Firefox返回undefined。

iOS

对iOS设备来说,非retina屏幕devicePixelRatio为1,retina屏幕为2。因为虽然实际像素成倍增加,但为了不破坏为320px宽的iPhone精心设计的网页,浏览器仍然将viewport中的device-width识别为320px,即dips仍为320px, 640/320 = 2。

iOS平台相对简单,devicePixelRatio只有1和2这两个值。绝大多数其他平台的设备物理像素等于dips,所以也很简单,devicePixelRatio 为1。

Android

事实上Google Nexus One是最早使用dips的设备,甚至早于iPhone。Galaxy Nexus 和 Galaxy Note 也采用了类似retina的显示技术。
  • Nexus One物理分辨率480x800, 但Android WebKit开发团队认为竖屏模式320px宽度最适合网页浏览,因此dips仍设为320px,devicePixelRatio 为 480/320 = 1.5。在这款手机上,Opera Mobile做了相同的处理, devicePixelRatio 同样是 1.5。 (顺便提一下,BlackBerry Torch 9810 搭载 OS7,物理分辨率同为480,但BlackBerry WebKit团队将devicePixelRatio设为1。实际使用来看,设置成1.5应该好一些,480px宽的页面在Torch上看起来太费劲了。)
  • Galaxy Nexus物理分辨率为720x1200,Android团队将dips宽度提升为360px, devicePixelRatio 720/360 = 2。Chrome、QQ浏览器也做了相同处理。但是Opera有些差异,dips宽仍为,320px,devicePixelRatio of 720/320 = 2.25。
  • Galaxy Note,物理分辨率800x1200,Android WebKit、Chrome、 QQ都为2(即dips宽为400px);Opera为2.25,即dips宽为 356px。

与其他属性的关系

devicePixelRatio、物理分辨率、dips之间仅仅是单纯的数学计算,知道其中两个就可以算出第三个。但是如何获得dips宽度或者物理分辨率宽度呢?

获取dips宽度很简单:页面设置<meta name="viewport" content="width=device-width">,获取document.documentElement.clientWidth,绝大多数浏览器返回布局视口的宽度,等于dips宽度。(兼容列表

如果无法使用上面的方法,就只能用screen.width了。不同浏览器返回的值不同:

  • Retina iOS设备上,screen.width返回dips宽,如retina和非retina iPad竖模式都返回768
  • 在上面的三个Android设备中,screen.width返回物理分辨率宽度,所有浏览器都返回一样的值
这验证了一个理论:Apple增加屏幕像素是为了让显示效果更加精细平滑,而Android设备产商则是为了往屏幕上塞更多东西。这也解释了为什么苹果强调从非retina到retina体验的连续性,而Android只关注分辨率数字上的提高。

其他平台上的浏览器如何呢?由于条件限制,只能在部分设备上测试。Nokia Lumia Windows Phone上的IE9和android一样,screen.width返回物理分辨率,但是不支持devicePixelRatio,无法做更全面的测试。

对于移动客户端上,可以总结为:

  • devicePixelRatio在大多浏览器上都是可靠的。
  • iOS上,devicePixelRatio x screen.width = 物理分辨率。
  • 在 Android 和 Windows Phone设备上, screen.width / devicePixelRatio = dips。

Retina MacBook

Retina MacBook的devicePixelRatio应该为2,但实际情况可能比想象中复杂,因为可以调整分辨率。关键是分辨率改变后,devicePixelRatio 保持不变。

Retina MacBook 是2800x1800物理分辨率为,显示分辨率为1400x900,所以devicePixelRatio为2。但是将分辨率调为1920x1200之后, devicePixelRatio 还是 2。严格来说这是错误的,应该为1.5。但无论如何,Apple将devicePixelRatio标准统一为1和2两个值对开发者还是有利的:监测到2,则提供为retina优化图片;如果为1,提供普通图片。

为Retina设备提供高分辨率图片将加重Web数据传输负担,特别是通过移动网络,但出于商业竞争考虑,很多公司还是会这样做。

内容来源: