102

Question

Is there a safe way to get the actually correct screen physical dimensions in Chrome, on Android? If necessary, old versions of Chrome and Android can be left out of scope.

Prior research

There are numerous dead-end questions on stackoverflow about getting the actual physical screen dimensions of a device from within javascript (or css). It seems there is no convergence between html api standardization and actual browser implementations in that, not to mention the browser implementation relies on OS api's which in turn rely on hardware providing the right information.

Some prior answers by the way are arcane (year 2011 and the like) in assuming a certain pixel density that prevailed at that time, and therefore useless. Others relate to webkit whereas Chrome blink may have superseded webkit in chrome (?).

I would like to explore the existence of a simple solution by constraining things to only Chrome on Android.

Note

This is all about a javascript (or css) solution inside the browser, not a solution for a native app.

15
  • 22
    That's simply wrong. My user interface wants to know things like how large should a button be as the user sees it. you may possibly be thinking too much as a code developer in that ;)
    – matanox
    Commented Feb 10, 2014 at 17:35
  • 12
    The size of a button, for example, shouldn't be a percentage of the viewport - but rather large enough to touch. I am not sure how that makes sense for high quality design.
    – matanox
    Commented Feb 13, 2014 at 12:55
  • 17
    @matt is absolutely correct. One of the most important aspects of Web UX/UI, especially in a fat-finger world, is making sure the buttons are both appropriate for the pointer--in this case, a finger--as well as appropriately sized for the viewing distance from screen to eye. This new realm of mobile devices have complicated the matter, so physical screen size detection is even more paramount.
    – Jason
    Commented May 7, 2014 at 8:56
  • 8
    I am 100% with you @matt. I don't understand why Mozilla and Google can't just give us a JavaScript property like window.screenDensity that contains the physical pixels per inch of the device you and I, matt, can take it from there. window.screenHeight and window.screenWidth in physical millimeters would be nice too.
    – trusktr
    Commented Jul 31, 2014 at 19:44
  • 7
    @Kinlan Physical screen size is important in general. This is why native development is more powerful than web development at the moment. In a native environment, I can make a button that is 1 (real-world) inch wide, on all modern devices, for example. This is not currently possible in a web environment, as far as I know. Have I missed something?
    – trusktr
    Commented Jul 31, 2014 at 19:47

13 Answers 13

136
+25

You can't really get the real physical dimensions or the actual DPI and even if you could, you can't do anything with them.

This is a pretty long and complex story, so forgive me.

The web and all browsers define 1px as a unit called a CSS pixel. A CSS pixel is not a real pixel, rather a unit that is deemed to be 1/96th of an inch based on the viewing angle of the device. This is specified as a reference pixel.

The reference pixel is 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. For reading at arm's length, 1px thus corresponds to about 0.26 mm (1/96 inch).

In 0.26mm of space we might have very many real device pixels.

The browser does this mainly for legacy reasons - most monitors were 96dpi when the web was born - but also for consistency, in the "old days" a 22px button on a 15 inch screen at 800x600 would be twice the size of a 22px button on a 15 inch monitor at 1600x1200. In this case the DPI of the screen is actually 2x (twice the resolution horizontally but in the same physical space). This is a bad situation for the web and apps, so most operating systems devised many ways to abstract pixel values in to device independent units (DIPS on Android, PT on iOS and the CSS Pixel on the web).

The iPhone Safari browser was the first (to my knowledge) to introduce the concept of a viewport. This was created to enable full desktop style applications to render on a small screen. The viewport was defined to be 960px wide. This essentially zoomed the page out 3x (iphone was originally 320px) so 1 CSS pixel is 1/3rd of a physical pixel. When you defined a viewport though you could get this device to match 1 CSS pixel = 1 real pixel at 163dpi.

By using a viewport where the width is "device-width" frees you up from having to set the width of the viewport on a per device basis to the optimal CSS pixel size, the browser just does it for you.

With the introduction of double DPI devices, mobile phone manufacturers didn't want mobile pages to appear 50% smaller so they introduced a concept called devicePixelRatio (first on mobile webkit I believe), this lets them keep 1 CSS pixel to be roughly 1/96th of an inch but let you understand that your assets such as images might need to be twice the size. If you look at the iPhone series all of their devices say the width of the screen in CSS pixels is 320px even though we know this is not true.

Therefore if you made a button to be 22px in CSS space, the representation on the physical screen is 22 * device pixel ratio. Actually I say this, it is not exactly this because the device pixel ratio is never exact either, phone manufacturers set it to a nice number like 2.0, 3.0 rather than 2.1329857289918....

In summary, CSS pixels are device independent and let us not have to worry about physical sizes of the screens and the display densities etc.

The moral of the story is: Don't worry about understanding the physical pixel size of the screen. You don't need it. 50px should look roughly the same across all mobile devices it might vary a little, but the CSS Pixel is our device independent way to build consistent documents and UI's

Resources:

21
  • 22
    You said "you can't do anything with them." I disagree. With that info I'd be able to set a font that is always 16 points (16/72nds of a real-world inch) in height. That is invaluable, and one of the reasons native development continues to be more powerful than web development.
    – trusktr
    Commented Jul 20, 2014 at 20:55
  • 9
    Actually, a perfectly reasonable use for the real screen size in pixels is to render a background image with the appropriate resolution.
    – WhyNotHugo
    Commented May 9, 2015 at 3:11
  • 3
    "50px should look roughly the same across all mobile devices" please prove that using for example a 1200x1920 4 inch phone and a 1000x600 10 inch tablet next to eachother.
    – iloveregex
    Commented Apr 23, 2016 at 19:09
  • 6
    I also disagree with "you can't do anything with them.": you can detect if the device is a phone or a tablet reliably and assume that user can easily point on top of the screen with their finger or not. Commented Jan 24, 2018 at 16:53
  • 3
    Very detailed answer, but I don't understand why stating that there nothing we can do with the physical size of the screen. There are many things we can do with this information. For example knowing (or setting) the physical dimension of something on the screen. For example to show something as it would be printed. Applications to augmented reality are also obvious. It would be nice if answers would stick to the question, and not decide what people would like to do.
    – Tom
    Commented Jun 21, 2018 at 14:44
10

There is no way to get physical dimensions of physical pixels or displays in a web app (no web API for it).


Based on Matanster's answer in which he observed SVG properties such as screenPixelToMillimeterX, I made a test to see if they work:

(EDIT: these properties are deleted (or never were) from spec, and browsers may no longer have (or never had) them, moving us further away from ever knowing actual physical display sizing).

// 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\"?");

This is the output:

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

Nope.

There seems to be no way to get real physical values in a web browser yet.

19
  • 1
    I'm not sure what answer you are referring to (I don't see a "Matt" anywhere), but i get NaN due to svgEl.screenPixelToMillimeterX apparently not being defined.
    – Michael
    Commented Feb 8, 2018 at 2:24
  • I got the same result as you, 15.4" but my screen is actually 21", it's too different
    – Toan NC
    Commented Aug 24, 2021 at 14:40
  • @Michael He changed his name to "matanster" and deleted his answer (stackoverflow.com/a/24780546/454780).
    – trusktr
    Commented Aug 27, 2021 at 16:57
  • @TJS101 Unless there is a new web API I'm not aware of, it is impossible to get dimensions of physical pixels, and we can only get dimensions of CSS pixels, noting that CSS in units (and other "physical" units) are not accurate (they are relative to CSS pixels, not physical pixels, and 1in will therefore vary from device to device). Also the thisDevice object appears to be empty for me when I visit in Chrome in Linux. I really do wish we had API for physical screen dimensions.
    – trusktr
    Commented May 23, 2022 at 22:39
  • @trusktr Thank you for pointing this out. Older browsers don't support some of the newer functions I used, so I have added a "compatibility mode" that identifies if things like visualViewport are not supported and provides a cut down version of the demo page. hyperspaces.co.uk/device
    – TJS101
    Commented May 30, 2022 at 10:14
6

As a complement to the ”there's no good solution to this problem” answer, just check the units you can use on 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.

With this description it seems there is a solution. cm, mm and in would be used to draw something with the same size independently of the screen size and resolution. With this in mind, you can expect that at least one of px, pt or pc can be used to draw at the pixel level, for whatever precision you would like to use (otherwise, what's the point on having millions of pixels, right?). Well, no. All of the units are fractions of a metric unit, making all of these units just different scales. And the worst in the story is the fact that none of these are accurate. Just play with the w3schools example (draw a 20cm line and measure it with a ruler).

So in the end: - there is no way to draw something with physical dimensions accurately (which should be the case with cm, mm, in, and eventually pt and pc). - there is no way to draw something with the same size independently of the screen size and resolution (which should be the case with at least px).

This is both an implementation problem (actual screen size not being used) and design problem (why should px be independent of the screen size while there is already so many units for that).

5

You can get that info with WURFL:

Device display properties

The attributes are called:

resolution_(width|height)

physical_display_(width|height)

Long version:

The best and most reliant strategy to achieve this is to send the user agent string from the browser to a DB like WURFL (or another) up to date DB that can provide the needed information.

User Agent string

This is a piece of information that all modern browsers can provide; it exposes information about the device and it's OS. It is just not meaningful enough to your application without the help of a dictionary like WURFL.

WURFL

This is a database commonly used to detect device properties.

With it, you may be able to accurately support most of the popular devices on the market. I would post a code demo but one is available with the download on the WURFL site. You can find such a demo on the examples/demo folder that is downloaded with the library.

Download WURFL

Here is more information and explanation about checking the physical size and resolution: http://www.scientiamobile.com/forum/viewtopic.php?f=16&t=286

0
4

You can create any page element and set its width using real physical units. For example

<div id="meter" style="width:10cm"></div>

And then get its width in pixels. For example html code below (i used JQuery) shows device screen width in centimeters

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

alert(widthCM);
</script>
7
  • Wow I never realized you could do this with css. How accurate is this? How does your browser know the physical dimensions of your screen? Is the browser compatibility for this on caniuse.com somewhere? I can't find it. Commented Apr 1, 2015 at 21:01
  • 5
    W3C site says: "In the past, CSS required that implementations display absolute units correctly even on computer screens. But as the number of incorrect implementations outnumbered correct ones and the situation didn't seem to improve, CSS abandoned that requirement in 2011. Currently, absolute units must work correctly only on printed output and on high-resolution devices. CSS doesn't define what “high resolution” means. But as low-end printers nowadays start at 300 dpi and high-end screens are at 200 dpi, the cut-off is probably somewhere in between."
    – Mike
    Commented Apr 2, 2015 at 11:59
  • 1
    I think that browser like any other native application can get device resolution through OS API, provided to OS by device driver. Accuracy depends on this information.
    – Mike
    Commented Apr 2, 2015 at 12:15
  • But device resolution is not the same as actual physical dimensions. A 14" laptop and 15" laptop could have the same resolution. Commented Apr 2, 2015 at 16:44
  • 8
    No! You can't. 10cm in Css will have different size in reality. It's pure matter of luck if it will actually have 10cm, 12cm or 7cm. Here's my jsfiddle demo based on that solution returning wrong values, since browsers always behave like they have pixels per inch (dpi): jsfiddle.net/Lzsm3zo9 Commented Oct 9, 2016 at 11:36
3

As a response to zehelvion reply about using WURFL to find the resolution, it is also worth mentioning that WURFL is also available as a JavaScript snippet.

In the free edition offered at wurfl.io, you won't get information about the screen and resolution though (only device name, form factor and mobile/not mobile), but there is also a commercial version with more capabilities available here.

2
  • 3
    I suggest this to be in the comments to that particular answer.
    – Darkgaze
    Commented Nov 22, 2016 at 11:23
  • 2
    this is a ridiculously complicated solution to something that should just be provided natively by the browser.
    – Michael
    Commented May 7, 2019 at 2:47
2

I tackled this problem with one of my web projects http://www.vinodiscover.com The answer is that you can't know for certain what the physical size is, but you can get an approximation. Using JS and / or CSS, you can find the width and height of the viewport / screen, and the pixel density using media queries. For example: iPhone 5 (326 ppi) = 320px by 568px and a 2.0 pixel density, while a Samsung Galaxy S4 (441ppi) = 360px x 640px and a 3.0 pixel density. Effectively a 1.0 pixel density is around 150 ppi.

Given this, I set my CSS to show 1 column when the width is less than 284px, regardless of pixel density; then two columns between 284px and 568px; then 3 columns above 852px. It's much more simple then it seems, since the browsers now do the pixel density calculations automatically.

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

3
2

CSS pixels aren't really our "device independent pixel". Web platform consists of variety of device types. While CSS pixel seem to look pretty consistent on handhelds, it will be 50% bigger on a typical 96dpi desktop monitor. See my question . This is really not a bad thing in some cases, e.g. fonts should be larger on a larger screen, since distance to the eye is bigger. But ui element dimensions should be pretty consistent. Let's say your app has a top bar, you would rather want it to be the same thickness on desktop and mobiles, by default it will be 50% smaller, which is not good, because touchable elements should be bigger. The only workaround I have found is to apply different styles based on device DPI.

You can get screen DPI in JavaScript with window.devicePixelRatio . Or CSS query:

@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*/
    }

I don't know how applying this would work on a high dpi desktop monitor though. Perhaps elements would be too small. It is really a shame that the web platform doesn't offer anything better. I guess that implementation of dip wouldn't be too hard.

1
  • no, you can't. media queries are doing this stupid "assume 96dpi" crap, i.e. they are lying to you about what the read DPI is.
    – Michael
    Commented May 7, 2019 at 2:48
1

I noticed in your comments that you were actually concerned with the size that buttons and so on appear to the viewer.

I was having the same problem, until I discovered that it just was a matter of adding a meta tag to the HTML header to set the initial scale:

<meta name="viewport" content="width=device-width, initial-scale=1">

0

JqueryMobile width of element

$(window).width();   // returns width of browser viewport
$(document).width(); // returns width of HTML document

JqueryMobile Height of element

$(window).height();   // returns height of browser viewport
$(document).height(); // returns height of HTML document

Good Luck Danny117

1
  • 3
    Those are virtual dimensions, which are not always physical real-world dimensions.
    – trusktr
    Commented Jul 20, 2014 at 20:56
0

Using the getPPI() function (Mobile web: how to get physical pixel size?), to obtain a one inch id use this formula:

var ppi = getPPI();
var x   = ppi * devicePixelRatio * screen.pixelDepth / 24;
$('#Cubo').width (x);
$('#Cubo').height(x);

<div id="Cubo" style="background-color:red;"></div>
1
  • 6
    why pixelDepth?! isn't pixelDepth related to color depth, in which case I wonder how is it relevant to the calculation here....
    – matanox
    Commented Jun 21, 2015 at 9:44
0

Heh wish I could answer this but geeks building APIs don't provide the basic necessities and abstract things a bit too much at times.

BTW I have 40 years of UI and software design design experience and have been pushing to have just this for what seems like forever since before the days of "VESA" drivers :).

For touch screen I had a thing I called "fingerSize()" which was the number of pixels to be 1cm ( very close to diameter of average touch area of finger) but the root datmum is "dpcm".

The other thing you want for a display is "angle of view" The type of display device for viewing and touch function pretty much defines viewing distance.

    (Not code but I wanted fixed width font)

    Hand held - Phone/Tablet         25cm 
    Touch screen / Desktop Monitor   40cm         ( seated or standing at a counter
                                                    with partially extended arm )
    "Personal" Touch kiosk        50cm -> 80cm ( a bit further away standing 
                                                 extended arms and standing back 
                                                 to view )
    Presentation Screen.          any distance ( angle of view derived from pixel
                                                 width of device. An ideal conventional cinema 
                                                 seat (as opposed to imax or immersive) 
                                                 you want about 50 degrees
                                                 between edges of the screen. from viewer POV )

    So what you want universally available is:

    device usage type.
    finger size in pixels (dots per CM)
    pixel dimensions of display.

    Then internally, when laying out and drawing you want the size/shape of a pixel 
    for the current transform. 

This is what we try to provide in our APIs But alas hard to get in many cases.

-2

You can get a rough estimation of size, but it's not accurate.

I've put together an example which I've tested on a couple devices to see what the results were. My iPhone 6 returns values about 33% larger. My 27" desktop monitor on my Mac reported as a 30" monitor.

var $el = document.createElement('div');
$el.style.width = '1cm';
$el.style.height = '1cm';
$el.style.backgroundColor = '#ff0000';
$el.style.position = 'fixed';
$el.style.bottom = 0;
document.body.appendChild($el);
var screenDiagonal = Math.sqrt(Math.pow((window.screen.width / $el.offsetWidth), 2) + Math.pow((window.screen.height / $el.offsetHeight), 2));
var screenDiagonalInches = (screenDiagonal / 2.54);
var str = [
  '1cm (W): ' + $el.offsetWidth + 'px',
  '1cm (H): ' + $el.offsetHeight + 'px',
  'Screen width: ' + window.screen.width + 'px',
  'Screen height: ' + window.screen.height + 'px',
  'Browser width: ' + window.innerWidth + 'px',
  'Browser height: ' + window.innerHeight + 'px',
  'Screen available width: ' + window.screen.availWidth + 'px',
  'Screen available height: ' + window.screen.availHeight + 'px',
  'Screen width: ' + (window.screen.width / $el.offsetWidth).toFixed(2) + 'cm',
  'Screen height: ' + (window.screen.height / $el.offsetHeight).toFixed(2) + 'cm',
  'Screen diagonal: ' + screenDiagonal.toFixed(2) + 'cm',
  'Screen diagonal: ' + screenDiagonalInches.toFixed(2) + 'in',
  'Device Pixel Ratio: ' + (window.devicePixelRatio || 1)
].join('\n');
var $pre = document.createElement('pre');
$pre.innerHTML = str;
document.body.appendChild($pre);

http://codepen.io/kus/full/xOAPYB/

3
  • 1
    My 40inch reported as a 22inch.
    – RobotRock
    Commented Jul 27, 2016 at 8:48
  • Not accurate for me neither. I think the problem is due to window.devicePixelRatio. It is 1 on an Apple Thunderbolt screen, and 2 on an Macbook Pro Touchbar 15". Is this value always an integer? This wouldn't make sense since it is a ratio. Other elements: stackoverflow.com/questions/16385573/…
    – Tom
    Commented Jun 21, 2018 at 14:40
  • It might not have been much good back in 2016, but it reports a screen size of 45" for my desktop PC (real size is 40") and 10" for my Galaxy S10+, which is both close enough to i.e. differentiate between different scaled versions of UIs and documents. Not sure why you prefix all variables with $ though. Commented Nov 19, 2020 at 23:37

Not the answer you're looking for? Browse other questions tagged or ask your own question.