Last active
February 2, 2021 17:08
-
-
Save mmocny/012250227249f53d7758da7b18e876d5 to your computer and use it in GitHub Desktop.
Re-Implement Chrome conventions for mobile viewport test in JS.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Re-implement based on conventions from: | |
* https://source.chromium.org/chromium/chromium/src/+/master:cc/trees/layer_tree_host_impl.cc;l=160-176 | |
* | |
* With help from github.com/dontcallmedom and his library: | |
* https://github.com/dontcallmedom/metaviewport-parser (MIT https://github.com/dontcallmedom/metaviewport-parser/blob/master/LICENSE) | |
*/ | |
function HasFixedPageScale() { | |
// Simpler variant: | |
// document.head.querySelector('meta[name=viewport]').getAttribute('content').split(/ *, */).forEach(v => { val = v.split(/ *= */, 2); attrs[val[0]] = val[1] }) | |
// From: https://github.com/dontcallmedom/metaviewport-parser | |
function parseMetaViewPortContent(S) { | |
var parsedContent = { | |
validProperties : {}, | |
unknownProperties: {}, | |
invalidValues : {} | |
}; | |
var i = 1; | |
while (i <= S.length) { | |
while (i <= S.length && RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])) { | |
i++; | |
} | |
if (i <= S.length) { | |
i = parseProperty(parsedContent, S, i); | |
} | |
} | |
return parsedContent; | |
}; | |
function parseProperty(parsedContent, S, i) { | |
var start = i; | |
while (i <= S.length && !RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])) { | |
i++; | |
} | |
if (i > S.length || RegExp(',|;').test(S[i-1])) { | |
return i; | |
} | |
var propertyName = S.slice(start - 1, i-1); | |
while (i <= S.length && !RegExp(',|;|=').test(S[i-1])) { | |
i++; | |
} | |
if (i > S.length || RegExp(',|;').test(S[i-1])) { | |
return i; | |
} | |
while (i <= S.length && RegExp(' |\x0A|\x09|\0d|=').test(S[i-1])) { | |
i++; | |
} | |
if (i > S.length || RegExp(',|;').test(S[i-1])) { | |
return i; | |
} | |
start = i; | |
while (i <= S.length && !RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])) { | |
i++; | |
} | |
var propertyValue = S.slice(start - 1, i-1); | |
setProperty(parsedContent, propertyName, propertyValue); | |
return i; | |
} | |
function setProperty(parsedContent, name, value) { | |
if (propertyNames.indexOf(name) >= 0) { | |
var number = parseFloat(value); | |
if (!isNaN(number)) { | |
parsedContent.validProperties[name] = number; | |
return; | |
} | |
var string = value.toLowerCase(); | |
if (string === "yes" || string === "no" || string === "device-width" || string === "device-height" || | |
// https://webkit.org/blog/7929/designing-websites-for-iphone-x/ | |
(name.toLowerCase() === 'viewport-fit' && (string === 'auto' || string === 'cover'))) { | |
parsedContent.validProperties[name] = string; | |
return; | |
} | |
parsedContent.validProperties[name] = null; | |
parsedContent.invalidValues[name] = value; | |
} else { | |
parsedContent.unknownProperties[name] = value; | |
} | |
} | |
var propertyNames = ["width", "height", "initial-scale", "minimum-scale", "maximum-scale", "user-scalable", "shrink-to-fit", "viewport-fit"]; | |
//let sample = "width=device-width, initial-scale=1"; | |
let vp = document.head.querySelector('meta[name=viewport]'); | |
if (!vp) return false; | |
let vpc = parseMetaViewPortContent(vp.getAttribute("content") || ""); | |
if (!vpc) return false; | |
let { "minimum-scale": minScale, "maximum-scale": maxScale } = vpc.validProperties; | |
return Number.isFinite(minScale) && Number.isFinite(maxScale) && minScale == maxScale; | |
} | |
function HasMobileViewport() { | |
return document.scrollingElement.scrollWidth <= document.scrollingElement.clientWidth + 0.15; | |
} | |
function IsMobileOptimized() { | |
return HasFixedPageScale() || HasMobileViewport(); | |
} | |
// I'm not sure if there are more signals than just these two. | |
function HasTapDelay() { | |
let vp = document.head.querySelector('meta[name=viewport]'); | |
return !vp || !IsMobileOptimized(); | |
} | |
console.log("HasTapDelay:" , HasTapDelay()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment