设备像素比(devicePixelRatio,dpr)
定义
window.devicePixelRatio是设备物理像素和设备独立像素(device-independent pixels,dips)之间的比率。window.devicePixelRatio = 物理像素/ 设备独立像素
- 设备物理像素:
是一个物理概念,比如设备的分辨率,Phone 5的分辨率640 x 1136px。 - 设备独立像素dips :
是一个抽象像素,用于向CSS中的宽度、高度、媒体查询和meta 的viewport 中的device-width提供信息。通过观察retina和非retina设备之间的区别,可以最好地解释它们。 - CSS像素:
是Web编程的概念,指的是CSS中使用的逻辑像素。在CSS规范中,长度单位可以分为两类,绝对(absolute)单位以及相对(relative)单位。px是一个相对单位,相对的是设备物理像素。
比如iPhone 5使用的是Retina屏幕,使用2px x 2px的设备物理像素,代表 1px x 1px 的 CSS像素,所以设备物理像素为640 x 1136px,而CSS逻辑像素数为320 x 568px。
- 每英寸像素(pixel per inch,ppi):
表示每英寸所拥有的像素(pixel)数目,数值越高,代表显示屏能够以越高的密度显示图像。ppi的计算方式可以参考维基百科每英寸像素。
以上计算出ppi是为了得到密度分界,获得默认缩放比例,即设备像素比。由上图可知,ppi在120-160之间的手机被归为低密度手机,160-240被归为中密度,240-320被归为高密度,320以上被归为超高密度(Apple给了它一个高大上的名字——Retina)。
获得设备像素比后,便可得知设备物理像素与CSS像素之间的比例。当这个比率为1:1时,使用1个设备物理像素显示1个CSS像素。当这个比率为2:1时,使用4个设备物理像素显示1个CSS像素,当这个比率为3:1时,使用9(3*3)个设备物理像素显示1个CSS像素。
关于设计师和前端工程师之间如何协同:一般由设计师按照设备像素(device pixel)为单位制作设计稿。前端工程师,参照相关的设备像素比(device pixel ratio),进行换算以及编码。
所有非retina屏幕的iPhone在纵向模式下有320个物理像素的宽度(320px)。当你使用<meta name="viewport" content="width=device-width">
时,它将布局视区的宽度设置为320px,以便页面自然地适应屏幕。
因此,在非retina屏幕的iPhone上有320个物理像素和320个dips。因此,window.devicePixelRatio
等于1。
retina屏幕的iPhone在纵向模式下有640个物理像素的宽度(640px)。不过,使用meta标签设置viewport的网站不应该变成640px宽,而是保持320px,这是iPhone的最佳阅读尺寸。
因此,即使物理像素的数量是640,dips的数量仍然是320。window.devicePixelRatio
现在等于2。
浏览器支持
大多数浏览器都正确实现了window.devicePixelRatio
。该属性包含物理像素和dips之间的比率,即使一些值起初看起来很奇怪,但实际上它们是有意义的。
给一个没有正确实现window.devicePixelRatio
的浏览器列表会更有效。他们是:
-
IE和Firefox根本不支持这个属性。我假设下一个版本将实现它。
-
retina设备的Opera桌面浏览器
window.devicePixelRatio
的值是1,而它应该是2。我想下一个版本会解决这个问题。 -
Opera Mobile 10不支持它,但12正确实现了这个属性。
-
UC总是给出1,但当涉及到viewport属性时,UC非常困惑。
-
Chrome最近才在retina设备上实现了这个属性。Chrome19错误地返回1,Chrome22正确地返回2。
-
MeeGo WebKit (诺基亚N9/N950)做了一些可怕的事情:当应用meta viewport时,它会将值从1更改为1.5。
这真是坏消息。好消息是,Safari、Android Webkit、Chrome 22+和Android、Opera Mobile、BlackBerry Webkit、QQ、Palm Webkit和Dolfin正确实现了该属性。
两个注意事项:
MeeGo WebKit在应用meta viewport时更改值的想法是大错特错的。首先,在应用meta viewport时,像素比实际上没有改变:物理像素的数量和dips也没变,因此它们的比例也保持不变。
其次,有些浏览器习惯于在应用meta viewport时更改所有类型的内容(三星Dolfin是一个臭名昭著的例子),这一点也没有任何意义。应用meta viewport时唯一改变的是布局视区的尺寸。如果一个浏览器改变了其他的东西,那就完全是错误的。
有关devicePixelRatio的详细信息
这一节将给出一些例子,并考虑到了screen.width。
请注意,在大多数台式机和笔记本电脑上,devicePixelRatio仍然是1。Retina 笔记本电脑在Safari和Chrome22上显示2,在Chrome21(?)和Opera显示1,在IE和Firefox中未定义。(顺便说一下,2值并不总是正确的。见下文。)
iOS
非Retina 屏幕的iOS设备devicePixelRatio将显示1,而Retina 设备将显示2。这是因为在Retina 设备上物理像素的实际数量增加了一倍,但浏览器却假装没有,以免打乱人们为iPhone精心设计的320px宽的布局。毕竟,具有device-width的meta viewport的站点不应该突然变为640px宽。因此,设备独立像素(dips)宽度保持在320px,640/320=2。
在iOS上,设备像素比情况相对简单:只有值1和2。在大多数其他平台上,情况也很简单,因为实际物理像素计数等于dips计数,这使得设备像素比为1。
Android
主要的难题来自于Android,或者更确切地说,来自于许多具有Retina显示屏的现代设备,这些设备其像素明显多于320px,其中大部分运行的是Android。
事实上,据作者所知,谷歌的Nexus One是第一款使用dips的设备,甚至在iPhone之前。同时,Galaxy Nexus和Galaxy Note也都有Retina显示屏。仔细观察这三种设备是有指导意义的。
Nexus One的物理分辨率为480x800,但Android WebKit团队认为,以纵向模式查看的网页的最佳宽度仍然是320px。因此,dips保持320像素宽,设备像素比变成480/320=1.5。
在同一部手机上,Opera Mobile的dips也是320px宽,设备像素比也是1.5。
(顺便说一句,带OS7的BlackBerry Torch 9810也有480个物理像素,BlackBerry WebKit团队决定使用设备像素比为1。回想起来,如果他们将设备像素比设置为1.5,可能会更好,480px宽的网站在Torch上显示有点难以阅读。)
Galaxy Nexus的物理分辨率上升到了720x1200。Android团队也决定将dips抽象层的宽度提高到360像素。这使得设备像素比为720/360=2。Chrome团队、腾讯的QQ浏览器也做出了同样的决定。
然而,Opera不同意,他们决定坚持使用320px的dips宽度。这就产生了720/320=2.25的设备像素比。
最后,Galaxy Note的物理分辨率为800x1200。在这里,所有的浏览器都决定与Galaxy Nexus保持相同的比率:对于设备像素比,Android Webkit、Chrome和QQ坚持使用2(这意味着400px的dips宽),而Opera坚持使用2.25,达到略为奇怪的356px的dips宽。
说到这里,我们发现,各种浏览器基本上都在玩自己的游戏。
devicePixelRatio与其他属性的关系
不管怎样。除了一些例外情况,设备像素比在浏览器中工作相当一致(有关例外情况,请参阅之前的报告)。设备像素比、物理像素和dips之间的关系完全是数学关系,知道其中两个,就可以计算第三个。
但是我们如何找到dips宽度或者物理像素宽度呢?
找到dips宽度很容易:给你的HTML页面增加一个<meta name=“viewport” content=“width=device width”>
,然后读取document.documentElement.clientWidth
,大多数浏览器会给你布局视区的宽度,现在等于dips宽度。(这里是必要的兼容性表。)
但是,如果你不能使用这个计算方法,事情会变得更复杂。我们不得不使用screen.width
给出的值。但是这些值意味着什么呢?
如果你根据浏览器思考他们的意思,恭喜你!你开始理解移动世界了。
-
在iOS的Retina设备上,screen.width以dips为单位给出宽度。所以无论是Retina还是非Retina屏幕的iPad纵向模式下都会报告768。
-
在三种Android设备上,分别为480、720和800,screen.width以物理像素表示宽度。设备上的所有浏览器都使用相同的值。(想象一下,如果同一设备上的某些浏览器使用了dips,而其他浏览器使用的是物理像素!)
Vasilis 有一个很好的理论:苹果增加设备的物理像素是因为它想让显示器更清晰、更平滑,而安卓供应商增加设备的物理像素是为了在屏幕上塞进更多的东西。这是观察这些差异的一种方式:它解释了为什么苹果强调从非Retina到Retina的连续性,而安卓则专注于原始像素计数。
那么其他OSs上的其他浏览器怎么看呢?在这里,我只能使用那些与物理像素不同的dips的浏览器,而且这些浏览器不多。我可以从诺基亚Lumia Windows手机上的IE9中获得清晰的阅读,它与Android系统一致,并以screen.width
给出物理像素值。但是它不支持devicePixelRatio,所以不能完全测试它。
所以对于移动设备的结论是:
-
devicePixelRatio 在大多数浏览器上是最可靠的。
-
在iOS设备上,将devicePixelRatio 乘以screen.width以获得物理像素值。
-
在Android和Windows Phone设备上,用screen.width除以devicePixelRatio ,得到dips值。
参考文章:
devicePixelRatio
More about devicePixelRatio
A tale of two viewports — part two