Ruby's Louvre

每天学习一点点算法

导航

像素密度的危机

enter image description here

在基于屏幕的设计中,像素一直都是最小的单位。由于它不可分割,因而就成为设计师赖以度量屏幕距离的有形单位。以前总听人说:“一个像素是一个像素是一个像素。”这句话意在帮助不习惯固定屏幕密度的平面设计师理解像素的概念。由于存在这种一致性,Web设计师同样采用像素而不是点或其他单位来构建网站。

现在,随着硬件的发展,像素密度在增长,很难再像以前一样把像素作为一个可靠的单位。浏览器缩放是另一回事,QuirksMode的这篇文章里有介绍。在如今的高分辨率设备上,像素到底指什么呢?为什么分辨率为640px × 960px的iPhone 4在浏览器里声称自己是320px × 480px?事实上,有两种不一样的像素定义:一是指屏幕可以达到的最小单位(硬件像素),二是指视觉上一致的“参照像素”。

硬件像素

我们大都熟悉硬件像素。硬件像素是显示屏上能够显示的最小的点,通常由红、绿、蓝三个子像素构成。从这三个子像素中穿过的光线混合起来,为我们创造了一个像素的颜色。硬件像素与屏幕上的物理元素一一对应,不能拉伸、扭曲,也不能再分。这些特点让硬件像素很像原子——任何设计作品中最基本的单位。

参照像素和分裂原子

像素的概念在发生变化。W3C为所有基于像素的度量定义了一个标准,叫参照像素。于是,所有基于像素的设计不必局限于硬件像素,而是向一个基于视觉参照的单位靠拢。这个参照像素有可能等于硬件像素的两倍。在任何阅读场景下,这种像素都应该看起来一样大。使用参照像素的关键在于把屏幕尺寸作为上下文。同样是参照像素,在手机上就小,在投影中就大。如果你同时拿着手机,又看着投影,那么无论设备的分辨率如何,像素密度是否有差异,像素看起来都应该是一样大的。如果能够得到一致遵行,这个标准将使像素在任何设计作品和任何平台上都保持一致,不管像素密度有多大,也不管观看距离有多远。

参照像素的确很棒,可现在又有了一个不同的定义。Android设备有一个新单位,叫做“密度无关像素”(density independent pixel)简称dip。开发人员可以使用它来区分某个元素占据的可见像素数量。这样,使用px就可以基于硬件像素来显示锐利的图片和图案,使用dip则可以动态调整文本大小或跨设备保持某些部分一致。把一个像素的定义分成两个,对于Android而言很合适。但Web呢?几年内仍然会继续在各种设备中沿用基于像素的设计。在Web开发中也使用这些单位固然好,但如果不彻底改变大家当前对像素的理解,那只能破坏Web。想象一下,如果iPhone 4告诉网站它自己的实际宽度是640px,那么文本就会变成原来的一半大——当然是在没有缩放的情况下。而此时的网站就几乎看不清啦。所有禁用了缩放的移动网站就全都变成了废物。

enter image description here
图1:Galaxy Tab和Kindle Fire中的标准像素大小

我们同样不完全清楚每种设备如何处理像素,这就可能导致问题。比如,最早的Galaxy Tab和Kindle Fire的屏幕尺寸及分辨率都一样,但Tab的像素根据参照像素进行了调整,每个像素是Fire的1.5倍大,Fire沿用的是硬件像素。于是,必须得对所有设备逐一进行测试,毕竟说明书中所提到的都只是硬件像素。看到这两台设备的说明,开发人员会以为屏幕一样大,而且浏览器内核都是WebKit,那么网站呈现就会一样。可惜,事实并非如此。对于任何网站来说,Galaxy Tab是400px × 683px,而Kindle Fire是600px × 1024px。

确定断点,解决问题

没错,像素出问题了。可是,我们能通过媒体查询检测到这种不一致,然后进行相应调整。具体来说,可以使用device-pixel-ratio来检测像素的缩放比例。再辅以检测分辨率,就能够在某种程序上确定设备类型。iPhone 4的device-pixel-ratio值是2,即iPhone 4中的一个像素等于两个硬件像素。很多Android设备的device-pixel-ratio是1.5,因此一个像素等于1.5个硬件像素。目前,使用device-pixel-ratio时还是需要加厂商前缀,但无论如何,有了它就可以检测设备是否缩放像素了。

在确定设备类型时,专有特性是关键,但也要注意不能过分针对某款设备,以防其他设备也存在类似特性。比如最初的Galaxy Tab及类似设备,device-pixel-ratio等于1.5只是条件之一。今天,大多数Android手机的device-pixel-ratio也是1.5,这种冲突会引入其他麻烦。通过查询两个方向的device-width才会知道它比手机大,但不会大到超过将来会出现的其他平板。使用device-width可以知道屏幕分辨率,而widthheight返回的只是视口的宽度和高度。基于设备的这个指标,就可以很好地确定用户使用的设备类型。

@media screen and (device-pixel-ratio: 1.5)
    and (device-width: 683px)
    and (orientation: landscape),
  screen and (device-pixel-ratio: 1.5)
    and (device-width: 400px)
    and (orientation: portrait)

注意,device-pixel-ratio是需要厂商前缀的,因此-webkit--o-是对Webkit和Opera浏览器有效的。

下面我们再检测类似Kindle Fire的设备,它们与Tab的硬件分辨率相同,所以可以使用硬件像素。这种设备很难跟上网本及其他屏幕较大的设备乃至拥有相同分辨率的iPad区分开。使用媒体查询特性orientationmax-device-height可以针对我们想检测的设备。这些设备的高度通常会小于device-height的实际值,因此为了避开1024 x 768的平板,把600像素以下作为条件即可。这样,就可以找到分辨率和大小都一致的同类设备了:

@media screen and (device-pixel-ratio: 1)
    and (device-width: 1024px)
    and (max-device-height: 600px)
    and (orientation: landscape),
  screen and (device-pixel-ratio: 1)
    and (device-width: 600px)
    and (max-device-height: 1024px)
    and (orientation: portrait)

enter image description here
图2:Galaxy Tab和Kindle Fire上正常化的像素

使用em而不是像素不仅仅有利于缩放字形,还能更好地控制站点的缩放。你要做的就是修改html元素的font-size值。要让网站在Kindle Fire中的效果看起来与Galaxy Tab中一样,只要在Kindle Fire的媒体查询中把基准大小乘以3/2 (1.5)即可。如果你想在Galaxy Tab上使用基于硬件的像素,那就在它的媒体查询中将基准大小乘以2/3(.666667)。因为一切都基于em,那么整个站点自然会相对于基准font-size缩放。这个Gist是一个完整的例子。根据上下文修改它,可以改进跨平台的一致性。

要理解多个像素定义需要下一番功夫。像素本来是最基本的单位,而给它赋予视觉上一致的意义导致了理解上的困难。设备厂商在解决这些问题方面也做了很多工作,为我们节省了时间,但各种问题在所难免。无论如何,只要始终关注这个领域,我们一定会有办法发现和解决这些问题。

posted on 2013-01-16 12:04  司徒正美  阅读(3618)  评论(1编辑  收藏  举报