在安卓Chrome中获取屏幕的物理尺寸、dpi和像素密度

99

问题

在Chrome的Android版本中,有没有一种安全的方法可以获取实际正确的屏幕物理尺寸?如果需要,旧版本的Chrome和Android可以不考虑。

先前研究

关于从javascript(或css)内部获取设备的实际物理屏幕尺寸,stackoverflow上有许多死胡同的问题。似乎在HTML API标准化和实际浏览器实现之间没有一致性,更不用说浏览器实现依赖于操作系统API,而后者又依赖于提供正确信息的硬件了。

之前的一些答案是过时的(例如 2011 年左右),他们假定当时存在某种卓越的像素密度,因此毫无用处。其他的则与 WebKit 相关,而 Chrome blink 可能已经在 Chrome 中取代了 WebKit。

我想通过将事情限制在仅针对Chrome的Android版本上来探索一个简单的解决方案。

注意事项

这完全是关于浏览器内部的javascript(或css)解决方案,而非本地应用程序的解决方案。


22
这完全是错的。我的用户界面需要知道按钮在用户看来应该有多大。你可能想得太多了,像一个开发者一样思考代码 ;) - matanster
12
例如,按钮的大小不应该是视口的百分比,而应足够大,以便能够轻松点击。我不确定这对于高质量设计有何意义。 - matanster
17
@matt 绝对正确。在一个“粗手指”(fat-finger)的世界里,Web UX/UI 最重要的方面之一是确保按钮既适合用手指--也就是说,在触屏设备上操作--又适当地大小以适应从屏幕到眼睛的视距。移动设备的新领域使问题更加复杂,因此物理屏幕尺寸检测变得更为重要。 - Jason
8
我完全同意你的看法,@matt。我不明白为什么Mozilla和Google不能给我们一个类似于window.screenDensity的JavaScript属性,该属性包含设备每英寸的物理像素数,你和我(matt)可以从中获取信息。window.screenHeightwindow.screenWidth以物理毫米为单位也很好。 - trusktr
7
@Kinlan 物理屏幕尺寸通常很重要。这就是为什么原生开发目前比Web开发更强大的原因。在本机环境中,例如我可以在所有现代设备上创建一个真实世界中1英寸宽的按钮。据我所知,在Web环境中目前还无法实现这一点。我有遗漏什么吗? - trusktr
显示剩余10条评论
14个回答

135
你无法真正获得实际的物理尺寸或实际DPI,即使你可以,也无法做任何事情。
这是一个相当长且复杂的故事,请原谅。
网络和所有浏览器将1px定义为称为CSS像素的单位。 CSS像素不是真正的像素,而是被认为是基于设备的视角的1/96英寸的单位。 这被指定为参考像素

参考像素是具有96dpi像素密度和读者距离为手臂长度的设备上一个像素的视觉角度。对于标称手臂长度28英寸,因此视觉角度约为0.0213度。在手臂长度处阅读,1px大约对应于0.26毫米(1/96英寸)。

在0.26毫米的空间中,我们可能有非常多的实际设备像素。
浏览器这样做主要是出于传统原因 - 大多数显示器在Web诞生时的分辨率为96dpi - 但也是为了保持一致性,在“旧时代”,800x600分辨率下15英寸屏幕上的22px按钮将比1600x1200分辨率下15英寸显示器上的22px按钮大两倍。在这种情况下,屏幕的DPI实际上是2倍(水平分辨率加倍,但在相同的物理空间内)。这对于Web和应用程序来说是一个糟糕的情况,所以大多数操作系统设计了许多方法将像素值抽象成设备无关单位(Android上的DIPS,iOS上的PT以及Web上的CSS像素)。

iPhone Safari浏览器是第一个(据我所知)引入视口概念的浏览器。这是为了使完整的桌面样式应用程序能够在小屏幕上呈现而创建的。视口被定义为960像素宽。这本质上将页面缩小了3倍(iPhone最初为320像素),因此1个CSS像素等于1/3个物理像素。当您定义视口时,可以使该设备与163dpi匹配,使1个CSS像素等于1个真实像素。

使用视口,其中宽度为“设备宽度”,可以使您无需针对每个设备设置视口宽度以达到最佳CSS像素大小,浏览器会自动完成。
随着双倍DPI设备的引入,手机制造商不希望移动页面看起来缩小了50%,因此他们引入了一个称为devicePixelRatio的概念(我认为首先是在移动webkit上),这使他们保持1个CSS像素大约相当于1/96英寸,但让您了解您的资产(例如图像)可能需要两倍的尺寸。如果您查看iPhone系列的所有设备,则其所有设备都会在CSS像素为320px的屏幕上显示宽度,即使我们知道这不是真实的。
因此,如果您将按钮设置为22px的CSS空间,则在物理屏幕上的表示形式为22 * device pixel ratio。实际上,我说这话,它并不完全准确,因为设备像素比也从未精确,手机制造商将其设置为漂亮的数字,如2.0、3.0,而不是2.1329857289918...。
总之,CSS像素是与设备无关的,让我们不必担心屏幕的物理尺寸和显示密度等问题。
这个故事的寓意是:不要担心理解屏幕的物理像素大小。你并不需要它。50px在所有移动设备上看起来应该大致相同,可能会有一些差异,但CSS像素是我们构建一致文档和UI的设备无关方法。
资源:

22
你说“你不能对它们做任何事情。”我不同意。有了这些信息,我就可以设置一个始终为16点(现实世界英寸的16/72)高度的字体。这是非常宝贵的,也是本地开发继续比Web开发更强大的原因之一。 - trusktr
9
实际上,以像素为单位的真实屏幕尺寸可以用于渲染具有适当分辨率的背景图像,这是完全合理的用法。 - WhyNotHugo
3
"50像素在所有移动设备上应该看起来大致相同。请使用1200x1920的4英寸手机和1000x600的10英寸平板电脑并排放置以证明此说法。" - iloveregex
6
我也不同意“你无法对它们做任何事情”的观点:你可以可靠地检测设备是手机还是平板电脑,并假设用户能否轻松地用手指在屏幕上进行操作。 - Brian Cannard
3
非常详细的回答,但我不理解为什么要说屏幕的物理尺寸无法改变。我们可以利用这个信息做很多事情。例如知道(或设置)屏幕上某物的物理尺寸,以便像实际打印一样显示。增强现实的应用也很明显。希望回答能围绕问题展开,而不是决定人们想要做什么。 - Tom
显示剩余15条评论

10

在 Web 应用程序中,没有获取物理像素或显示器的物理尺寸的方法(没有相应的 Web API)。


根据Matanster的答案,他观察了 SVG 属性,如screenPixelToMillimeterX,我进行了测试以查看它们是否有效:

(编辑:这些属性已从规范中删除(或从未存在),浏览器可能不再具有(或从未具有)这些属性,使我们进一步远离了实际的物理显示尺寸)。

// on Macbook Pro Retina (2880x1800, 15.4"), is the calculated diagonal size
// approximately 15.4? Let's see...

var svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var screenWidthMillimeters = svgEl.screenPixelToMillimeterX * 2880;
var screenHeightMillimeters = svgEl.screenPixelToMillimeterY * 1800;
var screenDiagonalMillimeters = Math.sqrt(Math.pow(screenWidthMillimeters, 2) + Math.pow(screenHeightMillimeters, 2)); // pythagorean theorem
var screenDiagonalInches = (screenDiagonalMillimeters / 10 / 2.54); // (mm / 10mm/cm) / 2.54cm/in = in

console.log("The calculated diagonal of the screen is "+screenDiagonalInches+" inches. \nIs that close to the actual 15.4\"?");

这是输出结果:

The calculated diagonal of the screen is 35.37742738560738 inches. 
Is that close to the actual value of 15.4?

不行。

目前似乎还没有办法在Web浏览器中获取真实的物理值。


1
我不确定您所指的答案(我没有看到“Matt”),但是由于'svgEl.screenPixelToMillimeterX'显然未定义,我得到了NaN。 - Michael
我得到了和你一样的结果,15.4英寸,但我的屏幕实际上是21英寸,这太不同了。 - Toan NC
@Michael他改名为“matanster”并删除了他的答案(https://stackoverflow.com/a/24780546/454780)。 - trusktr
除非有我不知道的新Web API,否则无法获取物理像素的尺寸,我们只能获取CSS像素的尺寸,需要注意的是CSS“in”单位(以及其他“物理”单位)不准确(它们相对于CSS像素而不是物理像素,并且“1in”因此会因设备而异)。当我在Linux中使用Chrome访问时,thisDevice对象似乎为空。我真的希望我们有API来获取物理屏幕尺寸。 - trusktr
@TJS101 我的设备详情:System 76 Oryx Pro(64GB RAM,带有Nvidia 16GB选项)。你的数学可能是尽可能正确的,但我们无法使用当前的API获取物理像素尺寸。 - trusktr
显示剩余15条评论

5
你可以使用WURFL获取该信息: 设备显示属性 这些属性被称为:
resolution_(width|height)

physical_display_(width|height)

长版:

实现这一目标的最佳且最可靠的策略是将浏览器发送的用户代理字符串发送到类似于WURFL(或其他)最新的数据库中,该数据库可以提供所需的信息。

用户代理字符串

所有现代浏览器都可以提供此信息;它公开了有关设备及其操作系统的信息。但是,如果没有像WURFL这样的字典的帮助,它对您的应用程序来说并不足够有意义。

WURFL

这是一个常用于检测设备属性的数据库。

使用它,您可能能够准确支持市场上大多数流行的设备。我会发布一个代码演示,但是可以在WURFL网站的下载中找到它。您可以在与库一起下载的examples/demo文件夹中找到这样的演示。

下载WURFL

以下是关于检查物理尺寸和分辨率的更多信息和解释: http://www.scientiamobile.com/forum/viewtopic.php?f=16&t=286


请尝试访问http://www.hyperspaces.co.uk/device - 我已经在这上面工作了一段时间,现在处于后期测试阶段...很想知道你的结果(页面上有电子邮件链接)。在Windows / Mac / iOS / Android上进行测试。 - TJS101

5
作为对“这个问题没有好的解决方案”的补充,只需查看您可以在CSS中使用的单位https://www.w3schools.com/cssref/css_units.asp
Unit    Description
cm      centimeters
mm      millimeters
in      inches (1in = 96px = 2.54cm)
px *    pixels (1px = 1/96th of 1in)
pt      points (1pt = 1/72 of 1in)
pc      picas (1pc = 12 pt)

* Pixels (px) are relative to the viewing device.
For low-dpi devices, 1px is one device pixel (dot) of the display.
For printers and high resolution screens 1px implies multiple device pixels.

这段描述似乎提供了一个解决方案。使用cmmmin可以绘制出与屏幕大小和分辨率无关的相同大小的东西。有了这个想法,您可以期望至少可以使用pxptpc来以像素级别绘制,无论您想使用什么精度(否则,拥有数百万像素有何意义呢?)。好吧,不是这样的。所有单位都是度量单位的分数,使得所有这些单位只是不同的比例尺。而故事中最糟糕的是没有一个是准确的。只需使用w3schools示例进行测试(绘制一条20厘米的线并用标尺测量即可)。
所以最终: - 没有办法准确地绘制物理尺寸的东西(这应该是cmmmin甚至ptpc的情况)。 - 没有办法以与屏幕大小和分辨率无关的相同大小绘制东西(这至少应该是px的情况)。
这既是实现问题(实际屏幕尺寸未被使用),也是设计问题(为什么 px 应该独立于屏幕尺寸,而已经有这么多单位了)。

4
您可以创建任何页面元素并使用真实的物理单位设置其宽度。例如:
<div id="meter" style="width:10cm"></div>

然后获取它的像素宽度。例如,下面的html代码(我使用JQuery)显示设备屏幕宽度(以厘米为单位)。

<script>
var pixPer10CM = $('#meter').width();
var CMPerPix = 10 / pixPer10CM;
var widthCM = screen.width * CMPerPix;

alert(widthCM);
</script>

哇,我从未意识到可以用CSS做到这一点。这有多准确?你的浏览器如何知道屏幕的物理尺寸?这个在http://caniuse.com上的浏览器兼容性如何?我找不到它。 - Jake Wilson
5
W3C网站表示:“在过去,CSS要求实现在计算机屏幕上正确显示绝对单位。但由于错误的实现数量超过了正确的实现数量,并且情况似乎没有改善,因此CSS在2011年放弃了这个要求。目前,绝对单位只需要在打印输出和高分辨率设备上正确工作。CSS没有定义“高分辨率”的含义。但是由于低端打印机现在从300 dpi开始,高端屏幕则在200 dpi,所以分界线可能介于两者之间。” - Mike
1
我认为像其他本地应用程序一样,浏览器可以通过操作系统API获取设备分辨率,该信息由设备驱动程序提供给操作系统。准确性取决于此信息。 - Mike
但是设备分辨率并不等同于实际物理尺寸。一台14英寸的笔记本电脑和一台15英寸的笔记本电脑可能具有相同的分辨率。 - Jake Wilson
8
不行!在现实中,用CSS表示的10厘米大小会因为幸运而有可能真正达到10厘米、12厘米或7厘米。这是因为浏览器总是按照每英寸像素(DPI)的方式来显示,所以那种解决方案返回的值是错误的。这里是基于该解决方案的jsfiddle演示:https://jsfiddle.net/Lzsm3zo9/ - Dariusz Sikorski
显示剩余2条评论

3
作为对zehelvion有关使用WURFL查找分辨率的回复,值得一提的是WURFL也可以作为JavaScript片段使用。
wurfl.io提供的免费版本中,您将无法获取有关屏幕和分辨率的信息(仅设备名称、表单因素和移动/非移动),但也有一个商业版本,在此处提供更多功能

3
我建议将此内容放在对应答案的评论中。 - Darkgaze
2
这是对于本应该由浏览器提供的某个东西来说过于复杂的解决方案。 - Michael

2

CSS像素并不是我们所说的“设备独立像素”。Web平台包括各种设备类型。虽然在手持设备上CSS像素看起来相当一致,但在典型的96dpi桌面监视器上,它会变大50%。请参见我的问题。在某些情况下,这实际上并不是一件坏事,例如字体在较大的屏幕上应该更大,因为到眼睛的距离更远。但UI元素的尺寸应该相当一致。假设您的应用程序有一个顶部栏,您希望它在桌面和移动设备上具有相同的厚度,默认情况下它会小50%,这不好,因为可触摸元素应该更大。我找到的唯一解决方法是根据设备DPI应用不同的样式。

您可以使用JavaScript中的window.devicePixelRatio获取屏幕DPI。或者使用CSS查询:

@media  only screen and (-webkit-min-device-pixel-ratio: 1.3),
    only screen and (-o-min-device-pixel-ratio: 13/10),
    only screen and (min-resolution: 120dpi)
    {
     /* specific styles for handhelds/ high dpi monitors*/
    }

我不知道在高dpi桌面显示器上应用这个方案会怎样,也许元素会太小。很遗憾,网络平台没有提供更好的解决方案。我猜实现dip不会太难。


不行。媒体查询在做这种愚蠢的“假设96dpi”的事情,也就是它们欺骗你关于实际DPI的信息。 - Michael

2
我在我的一个网页项目http://www.vinodiscover.com中解决了这个问题。答案是你无法确定物理尺寸,但你可以得到近似值。使用JS和/或CSS,你可以找到视口/屏幕的宽度和高度以及像素密度。例如:iPhone 5(326 ppi)= 320px x 568px 和2.0像素密度,而三星 Galaxy S4(441ppi)= 360px x 640px 和3.0像素密度。实际上,1.0像素密度约为150 ppi。

有了这个,我设置了我的CSS,在宽度小于284px时显示1列,不考虑像素密度;在284px到568px之间显示两列;在852px以上显示3列。现在,浏览器会自动执行像素密度计算,所以这比看起来更简单。

http://www.quirksmode.org/blog/archives/2010/04/a_pixel_is_not.html


3
在本地开发中,您可以获得精确的值。原文意思为:本地开发优势得分+1,Web开发劣势得分-1。 - trusktr
你能在Android中获取精确的物理尺寸吗? - Apollo Clark
1
是的:https://dev59.com/c3A75IYBdhLWcg3wrbG_ - trusktr

1
我注意到你在评论中实际上关注的是按钮等元素在观看者眼中的大小。
我曾经遇到过同样的问题,直到我发现只需在HTML头部添加一个meta标签即可设置初始缩放比例: <meta name="viewport" content="width=device-width, initial-scale=1">

0
使用getPPI()函数(移动Web:如何获取物理像素大小?),获取一英寸的id使用以下公式:
var ppi = getPPI();
var x   = ppi * devicePixelRatio * screen.pixelDepth / 24;
$('#Cubo').width (x);
$('#Cubo').height(x);

<div id="Cubo" style="background-color:red;"></div>

6
为什么是像素深度?!像素深度不是与颜色深度有关吗?如果是这样的话,我想知道它在这里的计算中是如何相关的...... 为什么使用像素深度?!像素深度与色彩深度有关,但在这种情况下,我想知道它与计算有什么关系.... - matanster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接