Detecting physical screen dimensions of WebKit devices in JavaScript - javascript

I'd like to categorize devices by screen width in client-side JavaScript code
All devices fitting to one hand (7" less) to mobile category
Treat other devices as desktop devices
Fallback: Treat devices which do not support necessary APIs as mobile devices
Question
Which related JavaScript and CSS APIs I could use to detect the screen physical dimensions? Please note that these APIs do not need to be necessarily supported in older browsers, as there is safe fallback. Also, I don't care about legacy desktop browsers either.
Firefox support is optional - if they have compatible APIs already.
Please note that this is about physical dimensions, not pixel dimensions.

There's no direct way to get the screen size in inches, but there are workarounds that use screen density to find the device size. It's not perfect, but you don't really need to know the exact size to 5 significant figures. Also, it is normally better to simply use pixel values, IMO.
HTML
Make a test div, and then see the number of pixels displayed to get the pixel density, then use that in your calculations. This should work, assuming that your browser/OS are configured properly (it didn't work in the this question but it was within half an inch on my computer).
EDIT: This is 100% wrong. The inch/cm measurements in CSS aren't based on an actual physical measurement. They're based on an exact conversion (1 inch = 96 px, 1 cm = 37.8 px). My apologies.
CSS
The best way to detect physical screen size is to use CSS media queries. The min-resolution and max-resolution queries can be used to get the resolution in either dpi or dpcm:
#media (min-resolution: 300dpi){
// styles
}
Combining it with the min-device-width and max-device-width queries, you get something like:
#media (resolution: 326dpi) and (device-width: 640) and (device-height: 960){
// iPhone
}
The problem is that if you want to target 7 inch devices, you'd have to have many resolutions and corresponding widths that go together, which could get complicated.
For more information:
MDN- CSS Media Queries
MDN- Resolution
"Mobifying" Guide
High DPI Images for Variable Pixel Densities (Somewhat Related)
Javascript
You can use window.devicePixelRatio to determine the screen density. From Android's WebView Reference:
The window.devicePixelRatio DOM property. The value of this property specifies the default scaling factor used for the current device. For example, if the value of window.devicePixelRatio is "1.0", then the device is considered a medium density (mdpi) device and default scaling is not applied to the web page; if the value is "1.5", then the device is considered a high density device (hdpi) and the page content is scaled 1.5x; if the value is "0.75", then the device is considered a low density device (ldpi) and the content is scaled 0.75x.
Then using this, you calculate the physical size by dividing this by the total number of pixels, which can be calculated with window.screen.width and window.screen.height (Don't use window.screen.availHeight or window.screen.availWidth because these only detect the available height).
For more information:
Android Webview Reference
MDN - Screen.width
MDN - Screen.height
devicePixelRatio Explanation

better to use CSS
#media screen and (max-width: 672px){
//your code for mobile category
}
#media screen and (min-width: 672px){
//your code for desktop category
}

Related

HTML & CSS: fixed pixel height seems to be rendered differently in diffent screens / devices

I have set a fixed height for a div, let's say:
div.box {
height: 250px;
}
Using a tool (Meazure) which measures the pixels of the screen, I've noticed that on my desktop PC, which has a monitor of 1680x1050 pixels resolution, the pixels of the box are 250px (the right value); however, in my laptop, which has a 1920x1280 resolution display, the pixels measured using Meazure are different! It shows 539 pixels...
The same thing happens for offset values given in pixels... I notice different behaviours among different screens and devices (on my smartphone this effect is much more amplified...)
How can I set a "fixed" value which will appear the same for every device?
(Note: I don't want to use 100% for the width, since I want the box to have a fixed value even after resizing the window).
How can I set a "fixed" value which will appear the same for every device?
That's the thing, though: a "fixed" pixel value wouldn't appear the same on every device, because high-density screens are a thing that exists.
That 250px box that looks fine on a 72ppi screen would be itsy-bitsy on a high density 300ppi screen (specifically it'd be 24% of the intended size.) Browsers compensate for this using the device pixel ratio to adjust the specified pixel value to an appropriate size for that screen on that device. (Your 'meazure' tool doesn't appear to be taking this pixel ratio into account, which would seem to rather limit its usefulness, as it will only give accurate results on a traditional low-density screen.)
In theory you could undo this by multiplying the size of an element by the inverse of the current devicePixelRatio, but the result would be the opposite of what you want: the elements would have the same number of physical pixels, but would look completely different sizes on each device.
In practice it's mostly safe to ignore that this is happening at all and trust the browser to adjust your specified sizes correctly. (Take measurements using a density-aware tool, or the browser's own developer tools.) The only case where you really need to take this into account is if you include high-resolution bitmap images for use on higher-density screens; in those cases you'd use #media queries to determine which image the browser should use, such as
#media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
/* 2x-res images here */
}
/* low-res images here */
(the -webkit prefixed value is, of course, vendor-specific; resolution is the not-yet-universally-supported standard.)
I would first suggest to first check actual CSS properties. Right button -> inspect element and to see if on your PC and laptop div.box height is actually set to 250px
Maybe due to different resolutions, different styles are being applied.
If you have a www. page to look at, post it in comments

Why does screen.width detect different width than phone manufacturer stats? [duplicate]

As far as I know it's the ratio between the "abstract" resolution and the device's physical resolution. So I test it (on HTC Desire), the physical resolution is 480x800, it's logged out the ratio is 1.5. I threw in some elements, but it still take exactly 480px width to fill the viewport where my naive thought it's need '320px'?
From http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html, where the author discusses the differences in devicePixelRatio across mobile devices:
On iOS Retina devices, screen.width gives the width in dips. So both a
retina and a non-retina iPad report 768 in portrait mode. On the three
Android devices, screen.width gives the width in physical pixels; 480,
720, and 800, respectively. All browsers on the devices use the same
values. (Imagine if some browsers on the same device used dips and
others physical pixels!)
Which leads the author to the following conclusion:
On iOS devices, multiply devicePixelRatio by screen.width to get the physical pixel count.
On Android and Windows Phone devices, divide screen.width by devicePixelRatio to get the dips count.
What matters in your case is screen width, plain and simple. The calculation of DIPs is something for the device to take care of, rather than you as the developer. If the device wants to compensate for a different pixel ratio, it will serve you a width in DIP and give the ratio. If it feels that pages should be displayed with the native unmodified pixel resolution, it will serve you that width instead. The author of the post also comes to the following conclusion which I find interesting:
Apple added pixels because it wanted to make the display crisper and smoother, while the Android vendors added pixels to cram more stuff onto the screen.
At any rate, use the width the browser gives you and leave it to the device to compensate.

How does viewport detection differentiate tablet from phone?

Everywhere I look, people keep saying stay away from UA-sniffing, even JQuery dropped that feature...
So how in the world does viewport-detection fill this gap of tablet vs phone (since newer models overlap in resolution)?
Can anyone explain how viewport detection is THE WAY to go on this...
According to your comments, what you really want to be doing is setting
<meta name="viewport"
content="width=device-width,
initial-scale=1.0,
minimum-scale=1.0">
In your <head>, which will force the pages to render at the device's width (or individual browser's width on that device, if you have, say Opera+Chrome+Android+etc installed on an Android, which will all likely be the same viewport, anyway).
For most 10" tablets, the viewport is the resolution of the device.
For most phones, the viewport-width (in portrait) is 320px - 360px.
So even though the Galaxy S4 and Note 3 might be 1920x1080, they're really 640x360 when the viewport is enabled (where each CSS pixel has 9 [3x3] screen-pixels worth of "sub-pixel" anti-aliasing applied, and where fonts/images are rendered at the full-resolution of the screen-pixels [a 200x100 image in CSS width/height could actually be a 600x300 image]).
Instead of 3:1, "retina" iDevices have a 2:1 viewport DPPX (dot-per-pixel).
Other Androids/BBs/browsers have wonky, potentially-fractional DPPXs (so depending on Int-based DPPXs in equality tests should be avoided, too).
Then, you can test in JS, by using document.body.getBoundingClientRect().width, assuming that your body and layout are set appropriately in CSS.
If you aren't already doing this, then you probably have more to worry about in your responsive-design than whether an ad seems too big or too small.
In terms of UA-sniffing, it is occasionally valid.
That is, it's valid when you sniff the UA from your server-side language, against a DB of all-known UAs for phones/tablets, and then pre-compose an HTML page with baked-in CSS/JS, and pre-optimize images for that exact model...
However, that's not sniffing for specific sections of a UA string, that's searching every UA string for an exact match, and building to the specs of that device.
The reasoning is simple here:
How do you differentiate, in a UA, between all Android phones, all Android tablets and all other "miscellaneous" devices which run on the Android platform, when there is no standard way of defining every facet of the device+browser?
You might know the difference between an iPhone and an iPad, but how do you know the difference between Chrome on a generic 6" Taiwanese cell-phone and a generic 7" Taiwanese tablet?
The one instance of UA-sniffing that I can think of being valid is the .toDataURL() method of canvas in Android 2.2, which was technically added (you can detect it), but was never implemented (it just returns blank data, because the function was never actually written).
EDIT
SASS example, assuming Meta-Viewport is set properly
// my-widget.scss
// assuming a 1920x1080 phone (Samsung S4, Note 3 / Google Nexus 5 / HTC One)
// assuming 1920x1080 is max tablet size (with portrait width 1080)
// assuming that larger than 1080 is desktop
.my-widget {
// default experience
background-color : grey;
color : black;
font-size : 1rem;
// 1080px phone
#media screen and (max-width : 360px) {
font-size : 2rem;
background-color : white;
color : black;
}
// tablets up to 1080px, or phones in landscape-mode
// (or really-really big phones... none in North America, that I know of)
#media screen and (min-width : 361px) and (max-width : 1080px) {
background-color : black;
color : white;
}
}
Don't want to allow phones in landscape to move to a different layout, then increase it to 640px, or add an orientation-check to the #media rule.
Realistically, you shouldn't be targeting device-constraints. What you should be doing is targeting content-restraints.
Where does it make sense for your widgets to flow out into three or four columns, and where does it make sense (at what pixel/em-widths) to make everything break down into single-column mode, because your experience breaks otherwise.
But the point is that with the viewport set, you can now serve the super-small experience to the Samsung Galaxy Gear, the Nintendo 3DS, etc... a small experience to phones, a medium experience to iPads and 7"/8" tablets, a larger-medium experience to full-sized tablets, a desktop/TV experience, and a stupid-huge experience to people with multiple-monitors, or the Nexus 10, or 4k TVs, et cetera.
And it all comes at no extra sniffing...
Just a little planning, and some media queries.
You can add as many or as few breakpoints as you like.
Heck, knowing that the iPhone is 320px, you could serve an experience specifically to things sized exactly like iPhones, and then serve generic mobile from 321 up to 480 (or 640), or just make one responsive-grid flow all the way from 320px to 768px (iPad width), and have that be your "small", and serve everything larger as desktop...
Sky is the limit.
You just need to know what breakpoints you care about.

Responsive Design on mobile phones with higher resolutions

To my understanding (correct me if I am wrong) a modern Responsive website will change to fit the size and type of device you are using. Or this can be applied if the size of the window changes.
My question is why does my mobile phone display a Responsive site just like how a modern 1080p monitor would display it.
Essentially, my current monitor is running at 30" and is at a resolution of 768p. My phone also has a resolution of 768p.
Many responsive websites use media queries to display a CSS file based on the pixel width.
Wouldn't this be the same for both my monitor and phone?
MY QUESTION: How can I make a site responsive based on the screen size (in inches, etc) and not the screen resolution or number of pixels.
EDIT: My responsive design has 3 levels of CSS for different pixel widths (media-queries). When viewing on a monitor or smartphone, it displays the higher-most level (above 767p). How can I get my smartphone to display my lowest-level CSS (below 480p) even though it actually has more pixels.
I recently created a website using similar tech http://www.super-rod.tv/
It targets on both PC and mobile devices and will response to dynamic browser width resizing.
I used media query with max-width listing from higher-most to lower. For 1080P screens it has the best full screen display and for larger ones like 4K screen it will be centered with a texture background, on lower res like 768P it uses a smaller set of images and also be centered just like on a 4K screen.
If you are only targeting mobile devices, you can use device-width instead see ref here width versus device-width
To force using lowest CSS set you can either by using the max-width of 1000px (I don't think those who are still using 800x600 on PC would be your target?), this would pass out all desktops, or you can use browser UA to tell (defining for all IE,Safari,FF,Chrome,Opera etc., and the rest are mobiles).

Android 2.2 2.3 workaround for device-width media query

I've observed a problem on Android 2.2 and 2.3 native browser where device-width CSS media query and window.screen.width both report sizes based on your webpage document and scaling applied.
Example: 1:1 scaling, 960px wide page will show proper device width (say, 320px)
Example: fit-screen scaling, 960px wide page, improperly reports 960px device width
So with appropriate viewport meta tag content it seems predictable. However, in my case I cannot rely on the meta tag. Does anyone use a workaround to get a reliable device width measurement in Android irrespective of viewport meta tag? Other platforms do report this correctly across all scaling.
Ref:
http://code.google.com/p/android/issues/detail?id=11961
window.outerWidth and window.outerHeight always report the browser pixels (ie screen resolution minus UI bars, typically 480x762 on a Galaxy S.)
You may then to throw in window.devicePixelRatio to calculate the virtual pixel width (320px).

Categories