PPI的复杂之处在于若是他所属的上下文环境不一样,意义也会彻底不同。 当咱们在谈论显示设备的PPI时,它代指的屏幕的像素密度;当咱们在谈论和图片相关时,咱们谈论的是打印时的分辨率或者打印机的打印精度。这里咱们主要描述的前一种状况.css
PPI全称为Pixel Per Inch,译为每英寸像素取值,更确切的说法应该是像素密度,也就是衡量单位物理面积内拥有像素值的状况。html
如上图所示,在1英寸单位内面积内拥有的像素越多,密度越大,PPI值就越高。但像素密度的实际意义是什么?它表达的是什么?或高或低对设备显示来讲有什么影响?css3
通常来讲,咱们固然但愿PPI值越高越好,由于更高的PPI意味着在同一实际尺寸的物理屏幕上能容纳更多的像素,可以展示更多的画面细节,也就意味着更平滑的画面。原理以下:web
但你有没有仔细相关Pixel Per Inch中的pixel像素的概念究竟指的是什么样的像素?你可能会反问我像素难道还分不少种不成?我能够很肯定的告诉你,是的。算法
不管是早期的CRT显示器仍是现在的LCD显示器,都是基于点阵的。也就是说经过一些列的小点排列成一个大的矩形,不一样的小点经过显示不一样的颜色来显示成图像。好比下图就是LCD显示器上一个6x6个小点排列成的矩阵:express
注意每个像素(pixel,也能够称之为dot)又是由三个子像素(subpixel)红绿蓝组合而成。当须要显示图片信息时,它的工做原理能够以下图所示:浏览器
上图中的左侧是放大以后咱们能看到的像素,而右侧就是对应像素在显示器上的显示状况了。app
注意上图表明的仅是LCD显示器的物理像素状况,早期的CRT显示器的物理像素一样也是由独立的点组成。可是不存在subpixel的概念,状况以下图所示:ide
上面描述的这些显示器上的像素咱们就称之为物理像素(physical pixel)或者设备像素(device pixel)。函数
做为Web开发者,咱们接触的更多的是用于控制元素样式的样式单位像素。这里的像素咱们称之为CSS像素。
CSS像素有什么特别的地方?咱们能够借用quirksmode中的这个例子:
假设咱们用PC浏览器打开一个页面,浏览器此时的宽度为800px,页面上同时有一个400px宽的块级元素容器。很明显此时块状容器应该占页面的一半。
但若是咱们把页面放大(经过“Ctrl键”加上“+号键”),放大为200%,也就是原来的两倍。此时块状容器则横向占满了整个浏览器。
吊诡的是此时咱们既没有调整浏览器窗口大小,也没有改变块状元素的css宽度,可是它看上去却变大了一倍——这是由于咱们把CSS像素放大为了原来的两倍。
CSS像素与屏幕像素1:1一样大小时:
CSS像素(黑色边框)开始被拉伸,此时1个CSS像素大于1个屏幕像素
也就是说默认状况下一个CSS像素应该是等于一个物理像素的宽度的,可是浏览器的放大操做让一个CSS像素等于了两个设备像素宽度。在后面你会看到更复杂的状况,在高PPI的设备上,CSS像素甚至在默认状态下就至关于多个物理像素的尺寸。
经过上面这个例子我想传递一个很是重要的概念,就是CSS像素历来都只是一个相对值。
回到PPI上来,如今咱们有了两种像素,设备像素和CSS像素。那么PPI中的像素是指哪种?
请记住,PPI中的pixel指的应该是物理像素。
可是在维基百科对PPI的解释中,pixel被解释为一种相似于分辨率下的像素:
The apparent PPI of a monitor depends upon the screen resolution (that is, the number of pixels) and the size of the screen in use; a monitor in 800×600 mode has a lower PPI than does the same monitor in a 1024×768 or 1280×960 mode.
上面这段话是在说,同一尺寸的显示器在800x600分辨与1024x768分辨率下的像素密度明显是不一样的,明显后者单位面积内的像素更多,固然后者的像素密度更高。
这里考虑了另外一种状况,即在同一显示器下由于分辨率调整致使显示器的像素密度不一样。这里的像素虽然是否是在浏览器中显示,但原理也相似于CSS像素,即由多个物理像素组成一个指定分辨率下的像素。
但问题是,这样的比较是没有任何意义的,咱们一般在比较PPI时,必定是在跨设备比较,为了体现设备的技术优点,也必定是拿设备的最优或者极限状况进行比较,这样状况下分辨率下像素是与物理像素一一匹配的。 不能说一台23寸的2k显示器和一台23寸的1080p显示器由于都能调整到1440x960的分辨率,那么他们的PPI就相同了?PPI终究是体现设备某方面性能的参数。
也就是说,当咱们在谈论一台设备的PPI时,它是一个定值,是一个固定的参数。
那么PPI怎么计算呢?没错,就和你想的如出一辙,用屏幕边的物理像素除以物理尺寸便可,以Samsung Galaxy S4为例:
因而可知Galaxy S4的屏幕分辨率为441PPI。
但PPI太高一样也会带来问题,相同的图片素材,在越高的设备上会显示的越小。如下是一个像素在不一样PPI设备上的可见状况,随着PPI的增高可视度愈来愈小:
那么能够预见一种很糟糕的状况是,同一尺寸的屏幕下假设PPI提升了一倍,极可能程序界面缩小了4倍(由于在屏幕尺寸不变的状况下物理像素点面积是原来的1/4)。
以Surface Pro 3为例,它的默认分辨率是2160x1440,也就是说Surface这台设备的屏幕物理像素有2160x1440个点,同时默认分辨率状况下,一个点物理像素点对应于一个分辨率像素。 但由于屏幕只有12寸,像素密度很是高,因而就出现了上面的问题,各个文字和图标被缩的过小了,电脑是彻底不可用的。
解决方法是,Windows默认将全部的文本和素材(实际上就是分辨率像素)都放大了1.5倍(在“屏幕分辨率”-“放大或缩小文本和其余项”中进行了设置),原来是一个物理像素对应一个分辨率下的像素,如今则是1.5个物理像素对应一个分辨率下的像素,也就意味着分辨率下的像素变大了,实际分辨率下降了,已经变成了1440(2160/1.5)x900(1440/1.5)(此时若是你尝试用window.screen.width/window.screen.height去检测返回结果也会是1440x900)。这里留给读者一个问题,
这样和直接将PC的分辨率调整为1440x900有什么区别呢?
但把素材和文字放大就真的一劳永逸了吗?不,甚至还会带来反作用。放大素材对位图来讲是很是危险的一件事。假设一款软件中的素材图片分辨率为32x32,可是为了配合总体界面的拉伸,它也必须被拉伸至原来的1.5倍等于为48x48。你必定有在Photoshop中把图片强制放大为原来几倍的效果的经验。 这样以来,图片素材就变得模糊了。同时由于Window使用的字体为点阵字体而非矢量字体,因此甚至在软件中的字体也会变得模糊。
简单一点来讲,采用这种技术须要将32x32的图片强制拉伸为48x48,多出来的像素如何凭空生成?计算机只有猜想了,经过线性插值算法。因此图片便会出现模
糊。
但位图可能会被拉伸的问题并不是也是绝对的,假设软件须要显示的icon大小为32x32,可是图片素材大小为64x64,那么即便Windows的UI界面拉伸1.5倍,icon大小为48x48,由于原图片足够大,图片仍处于未拉伸的状态。那么也不会模糊。
反过来咱们能够得出结论,为了让在低PPI上和高PPI上图片显示的效果一致,图片素材应该尽量的高清。
Apple的Retina技术使用的也是上面相同的方案。以15.4寸的Retina版Macbook Pro为例。显示屏的物理像素点实际上有2880x1880,但其实默认的最优分辨率只有1440x900,恰好是物理像素的一半。也就是说操做系统默认使用了4:1的缩放。但这一样也有可能会出现使用软件虚化的问题。
我不清楚Mac软件开发中是如何解决这个问题的,但能够参考iPhone开发中的解决方案,苹果鼓励开发者准备两份素材,普通和高清素材。而且经过素材文件名后缀来区分,好比普通素材名称为apple.png,那么高清素材名称就为apple@2x.png。天然高清素材是普通素材面积的四倍,系统会优先使用高清素材,但自动缩小到普通素材的大小,这样也就不存在图片拉伸的问题了。
从上面咱们得知,由于高像素密度设备下的UI会采用必定比例的缩放,因此CSS像素也会面临一样的问题:
正如上图所示,左侧普通屏幕中,2x2的CSS像素真的只须要2x2的物理像素。可是右侧高清屏中,2x2的CSS像素却须要4x4的物理像素。
我刚刚有说道解决高清PPI下图片渲染问题的方法之一就是使用更高清的图片素材。但问题是须要有多高清?
在Retina显示屏上,根据上一节描述的原理,当咱们须要渲染一张32x32的图片,咱们实际上须要准备64x64的素材。由于苹果默认把全部素材都进行了两倍的放大。但若是有一台更高清的设备,进行了三倍或者四倍或者更高的倍数,咱们岂不是须要准备更多尺寸或者体积更大的文件素材?在Web开发中咱们正在面临这样的问题。
首先咱们要学会如何表达和判断这样一种CSS像素和物理像素不平等。
DevicePixelRatio定义以下:
window.devicePixelRatio = physical pixels / dips
分母dips全称为device-independent pixels,译为与设备无关像素。 更通俗的说应为与物理像素无关的CSS像素。
以iPhone4为例,在垂直状态下手机的物理像素宽度有640px,可是由于2:1缩放的关系,此时的dip,设备报告给咱们的宽度只是320px。 此时的DevicePixelRatio就为 640 / 320 = 2;
devicePixelRatio说白了就是手机的物理像素与实际使用像素的缩放比。
注意devicePixelRatio并不是是一个默认值。在默认状况下CSS像素是由手机默认的缩放决定的。但同时由于浏览器页面也能够被人为的进行缩放。好比iPhon4中默认的分辨率宽度为320px。浏览网页时咱们彻底能够自行放大两倍为160px。这样以来window.devicePixelRatio就变味了 640 / 160 = 4。
与divicePixelRatio几乎等价的一个概念时dppx:dots per pixel。 表示单个CSS像素占用的物理像素个数。仔细想一想,这与devicePixelRatio实际上是一个意思, iPhone4的dppx为2,不就是与devicePixelRatio恰好相等吗。devicePixelRatio是从宏观上来讲这件事。把总体宽度作运算。dppx是从微观角度上说这件事,考虑的是单个像素之间的比较。
请记住,当咱们在谈论一台显示设备的像素密度时,dpi与ppi是等价的。dots per pixel中的dots就是代指物理像素。
可是若是你在mediaquery中使用dpi是就要注意了,Chrome会在控制台中提示你使用dppx而非dpi:
Consider using ‘dppx’ units instead of ‘dpi’, as in CSS ‘dpi’ means dots-per-CSS-inch, not dots-per-physical-inch, so does not correspond to the actual ‘dpi’ of a screen. In media query expression: only screen and (-webkit-min-device-pixel-ratio: 2), not all, not all, only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx)
上面这段话的意思是,在mediaquery中inch表示的CSS定义中的一英寸,而非生活中物理定义的一英寸。
实话实说我并无找到关于CSS中一英寸的定义,可是在W3C关于Resolution的定义中,咱们能够看到看到它所定义的1dppx是与96dpi具备一样含义的。那么2dppx也就是192dpi了咯。这固然脱离了咱们传统上的dpi了,Surface Pro 3的dpi(也就是ppi)可以达到216ppi,可是在默认未放大界面时的dppx仍然能够是1。
我的人为这是一个很鸡肋的概念,但也正是由于了解的人太少了,仍是须要值得一提。
假设咱们规定了CSS像素值须要与设备像素大小相等,但当随着手持设备距离人的远近不一样,设备像素密度的不一样,都会致使咱们看见的设备上的CSS像素的可见大小发生变化(相似于巨大的月亮由于离地球遥远在人眼看来也不过像硬币同样大小)。为了保证CSS像素在不一样设备和不一样距离上观测到的大小保持一致保持连贯性。W3C定义了一个CSS相对像素(CSS reference pixel)的概念
It is recommended that the reference pixel be the visual angle of one pixel on a device with a pixel density of 96dpi and a distance from the reader of an arm’s length. For a nominal arm’s length of 28 inches, the visual angle is therefore about 0.0213 degrees.
W3C规定,把人眼可以辨别到的,距离本身一个手臂长度(约28英寸),像素密度为96dpi设备上的一个物理像素设为参考像素。因此咱们能够算出眼睛看到参考像素的视野角度为0.0213度:
有了这一系列参照,经过三角函数关系,咱们能够算出一样一台设备在不一样距离下CSS像素理想的大小。 当远离观察者时像素应该增大,当靠近观察者时像素应该减少:
这么作的优点在于不管设备距离观察者距离是多少,也不管设备的像素密度和物理像素大小是多少,观察者看到的CSS像素是一致的,保证了用户体验的一致性:
但问题是如何来实践这一标准呢?
<meta name="viewport">
咱们有了物理像素,CSS像素——那么问题来了,当你再手机上使用浏览器打开网页时,网页应该按照哪种宽度进行渲染?
首先咱们须要了解一个概念:viewport,我常见到的中文译为视口,但我的以为这个翻译有一些晦涩。 Viewport是用于限制Html元素——“限制”这两个字不是那么好理解。quirksmode上有一篇文章谈到这个概念时打了一个很是形象的比方:
假设body标签内有一个块状元素宽度为10%: div {width:10%;}
,咱们知道当咱们缩放浏览器时这个块状元素的宽度也会跟着变化。 这是由于它的宽度占它父元素的10%。那么它的父元素,也就是body元素的宽度是由谁决定的呢?
咱们知道一个块状元素默认宽度为它父元素的100%,也就是body元素的宽度与包裹它的html元素宽度相同。那么问题又变成了html元素的宽度是由谁决定的?
答案是浏览器窗口。如今咱们能够概括起来,html元素是被浏览器限制而且包裹起来的。html的宽度就是浏览器的宽度。
但事实上,html元素宽度是占据viewport的100%,而在桌面浏览器中,viewport与浏览器窗口大小恰好相等(注意,这仅仅是在桌面浏览器上)。
OK,在因而咱们获得了一个结论,html宽度是由viewport决定的,可是 在桌面浏览器中,viewport大小与浏览器窗口大小相等。
但这一套规则在手机则是没法被执行的。大部分手机的屏幕分辨率目测只有400px,若是页面上真的有某一个页面元素仅占10%,也就是40px的话,肉眼几乎是没法分辨的。实际状况应该会更糟糕,iPhone4的Safari默认是以980px来渲染网页的。若是你在Chrome以桌面版的方式访问stackoverflow,那么结果会是这样的:
体验很是糟糕吧,全部的连接几乎都没法准确点击。那么如何解决这个问题?
第一个办法,放大页面。
咱们会很习惯的用手势去放大页面。可是要注意咱们这里作的仅仅是放大页面,改变的是页面的缩放(scale),效果与PC上浏览器的相似。可是没有改变页面的布局,此时用于渲染页面布局的layout仍然是980px
第二个办法是,改变布局。
好比下面一个页面上有一张320px宽的图片,若是咱们以默认的980px去渲染的话,它会显得过于窄小:
但若是咱们能够将渲染它的布局设为320px的话,看上去就会好不少了,同时此时咱们也未对页面
进行缩放:
固然你也能够结合上一步,同时对页面进行缩放:
不只仅是放大,即便是在320px的像素下,咱们也能够进行缩小:
回归到技术上,以上这些均可以经过viewport标签来解决,好比说上面的需求,把布局设定为320px,同时进行1.5倍的缩放:
<meta name="viewport" content="width=320, initial-scale=1.5">
所见即所得,须要设置的属性在content以逗号分割开来,表示页面布局宽度,表明页面初始状态的缩放比例,若是你不想让用户进行缩放,还能够添加字段来保证用户没法进行缩放。widthinitial-scaleuser-scalable=no
更重要的是,咱们还能够无需指定特定宽度,经过设置width=device-width
,指定布局宽度等于手机分辨率宽度(可是咱们不用关心手机分辨宽度是什么)来更好的利用响应式设计。注意这里的device-width
表示手机的分辨率宽度,而并不是手机物理像素宽度。iPhone4在垂直状态下物理像素宽度为640,这里的device-width
表明的则应该是它的dip像素320px。
给viewport标签添加width=device-width
适用于这样一种状况:你在为移动设备开发的响应式网页时,你会面临多重分辨率状况,可是你又没有必要使用到重量级的mediaquery,同时也为了不手机浏览器使用桌面分辨率宽度去渲染页面, 同时这还能兼容在手机横握或者竖握的状况。 这样让你的响应式页面可以适用大多数的移动设备。
写到这里咱们能够作一个总结,viewport标签的做用是什么?它可以让你撇开设备的干扰,告诉设备你想用什么样的宽度渲染网页。让它听命于你,而不是你听命于他。
上面咱们谈到viewport有个半专业的名词成为layout viewport,虽然它是一个非官方的词汇,可是很是多的文章都引用了这个概念。layout viewport专用于页面渲染的控制。还有一种viewport称之为visual viewport,能够译为可视窗口。两种viewport的区分以下:
由此能够看出visual viewport就比如是浏览网页的一个窗口,网页正是这窗外的景色。固然咱们还会碰见layout viewport与visual viewport大小相等的状况。好比像下面这样:
这也就是我上面描述的width=device-width
了。
在文章的开头我有说PPI在不一样上下文中的含义是不一样的,若是你仍有好奇心,能够继续往下阅读。接下来咱们谈谈Web之外的PPI含义。
首先咱们要重申上面的结论,就谈论显示设备的像素密度而已,PPI和DPI和同样的概念,而且其中的像素pixel和点dots代指的都是物理像素。
若是你去查看一张JPG图片的属性时,你会发现有横向或者纵向的以dpi为单位的属性或者在Phototshop新建一份文档时,要填写一个以ppi为单位的属性值:
这里也存在被混用和混淆的地方。其实他们都表示打印时的分辨率值。意为在打印时每英寸上的像素(也就是跟接近PPI,但咱们更经常使用DPI)。这里的英寸固然再也不是屏幕像素了,而是纸张尺寸了。
PPI或者DPI对于图片来讲意味着什么?准确来讲什么都不意味着。 一张图片只是存在相机或者硬盘里的数据文件而已,你能告诉我它有多少英寸长或者多少英寸宽吗?只有当它被打印出来的时候才会涉及到打印媒介的尺寸,DPI才有意义。 若是你想让图片更丰富,惟一的办法是增长图片的像素,提高你的拍摄技巧。
固然在纸张上是没有像素的概念。但咱们能够去抽象的去想象它。假设有一张300x300像素的图片。打印分辨率的为30DPI,那么最后打印出来尺寸为10x10英寸。假如打印时的DPI值为300DPI,那么打印出来的尺寸则为1x1英寸。因此咱们能够把DPI当作调节打印尺寸大小的手段。
那么DPI值越高,图片就越小就越清晰?固然也并不是如此。若是你距离60厘米去观看一张194DPI打印出来的图片。你会无法区分它究竟是194DPI仍是300DPI。由于人眼的分辨率是有限的。这对显示设备一样通用的。iPhon4的像素密度有326DPI,而New iPad的像素密度只有264DPI,New iPad的显示效果会更差吗?参考大多数人使用的距离和方式,其实眼睛获得的效果实际上是无太大差别的。这也是为何大型显示器或者户外广告DPI都不会很高,由于咱们观看他们的时候距离很远,效果并不是太差。
最后咱们能够来看另外一个场景的DPI:描述打印机的打印分辨率:
当一张显示器上的图片打印在图片上的时候,像素这个概念实际上是咱们想象出来的,更加实际的概念时是印刷设备的每个“点”:
当你尝试去用放大镜去查看彩色印刷物品上的图片时,从小到大你看到的结果应该是这样的:
为何会这样?简而言之,印刷的原理是经过半色调(halftone)技术,经过控制CMYK四种颜色点印刷时的每个印刷点的大小,角度,间隙来模拟出一种颜色的感受:
好比当你以600DPI打印一张150PPI的图片时,每个像素应该包含16个点(600dots / 150pixels = 4)。
从上面咱们已经知道PPI可以决定印刷品物理尺寸的大小,打印机的DPI参数更是能进一步决定印刷体的好坏。咱们用于都在追求更高的DPI和PPI。
150dpi一般已是被认为算的上是高质量的打印分辨率了。新闻报纸使用的分辨率一般是85dpi。户外的广告牌一般使用的是45dpi。可是由于距离的关系你不会以为他们的印刷质量太差。
这篇文章我把移动开发中可能会涉及到的概念都作了一些涉及。在下篇中我将运用到这些概念,而且总结在移动设备上的图片加载方案。