Check if viewport meta tag is being used
Asked Answered
C

9

14

I have a canvas that needs to be resized when the browser window is resized, so I have the following:

var resizeCanvas = function () {
    var ratio =  Math.max(window.devicePixelRatio || 1, 1);
    canvas.width = (canvas.offsetWidth || canvas.width) * ratio;
    canvas.height = (canvas.offsetHeight || canvas.height) * ratio;
    canvas.getContext('2d').scale(ratio, ratio);
}

window.addEventListener('resize', resizeCanvas);

This works great, except on mobile devices scrolling triggers the resize event.

This is undesired as resizing the canvas clears its contents, which means as a mobile user scrolls, the canvas is always wiped.

Thanks to this answer I came up with a solution based on caching the width and double checking it, but based on my design, I really only need to resolve the issue for devices which are affected by my viewport metatag:

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

Is there someway I can check if that meta tag is being used by the browser? I'm looking for something like:

if(viewportMetaTagIsUsed){
    //For mobile browsers
    window.addEventListener("orientationchange", resizeCanvas);
} else {
    //For desktop browsers
    window.addEventListener('resize', resizeCanvas);
}
Cracknel answered 9/3, 2016 at 14:20 Comment(1)
Would it be a possibility to also bind to the touchmove event and detect the fact that the event is in fact caused by a scroll? Also one thing i noticed on my android device is that the resize event only appends when i reach the end and begining of the page. On an other note, you could detect the browser with code like the one here : https://mcmap.net/q/42141/-detecting-a-mobile-browser/643039Prosthetics
T
8

AFAIK, it's not possible to detect whether a browser is capable of processing the viewport meta-tag.

Herebelow are some alternatives to consider...


Alternative 1 : browser sniffing

!function(a){var b=/iPhone/i,c=/iPod/i,d=/iPad/i,e=/(?=.*\bAndroid\b)(?=.*\bMobile\b)/i,f=/Android/i,g=/(?=.*\bAndroid\b)(?=.*\bSD4930UR\b)/i,h=/(?=.*\bAndroid\b)(?=.*\b(?:KFOT|KFTT|KFJWI|KFJWA|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|KFARWI|KFASWI|KFSAWI|KFSAWA)\b)/i,i=/IEMobile/i,j=/(?=.*\bWindows\b)(?=.*\bARM\b)/i,k=/BlackBerry/i,l=/BB10/i,m=/Opera Mini/i,n=/(CriOS|Chrome)(?=.*\bMobile\b)/i,o=/(?=.*\bFirefox\b)(?=.*\bMobile\b)/i,p=new RegExp("(?:Nexus 7|BNTV250|Kindle Fire|Silk|GT-P1000)","i"),q=function(a,b){return a.test(b)},r=function(a){var r=a||navigator.userAgent,s=r.split("[FBAN");return"undefined"!=typeof s[1]&&(r=s[0]),s=r.split("Twitter"),"undefined"!=typeof s[1]&&(r=s[0]),this.apple={phone:q(b,r),ipod:q(c,r),tablet:!q(b,r)&&q(d,r),device:q(b,r)||q(c,r)||q(d,r)},this.amazon={phone:q(g,r),tablet:!q(g,r)&&q(h,r),device:q(g,r)||q(h,r)},this.android={phone:q(g,r)||q(e,r),tablet:!q(g,r)&&!q(e,r)&&(q(h,r)||q(f,r)),device:q(g,r)||q(h,r)||q(e,r)||q(f,r)},this.windows={phone:q(i,r),tablet:q(j,r),device:q(i,r)||q(j,r)},this.other={blackberry:q(k,r),blackberry10:q(l,r),opera:q(m,r),firefox:q(o,r),chrome:q(n,r),device:q(k,r)||q(l,r)||q(m,r)||q(o,r)||q(n,r)},this.seven_inch=q(p,r),this.any=this.apple.device||this.android.device||this.windows.device||this.other.device||this.seven_inch,this.phone=this.apple.phone||this.android.phone||this.windows.phone,this.tablet=this.apple.tablet||this.android.tablet||this.windows.tablet,"undefined"==typeof window?this:void 0},s=function(){var a=new r;return a.Class=r,a};"undefined"!=typeof module&&module.exports&&"undefined"==typeof window?module.exports=r:"undefined"!=typeof module&&module.exports&&"undefined"!=typeof window?module.exports=s():"function"==typeof define&&define.amd?define("isMobile",[],a.isMobile=s()):a.isMobile=s()}(this);

alert(isMobile.any ? 'Mobile' : 'Not mobile');

This particular browser sniffing code is that of a library called isMobile.


Alternative 2 : window.orientation

Test is window.orientation is defined :

alert(typeof window.orientation !== 'undefined' ? 'Mobile' : 'Not mobile');
Triplicity answered 12/3, 2016 at 2:4 Comment(6)
I have a laptop 1024x768Tecla
@SergeSeredenko : 1024x768 is becoming increasingly rare for desktop computers, but alternative #3 definitely the least reliable alternative. Therefore, I removed it.Triplicity
Was window.orientation not superceded by window.screen.orientation which is supported by desktop browsers?Cracknel
@MisterEpic : The very point of alternative #2 is that window.orientation is NOT supported by desktop browsers.Triplicity
Understood, but can you confirm that it is supported only by all mobile browsers present and future?Cracknel
Please don't do user agent sniffing, it causes your app to break when a new phone is released with a slightly different user agent string.Olivann
E
3

Have you tried:

var viewportMetaTag = document.querySelector('meta[name="viewport"]');
var viewportMetaTagIsUsed = viewportMetaTag && viewportMetaTag.hasAttribute('content') ? true : false;

Documentation on MDN:

Easterner answered 9/3, 2016 at 16:40 Comment(3)
This will only indicate whether the meta tag is present, which it is in both desktop and mobile browsers. It's just mobile browsers will take that as a cue to blow the webpage up to take the full width of the device. Your code will always return true (p.s. you don't need the ternary at the end)Cracknel
Ah yes, now I understand what you're looking for.Easterner
@Easterner However, in my case, this is exactly the code I was looking for.Popover
O
3

Ideally, you should treat mobile devices and desktops as the same, because the line is so very blurred. Tablet propped up with a keyboard? Laptop with touchscreen? The only difference is where the cpu is located at that point.

Stick with what you were doing: Cache the width and check if it changes. Don't try to determine if the device is a mobile or a desktop device, because you will at some point fail.

Olivann answered 17/3, 2016 at 20:35 Comment(0)
A
2

you can check if orientationchange event exists or not and based on that assign the function. something like below code

if("onorientationchange" in window) {
  //For mobile browsers
  window.addEventListener("orientationchange", resizeCanvas);
} else{
  //For desktop browsers
  window.addEventListener('resize', resizeCanvas);
}

code snippet to detect event support is taken from below thread

Detecting support for a given JavaScript event?

Anticipate answered 17/3, 2016 at 16:19 Comment(0)
Y
2

Try this:

//mobile detection
    var isDevice = false;
    if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
        isDevice = true;
        // your code ...
    }

or:

if ($('meta[name="viewport"]').size() > 0) {
      // your code ...
}

or:

if ($('meta[name="viewport"]').attr('content').indexOf('device-width') - 1) {
      // your code ...
}
Yaws answered 17/3, 2016 at 20:42 Comment(0)
Q
1

I would argue that what you want is not necessarily to detect the use of the viewport tag, but really whether you are running inside of a mobile browser.

From this answer we can snag a function to detect most mobile browsers:

window.mobilecheck = function() {
    var check = false;
    (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
    return check;
}

Then you can use it to do what you want:

if(window.mobilecheck()){
    //For mobile browsers
    window.addEventListener("orientationchange", resizeCanvas);
} else {
    //For desktop browsers
    window.addEventListener('resize', resizeCanvas);
}
Quebec answered 12/3, 2016 at 2:21 Comment(1)
Hoo boy, yes, that's an option, but I am hoping beyond hope I don't have to do UA sniffing.Cracknel
T
1

You could change the content of the meta tag via js (for example, set it to width=123). Now, you've got to have such an element in your page which would certainly change its size because of that (div@width:100% maybe?). After that, you restore original value of meta, but already knowing if it means anything for the browser.

If you go this way, the result of the proceduce should be saved to localStorage or cookie, so that you mess with the page only once.

Tecla answered 12/3, 2016 at 2:51 Comment(0)
I
0

Try this:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=0.1">
<script>
    var width=$(window).width();
    $('meta[name=viewport]').attr('content','width=device-width, initial-scale=1');
    var newWidth=$(window).width();
    var viewportMetaTagIsUsed=width!=newWidth;
    alert(viewportMetaTagIsUsed?'using meta viewport':'not using meta viewport');
</script>

Or more encapsulated:

	function usesViewport() {
		var meta=$('meta[name=viewport]');
		var content=meta.attr('content');
		if (!meta.length) {
			meta=$('<meta name="viewport" content="width=device-width, initial-scale=1" />').appendTo('head');
			console.log(meta.parent());
		}
		$('meta[name=viewport]').attr('content','width=device-width, initial-scale=1');
		var width1=$(window).width();
		$('meta[name=viewport]').attr('content','width=device-width, initial-scale=0.1');
		var width2=$(window).width();
		if (content) {
			$('meta[name=viewport]').attr('content',content);
		} else {
			meta.remove();
		}
		var result=width1!=width2;
		return result;
	}
	$(function() {
		alert(usesViewport()?'Uses viewport':'Doesn\'t use viewport');
	});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

I don't know why it doesn't work here, probably something to do with the sandboxing of the script, but still, I copied and pasted it in the console on Wikipedia and it works, for example.

Isomeric answered 17/3, 2016 at 16:11 Comment(0)
P
0

You may check effectiveness of viewport meta tag by reconfiguring viewport. see code below which is tested on iOS Safari, Android Chrome, Android Firefox.

function checkIfViewportMetaEffective() {
  return new Promise((resolve, reject) => {
    let meta = document.querySelector('meta[name="viewport"]');
    if (!meta) {
      reject(new Error('No viewport meta tag found'));
      return;
    }
    let content = meta.content;
    let root = document.documentElement;
    let tempWidth = root.clientWidth + 3;
    let resolved = false;
    let isApproxmate = (a, b, epsilon = 1) => {
      return a > b - epsilon && a < b + epsilon;
    };
    let resizeHandler = (e) => {
      resolved = true;
      visualViewport.removeEventListener('resize', resizeHandler);
      console.log(root.clientWidth, tempWidth);
      resolve(isApproxmate(root.clientWidth, tempWidth, 1));
      // reset viewport and trigger repaint again
      meta.content = content;
      div.remove();
    };
    visualViewport.addEventListener('resize', resizeHandler);
    setTimeout(() => { if (!resolved) resizeHandler(); }, 50);
    // reconfigure viewport and trigger repaint
    meta.content = content.replace('device-width', tempWidth);
    let div = document.body.appendChild(document.createElement('div'));
  });
}
queueMicrotask(async () => {
  let text = 'is viewport meta effective? ' + await checkIfViewportMetaEffective();
  console.log(text);
});
Putnem answered 23/4, 2024 at 7:27 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.