For media queries there are a number of media features defined.
I'd like to read a browsers actual media features' values in JavaScript. How can I do this?
To be clear, I do not want to know whether some media queries match. I want to know, for example, the physical width of the screen. Something similar to this:
let width = window.getMediaValue("device-width", "cm");
Every device has its own dpi and the JavaScript API doesn't provide more precise information than devicePixelRatio.
The devicePixelRatio of Window interface gives you a ratio
that indicates whether the rendered page should be scaled or not.
Browsers assume a devicePixelRatio of 1 means 96 dpi. I've tested in on my own 17.3" screen:
Math.sqrt(Math.pow(window.outerWidth / 96, 2) + Math.pow(window.outerHeight / 96, 2));
But it gave me 18.92 inches, which is wrong.
Then I used an online equation solver to find out the real dpi of my screen, and it's actually 105.
Indeed the result of this on my computer
Math.sqrt(Math.pow(window.outerWidth / 105, 2) + Math.pow(window.outerHeight / 105, 2));
Outputs 17.3
Media queries was introduced in CSS3, and is one of the key ingredients for responsive web design. Media queries are used to determine the width and height of a viewport to make web pages look good on all type of devices
The window.matchMedia() method returns a MediaQueryList object representing the results of the specified CSS media query string. The value of the matchMedia() method can be any of the media features of the CSS #media rule, like min-height, min-width, orientation, etc.
You can use native navigator object to get media properties, like access to webcam, mic. for ex:-
navigator.mediaDevices.getDisplayMedia()
or also use
function getWidth() {
return Math.max(
document.body.scrollWidth,
document.documentElement.scrollWidth,
document.body.offsetWidth,
document.documentElement.offsetWidth,
document.documentElement.clientWidth
);
}
function getHeight() {
return Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.body.offsetHeight,
document.documentElement.offsetHeight,
document.documentElement.clientHeight
);
}
console.log('Width: ' + getWidth() );
console.log('Height: ' + getHeight() );
also there is screen object:-
screen.availHeight
I have a page where I want to use the height of the window to restrict my use of rangeForCoordinates(). Example:
var windowHeight = window.innerHeight;
var test = rangeForCoordinates(x, windowHeight-1);
I found a few android phones where the screen density causes rounding, example:
// device screen density: 1.33
// webview height in pixels: 610 pixels
// window.innerHeight gives me: 459
// (610 / 1.33) = 458.64... and rounded up
Now if I try using that height as the ceiling, I'll get an intersected element that doesn't make any sense:
// incorrect element returned
var test = rangeForCoordinates(x, 459-1);
If I instead use the floor'd instead of rounded value, it works fine:
// ok
var test = rangeForCoordinates(x, 458-1);
Is there a way to get the height of the window without this rounding applied? It looks like 459 is out of bounds.
I was hoping that rangeForCoordinates() would return null if given out of bounds coordinates, but looks like that's not the case on some devices.
Thanks
Hello fellow code people :)
I am a frontend web developer and as such in need of constant knowledge of the actual viewport size in order to see where in responsive designing breakpoints start and end.
I know FF's own 'test window size' function, but came across a very handy extension: FireSizer.
the extension has one itsy bitsy drawback: It gives back the window-size including FF's borders and scrollbar. I need the viewport-size though. So I need the extension hacked, but dont't know enough javaScript to do so. Maybe someone is willing to help em out here?
I would love the extension to actually look for the scrollbar, and subtract from the width
a) 14 if no scrollbar present or
b) 30 if scrollbar present
I found of what I think is the right place to alter the code:
//
// Update the status bar panel with the current window size
//
function FiresizerUpdateStatus() {
var width = window.outerWidth + ''; // <- Think code needs to be edited here
var height = window.outerHeight + '';
document.getElementById("firesizer-statuspanel").label = width + 'x' + height;
}
Thanks for any effort!
AO
#Chen Asraf:
Well thank you very much. I didn't know there was an element to call the document-width. I changed the code to the following, and that did the trick (also when compared to FF's own 'Responsive Design View mode', which is spot on, its off by 2px - which i subtract from clientWidth.)
function FiresizerUpdateStatus() {
var width = window.outerWidth + ''; // changed this line to:
var width = document.documentElement.clientWidth-2 + '';
var height = window.outerHeight + '';
document.getElementById("firesizer-statuspanel").label = width + 'M' + height;
}
Thanks
AO
Possible duplicate of Get the browser viewport dimensions with JavaScript
Seems like you can get the window's inner dimensions by using:
// My window is maximized; screen is 1366x768
alert(document.documentElement.clientWidth);
// ^ returns 1349 (17 missing pixels because of scrollbar)
alert(document.documentElement.clientHeight);
// ^ returns 643 (125 pixels missing because of start bar & Chrome toolbars)
You can then compare the following with whatever else you need (for example, compare client width with window width to find if the difference is big enough to be a scrollbar - just experiment with the sizes)
I am designing a mobile website that has a section to download wallpapers from. In order to accommodate many users, I wish to make it possible to download a wallpaper based on the screen resolution. I want to detect resolution from JavaScript and show the appropriate wallpaper.
This is what I found online and tried and failed xD:
width = window.innerWidth || document.body.clientWidth
height = window.innerHeight || document.body.clientHeight;
For my SGS3, which has the resolution 720x1280 I get the 360x567.
How should I discover the resolution of the phone from JavaScript?
You can perhaps use the screen object:
var w = screen.width;
var h = screen.height;
Update - Try to use it with the window.devicePixelRatio:
var ratio = window.devicePixelRatio || 1;
var w = screen.width * ratio;
var h = screen.height * ratio;
Ken Fyrstenberg, great stuff, thanks. I was looking for an easy way to detect all the possible screen size and resolution data, and to answer the question of what the ratio is good for, it lets you see if it's for example a retina display type high resolution device.
wh:768x1024 cwh:768x905 rwh:1536x2048 ts:touch
combined with the touch tests check this related SO:
I can get a very good sense of the actual screen/touch specs of the devices our real users are running.
for web stuff, of course, what you really are interested in is the size of the actual browser inner window, the space you are allotted on the device that is. Just as an aside, I've already seen that apple devices appear to always give the portrait mode dimensions, eg, 768 x 1024 for a non retina display iPad, which is a bit annoying because I was hoping to also learn how most users actually interact with the web and our site.
Android seems to give the actual width/ height of that moment, ie, either landscape or portrait width/height.
For example:
var ratio = window.devicePixelRatio || 1;
var is_touch_device = 'ontouchstart' in document.documentElement;
var touch_status = (is_touch_device) ? 'touch' : 'no-touch';
touch_status = ' ts:' + touch_status;
var width_height = 'wh:' + screen.width + 'x' + screen.height;
var client_width_height = ' cwh:' + document.documentElement.clientWidth + 'x' + document.documentElement.clientHeight;
var rw = screen.width * ratio;
var rh = screen.height * ratio;
var ratio_width_height = ' r:' + ratio + ' rwh:' + rw + 'x' + rh;
var data_string = width_height + client_width_height + ratio_width_height + touch_status;
This creates a lot of data about the client system which you can then pass to something using whatever method you like.
UPDATE:
It just took a few minutes using this method to find how apple devices actually report their width/height:
wh:375x667 cwh:667x375 r:2 rwh:750x1334 ts:touch Device type: mobile
As you can see, the document.documentElement.clientWidth method reports the actual width if portrait/landscape, good stuff.
This will work in mobil device too
screen_width = document.documentElement.clientWidth;
screen_heght = document.documentElement.clientHeight;
You can use window.screen.width and window.screen.height to detect the screen resolution of the device.
I'm working on a kind of unique app which needs to generate images at specific resolutions according to the device they are displayed on. So the output is different on a regular Windows browser (96ppi), iPhone (163ppi), Android G1 (180ppi), and other devices. I'm wondering if there's a way to detect this automatically.
My initial research seems to say no. The only suggestion I've seen is to make an element whose width is specified as "1in" in CSS, then check its offsetWidth (see also How to access screen display’s DPI settings via javascript?). Makes sense, but iPhone is lying to me with that technique, saying it's 96ppi.
Another approach might be to get the dimensions of the display in inches and then divide by the width in pixels, but I'm not sure how to do that either.
<div id='testdiv' style='height: 1in; left: -100%; position: absolute; top: -100%; width: 1in;'></div>
<script type='text/javascript'>
var devicePixelRatio = window.devicePixelRatio || 1;
dpi_x = document.getElementById('testdiv').offsetWidth * devicePixelRatio;
dpi_y = document.getElementById('testdiv').offsetHeight * devicePixelRatio;
console.log(dpi_x, dpi_y);
</script>
grabbed from here http://www.infobyip.com/detectmonitordpi.php. Works on mobile devices! (android 4.2.2 tested)
I came up with a way that doesn't require the DOM... at all
The DOM can be messy, requiring you to append stuff to the body without knowing what stuff is going on with width: x !important in your stylesheet. You would also have to wait for the DOM to be ready to use...
/**
* Binary search for a max value without knowing the exact value, only that it can be under or over
* It dose not test every number but instead looks for 1,2,4,8,16,32,64,128,96,95 to figure out that
* you thought about #96 from 0-infinity
*
* #example findFirstPositive(x => matchMedia(`(max-resolution: ${x}dpi)`).matches)
* #author Jimmy Wärting
* #see {#link https://stackoverflow.com/a/35941703/1008999}
* #param {function} fn The function to run the test on (should return truthy or falsy values)
* #param {number} start=1 Where to start looking from
* #param {function} _ (private)
* #returns {number} Intenger
*/
function findFirstPositive (f,b=1,d=(e,g,c)=>g<e?-1:0<f(c=e+g>>>1)?c==e||0>=f(c-1)?c:d(e,c-1):d(c+1,g)) {
for (;0>=f(b);b<<=1);return d(b>>>1,b)|0
}
var dpi = findFirstPositive(x => matchMedia(`(max-resolution: ${x}dpi)`).matches)
console.log(dpi)
There is the resolution CSS media query — it allows you to limit CSS styles to specific resolutions:
http://www.w3.org/TR/css3-mediaqueries/#resolution
However, it’s only supported by Firefox 3.5 and above, Opera 9 and above, and IE 9. Other browsers won’t apply your resolution-specific styles at all (although I haven’t checked non-desktop browsers).
Here is what works for me (but didn't test it on mobile phones):
<body><div id="ppitest" style="width:1in;visible:hidden;padding:0px"></div></body>
Then I put in the .js: screenPPI = document.getElementById('ppitest').offsetWidth;
This got me 96, which corresponds to my system's ppi.
DPI is by definition tied to the physical size of the display. So you won't be able to have the real DPI without knowing exactly the hardware behind.
Modern OSes agreed on a common value in order to have compatible displays: 96 dpi. That's a shame but that's a fact.
You will have to rely on sniffing in order to be able to guess the real screen size needed to compute the resolution (DPI = PixelSize / ScreenSize).
I also needed to display the same image at the same size at different screen dpi but only for Windows IE. I used:
<img src="image.jpg" style="
height:expression(scale(438, 192));
width:expression(scale(270, 192))" />
function scale(x, dpi) {
// dpi is for orignal dimensions of the image
return x * screen.deviceXDPI/dpi;
}
In this case the original image width/height are 270 and 438 and the image was developed on 192dpi screen. screen.deviceXDPI is not defined in Chrome and the scale function would need to be updated to support browsers other than IE
The reply from #Endless is pretty good, but not readable at all,
this is a similar approche with fixed min/max (it should be good ones)
var dpi = (function () {
for (var i = 56; i < 2000; i++) {
if (matchMedia("(max-resolution: " + i + "dpi)").matches === true) {
return i;
}
}
return i;
})();
matchMedia is now well supported and should give good result, see http://caniuse.com/#feat=matchmedia
Be careful the browser won't give you the exact screen dpi but only an approximation
function getPPI(){
// create an empty element
var div = document.createElement("div");
// give it an absolute size of one inch
div.style.width="1in";
// append it to the body
var body = document.getElementsByTagName("body")[0];
body.appendChild(div);
// read the computed width
var ppi = document.defaultView.getComputedStyle(div, null).getPropertyValue('width');
// remove it again
body.removeChild(div);
// and return the value
return parseFloat(ppi);
}
(From VodaFone)
Reading through all these responses was quite frustrating, when the only correct answer is: No, it is not possible to detect the DPI from JavaScript/CSS. Often, the operating system itself does not even know the DPI of the connected screens (and reports it as 96 dpi, which I suspect might be the reason why many people seem to believe that their method of detecting DPI in JavaScript is accurate). Also, when multiple screens are connected to a device forming a unified display, the viewport and even a single DOM element can span multiple screens with different DPIs, which would make these calculations quite challenging.
Most of the methods described in the other answers will almost always result in an output of 96 dpi, even though most screens nowadays have a higher DPI. For example, the screen of my ThinkPad T14 has 157 dpi, according to this calculator, but all the methods described here and my operating system tell me that it has 96 dpi.
Your idea of assigning a CSS width of 1in to a DOM element does not work. It seems that a CSS inch is defined as 96 CSS pixels. By my understanding, a CSS pixel is defined as a pixel multiplied by the devicePixelRatio, which traditionally is 1, but can be higher or lower depending on the zoom level configured in the graphical interface of the operating system and in the browser.
It seems that the approach of using resolution media queries produces at least some results on a few devices, but they are often still off by a factor of more than 2. Still, on most devices this approach also results in a value of 96 dpi.
I think your best approach is to combine the suggestion of the "sniffer" image with a matrix of known DPIs for devices (via user agent and other methods). It won't be exact and will be a pain to maintain, but without knowing more about the app you're trying to make that's the best suggestion I can offer.
Can't you do anything else? For instance, if you are generating an image to be recognized by a camera (i.e. you run your program, swipe your cellphone across a camera, magic happens), can't you use something size-independent?
If this is an application to be deployed in controlled environments, can you provide a calibration utility? (you could make something simple like print business cards with a small ruler in it, use it during the calibration process).
I just found this link: http://dpi.lv/. Basically it is a webtool to discover the client device resolution, dpi, and screen size.
I visited on my computer and mobile phone and it provides the correct resolution and DPI for me. There is a github repo for it, so you can see how it works.
Generate a list of known DPI:
https://stackoverflow.com/a/6793227
Detect the exact device. Using something like:
navigator.userAgent.toLowerCase();
For example, when detecting mobile:
window.isMobile=/iphone|ipod|ipad|android|blackberry|opera mini|opera mobi|skyfire|maemo|windows phone|palm|iemobile|symbian|symbianos|fennec/i.test(navigator.userAgent.toLowerCase());
And profit!
Readable code from #Endless reply:
const dpi = (function () {
let i = 1;
while ( !hasMatch(i) ) i *= 2;
function getValue(start, end) {
if (start > end) return -1;
let average = (start + end) / 2;
if ( hasMatch(average) ) {
if ( start == average || !hasMatch(average - 1) ) {
return average;
} else {
return getValue(start, average - 1);
}
} else {
return getValue(average + 1, end);
}
}
function hasMatch(x) {
return matchMedia(`(max-resolution: ${x}dpi)`).matches;
}
return getValue(i / 2, i) | 0;
})();
Maybe I'm a little bit steering off this topic...
I was working on a html canvas project, which was intended to provide a drawing canvas for people to draw lines on. I wanted to set canvas's size to 198x280mm which is fit for A4 printing.
So I started to search for a resolution to convert 'mm' to 'px' and to display the canvas suitably on both PC and mobile.
I tried solution from #Endless ,code as:
const canvas = document.getElementById("canvas");
function findFirstPositive(b, a, i, c) {
c=(d,e)=>e>=d?(a=d+(e-d)/2,0<b(a)&&(a==d||0>=b(a-1))?a:0>=b(a)?c(a+1,e):c(d,a-1)):-1
for (i = 1; 0 >= b(i);) i *= 2
return c(i / 2, i)|0
}
const dpi = findFirstPositive(x => matchMedia(`(max-resolution: ${x}dpi)`).matches)
let w = 198 * dpi / 25.4;
let h = 280 * dpi / 25.4;
canvas.width = w;
canvas.height = h;
It worked well on PC browser, showing dpi=96 and size was 748x1058 px;work well on PC
However turned to mobile devices, it was much larger than I expected: size: 1902x2689 px.can't work on mobile
After searching for keywords like devicePixelRatio, I suddenly realize that, I don't actually need to show real A4 size on mobile screen (under which situation it's actually hard to use), I just need the canvas's size fit for printing, so I simply set the size to:
let [w,h] = [748,1058];
canvas.width = w;
canvas.height = h;
...and it is well printed:well printed