正在检测移动设备 "notch"
Detecting mobile device "notch"
随着 iPhone X 的发布迫在眉睫,我正努力领先于游戏并准备我的一些 Web 应用程序来处理任何设计更改 - 其中最大的是新的 "notch" 前置摄像头。
我想知道在 Javascript 中是否有或可能有任何检测方法。
有趣的是,Chris Coyier 写了一篇关于 The "Notch" and CSS 的文章,它让我发现了 safe-area-inset-right
常量。有什么方法可以在 Javascript 中访问它,这是一个可靠的测试吗?
if (window.constant.safeAreaInsetRight) {
var notch = true;
}
这可能有点老套,但是,获取屏幕可用的高度和宽度并将它们与此规格匹配将使我们能够确定它是否是 iPhone X。
请注意
In portrait orientation, the width of the display on iPhone X matches
the width of the 4.7" displays of iPhone 6, iPhone 7, and iPhone 8.
The display on iPhone X, however, is 145pt taller than a 4.7"
display...
所以,首先,你要通过 userAgent 检查它是否是 iPhone,其次你要检查实际屏幕的区域(不包括默认为纵向的方向),最后,一旦我们通过它的屏幕尺寸知道它是一个 iPhoneX,您可以确定方向(基于上面 iPhone X 图下的 table)
if (navigator.userAgent.match(/(iPhone)/)){
if((screen.availHeight == 812) && (screen.availWidth == 375)){
if((window.innerHeight == "375") && (window.innerWidth == "812")){
// iPhone X Landscape
}else{
// iPhone X Portrait
}
}
}
References:
至于CSS的解决方法,我昨天找到了一篇有趣的文章,可能会有用
Let’s say you have a fixed position header bar, and your CSS for iOS
10 currently looks like this:
header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 44px;
padding-top: 20px; /* Status bar height */
}
To make that adjust automatically for iPhone X and other iOS 11
devices, you would add a viewport-fit=cover option to your viewport
meta tag, and change the CSS to reference the constant:
header {
/* ... */
/* Status bar height on iOS 10 */
padding-top: 20px;
/* Status bar height on iOS 11+ */
padding-top: constant(safe-area-inset-top);
}
It’s important to keep the fallback value there for older devices that
won’t know how to interpret the constant() syntax. You can also use
constants in CSS calc() expressions.
// iphone X detection
function hasNotch() {
if (CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) {
let div = document.createElement('div');
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
document.body.appendChild(div);
let calculatedPadding = parseInt(window.getComputedStyle(div).paddingBottom, 10);
document.body.removeChild(div);
if (calculatedPadding > 0) {
return true;
}
}
return false;
}
由于@youssef-makboul 的回答和@hjellek 的评论,iOS 已从 constant() 更改为 env() 语法,需要回退以在所有当前 iPhone X iOS 个版本。
const hasNotch = function () {
var proceed = false;
var div = document.createElement('div');
if (CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) {
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
proceed = true;
} else if (CSS.supports('padding-bottom: constant(safe-area-inset-bottom)')) {
div.style.paddingBottom = 'constant(safe-area-inset-bottom)';
proceed = true;
}
if (proceed) {
document.body.appendChild(div);
let calculatedPadding = parseInt(window.getComputedStyle(div).paddingBottom);
document.body.removeChild(div);
if (calculatedPadding > 0) {
return true;
}
}
return false;
};
要补充的几件事:
确保您的 index.html
中包含以下内容
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
此外:
这里有很棒的文章:CSS Tricks Notch
我正在使用这个:
function hasNotch() {
//iphone X 1.11
if (document.documentElement.clientHeight == 812 && document.documentElement.clientHeight == 375 && !!window.matchMedia && window.matchMedia("only screen and (-webkit-device-pixel-ratio: 3)").matches && iOSversion()[0] == 11) {
return true;
}
var proceed = false;
var div = document.createElement('div');
if (CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) {
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
proceed = true;
} else if (CSS.supports('padding-bottom: constant(safe-area-inset-bottom)')) {
div.style.paddingBottom = 'constant(safe-area-inset-bottom)';
proceed = true;
}
if (proceed) {
return true;
}
return false;
};
CSS是typescript的全局接口库:
interface CSS {
escape(value: string): string;
supports(property: string, value?: string): boolean;
}
declare var CSS: CSS;
或在CSS:
$margin_max_constant_notch:unquote('max(-12px, constant(safe-area-inset-left))');
$margin_max_env_notch:unquote('max(-12px, env(safe-area-inset-left))');
/*** iphone X 1.11, iphone XS (quote is OR) ***/
@media only screen
and (device-width : 375px)
and (max-device-width : 812px)
and (-webkit-device-pixel-ratio : 3),
/*** iphone XR ***/
screen and (device-width : 414px)
and (device-height : 896px)
and (-webkit-device-pixel-ratio : 2),
/*** iphone XS Max ***/
screen and (device-width : 414px)
and (device-height : 896px)
and (-webkit-device-pixel-ratio : 3),
/*** iphone XS Max Retina ***/
only screen and (-webkit-min-device-pixel-ratio: 3),
only screen and ( min--moz-device-pixel-ratio: 3),
only screen and ( -o-min-device-pixel-ratio: 3/1),
only screen and ( min-device-pixel-ratio: 3),
only screen and ( min-resolution: 458dpi),
only screen and ( min-resolution: 3dppx),
/** Google Pixel 3 XL **/
screen and (device-width: 360px)
and (device-height: 740px)
and (-webkit-min-device-pixel-ratio: 4),
only screen and ( min--moz-device-pixel-ratio: 4),
only screen and ( -o-min-device-pixel-ratio: 4/1),
only screen and ( min-device-pixel-ratio: 4),
only screen and ( min-resolution: 523dpi),
only screen and ( min-resolution: 4dppx) {
@media(orientation: portrait) {
/* mobile - vertical */
@media (max-width: 768px) {
/* up to 768px */
}
@media (max-width: 480px) {
/* up to 480px */
}
@media only screen and (max-width: 400px) {
/* up to 400px */
}
}
@media(orientation: landscape) {
html,body {
padding: $margin_max_constant_notch;
padding: $margin_max_env_notch;
}
/* mobile - horizontal */
@media screen and (max-width: 900px) {
/* up to 900px */
}
}
}
/** iphone X 1.12 **/
@supports(padding: max(0px)) {
@media screen and (device-width : 375px)
and (device-height : 812px)
and (-webkit-device-pixel-ratio : 3) {
@media(orientation: portrait) {
/* mobile - vertical */
@media (max-width: 768px) {
//até 768px
}
@media (max-width: 480px) {
/* up to 480px */
}
@media only screen and (max-width: 400px) {
/* up to 400px */
}
}
@media(orientation: landscape) {
html, body {
padding: $margin_max_constant_notch;
padding: $margin_max_env_notch;
}
@media screen and (max-width: 900px) {
/* up to 900px */
}
}
}
}
/** iphone 8 **/
@media only screen
and (device-width : 375px)
and (device-height : 667px)
and (-webkit-device-pixel-ratio : 2),
/** iphone 8 PLUS **/
screen and (device-width : 414px)
and (device-height : 736px)
and (-webkit-device-pixel-ratio : 3) {
@media(orientation: portrait) {
/* mobile - vertical */
}
@media(orientation: landscape) {
/* mobile - horizontal */
}
}
@media only screen
/** IPADS **/
and (min-device-width: 1024px)
and (max-device-width: 1366px)
and (-webkit-min-device-pixel-ratio: 2) {
/* for ipads */
@media(orientation: portrait) {
/* ipad - vertical */
}
@media(orientation: landscape) {
/* ipad - horizontal */
}
}
我最近打了这个。您可以将 CSS 环境变量 (env()) 的值设置为 CSS 自定义 属性,然后通过 JavaScript:
读取该值
CSS:
:root {
--sat: env(safe-area-inset-top);
--sar: env(safe-area-inset-right);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
}
JS:
getComputedStyle(document.documentElement).getPropertyValue("--sat")
添加notch-detected-event(0.7k纯JS)
如果检测到缺口,它会将 HTML5 data attributes 添加到 HTML 元素:
<html data-notch="true" data-orientation="portrait">
允许您使用 CSS:
调整布局
/* make room for the notch at the top */
html[data-notch="true"][data-orientation="portrait"] body {
padding-top: 44px;
height: calc(100% - 44px);
}
/* make room for the notch at the sides */
html[data-notch="true"][data-orientation="landscape"] body {
padding-left: 44px;
padding-right: 44px;
width: calc(100% - 44px - 44px);
}
或者监听 notch-detected 事件并执行一些 JS:
window.addEventListener('notch-detected', function(e) {
console.log("Notch detected, move shit around");
});
随着 iPhone X 的发布迫在眉睫,我正努力领先于游戏并准备我的一些 Web 应用程序来处理任何设计更改 - 其中最大的是新的 "notch" 前置摄像头。
我想知道在 Javascript 中是否有或可能有任何检测方法。
有趣的是,Chris Coyier 写了一篇关于 The "Notch" and CSS 的文章,它让我发现了 safe-area-inset-right
常量。有什么方法可以在 Javascript 中访问它,这是一个可靠的测试吗?
if (window.constant.safeAreaInsetRight) {
var notch = true;
}
这可能有点老套,但是,获取屏幕可用的高度和宽度并将它们与此规格匹配将使我们能够确定它是否是 iPhone X。
请注意
In portrait orientation, the width of the display on iPhone X matches the width of the 4.7" displays of iPhone 6, iPhone 7, and iPhone 8. The display on iPhone X, however, is 145pt taller than a 4.7" display...
所以,首先,你要通过 userAgent 检查它是否是 iPhone,其次你要检查实际屏幕的区域(不包括默认为纵向的方向),最后,一旦我们通过它的屏幕尺寸知道它是一个 iPhoneX,您可以确定方向(基于上面 iPhone X 图下的 table)
if (navigator.userAgent.match(/(iPhone)/)){
if((screen.availHeight == 812) && (screen.availWidth == 375)){
if((window.innerHeight == "375") && (window.innerWidth == "812")){
// iPhone X Landscape
}else{
// iPhone X Portrait
}
}
}
References:
至于CSS的解决方法,我昨天找到了一篇有趣的文章,可能会有用
Let’s say you have a fixed position header bar, and your CSS for iOS 10 currently looks like this:
header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 44px;
padding-top: 20px; /* Status bar height */
}
To make that adjust automatically for iPhone X and other iOS 11 devices, you would add a viewport-fit=cover option to your viewport meta tag, and change the CSS to reference the constant:
header {
/* ... */
/* Status bar height on iOS 10 */
padding-top: 20px;
/* Status bar height on iOS 11+ */
padding-top: constant(safe-area-inset-top);
}
It’s important to keep the fallback value there for older devices that won’t know how to interpret the constant() syntax. You can also use constants in CSS calc() expressions.
// iphone X detection
function hasNotch() {
if (CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) {
let div = document.createElement('div');
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
document.body.appendChild(div);
let calculatedPadding = parseInt(window.getComputedStyle(div).paddingBottom, 10);
document.body.removeChild(div);
if (calculatedPadding > 0) {
return true;
}
}
return false;
}
由于@youssef-makboul 的回答和@hjellek 的评论,iOS 已从 constant() 更改为 env() 语法,需要回退以在所有当前 iPhone X iOS 个版本。
const hasNotch = function () {
var proceed = false;
var div = document.createElement('div');
if (CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) {
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
proceed = true;
} else if (CSS.supports('padding-bottom: constant(safe-area-inset-bottom)')) {
div.style.paddingBottom = 'constant(safe-area-inset-bottom)';
proceed = true;
}
if (proceed) {
document.body.appendChild(div);
let calculatedPadding = parseInt(window.getComputedStyle(div).paddingBottom);
document.body.removeChild(div);
if (calculatedPadding > 0) {
return true;
}
}
return false;
};
要补充的几件事:
确保您的 index.html
中包含以下内容<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
此外:
这里有很棒的文章:CSS Tricks Notch
我正在使用这个:
function hasNotch() {
//iphone X 1.11
if (document.documentElement.clientHeight == 812 && document.documentElement.clientHeight == 375 && !!window.matchMedia && window.matchMedia("only screen and (-webkit-device-pixel-ratio: 3)").matches && iOSversion()[0] == 11) {
return true;
}
var proceed = false;
var div = document.createElement('div');
if (CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) {
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
proceed = true;
} else if (CSS.supports('padding-bottom: constant(safe-area-inset-bottom)')) {
div.style.paddingBottom = 'constant(safe-area-inset-bottom)';
proceed = true;
}
if (proceed) {
return true;
}
return false;
};
CSS是typescript的全局接口库:
interface CSS {
escape(value: string): string;
supports(property: string, value?: string): boolean;
}
declare var CSS: CSS;
或在CSS:
$margin_max_constant_notch:unquote('max(-12px, constant(safe-area-inset-left))');
$margin_max_env_notch:unquote('max(-12px, env(safe-area-inset-left))');
/*** iphone X 1.11, iphone XS (quote is OR) ***/
@media only screen
and (device-width : 375px)
and (max-device-width : 812px)
and (-webkit-device-pixel-ratio : 3),
/*** iphone XR ***/
screen and (device-width : 414px)
and (device-height : 896px)
and (-webkit-device-pixel-ratio : 2),
/*** iphone XS Max ***/
screen and (device-width : 414px)
and (device-height : 896px)
and (-webkit-device-pixel-ratio : 3),
/*** iphone XS Max Retina ***/
only screen and (-webkit-min-device-pixel-ratio: 3),
only screen and ( min--moz-device-pixel-ratio: 3),
only screen and ( -o-min-device-pixel-ratio: 3/1),
only screen and ( min-device-pixel-ratio: 3),
only screen and ( min-resolution: 458dpi),
only screen and ( min-resolution: 3dppx),
/** Google Pixel 3 XL **/
screen and (device-width: 360px)
and (device-height: 740px)
and (-webkit-min-device-pixel-ratio: 4),
only screen and ( min--moz-device-pixel-ratio: 4),
only screen and ( -o-min-device-pixel-ratio: 4/1),
only screen and ( min-device-pixel-ratio: 4),
only screen and ( min-resolution: 523dpi),
only screen and ( min-resolution: 4dppx) {
@media(orientation: portrait) {
/* mobile - vertical */
@media (max-width: 768px) {
/* up to 768px */
}
@media (max-width: 480px) {
/* up to 480px */
}
@media only screen and (max-width: 400px) {
/* up to 400px */
}
}
@media(orientation: landscape) {
html,body {
padding: $margin_max_constant_notch;
padding: $margin_max_env_notch;
}
/* mobile - horizontal */
@media screen and (max-width: 900px) {
/* up to 900px */
}
}
}
/** iphone X 1.12 **/
@supports(padding: max(0px)) {
@media screen and (device-width : 375px)
and (device-height : 812px)
and (-webkit-device-pixel-ratio : 3) {
@media(orientation: portrait) {
/* mobile - vertical */
@media (max-width: 768px) {
//até 768px
}
@media (max-width: 480px) {
/* up to 480px */
}
@media only screen and (max-width: 400px) {
/* up to 400px */
}
}
@media(orientation: landscape) {
html, body {
padding: $margin_max_constant_notch;
padding: $margin_max_env_notch;
}
@media screen and (max-width: 900px) {
/* up to 900px */
}
}
}
}
/** iphone 8 **/
@media only screen
and (device-width : 375px)
and (device-height : 667px)
and (-webkit-device-pixel-ratio : 2),
/** iphone 8 PLUS **/
screen and (device-width : 414px)
and (device-height : 736px)
and (-webkit-device-pixel-ratio : 3) {
@media(orientation: portrait) {
/* mobile - vertical */
}
@media(orientation: landscape) {
/* mobile - horizontal */
}
}
@media only screen
/** IPADS **/
and (min-device-width: 1024px)
and (max-device-width: 1366px)
and (-webkit-min-device-pixel-ratio: 2) {
/* for ipads */
@media(orientation: portrait) {
/* ipad - vertical */
}
@media(orientation: landscape) {
/* ipad - horizontal */
}
}
我最近打了这个。您可以将 CSS 环境变量 (env()) 的值设置为 CSS 自定义 属性,然后通过 JavaScript:
读取该值CSS:
:root {
--sat: env(safe-area-inset-top);
--sar: env(safe-area-inset-right);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
}
JS:
getComputedStyle(document.documentElement).getPropertyValue("--sat")
添加notch-detected-event(0.7k纯JS)
如果检测到缺口,它会将 HTML5 data attributes 添加到 HTML 元素:
<html data-notch="true" data-orientation="portrait">
允许您使用 CSS:
调整布局/* make room for the notch at the top */
html[data-notch="true"][data-orientation="portrait"] body {
padding-top: 44px;
height: calc(100% - 44px);
}
/* make room for the notch at the sides */
html[data-notch="true"][data-orientation="landscape"] body {
padding-left: 44px;
padding-right: 44px;
width: calc(100% - 44px - 44px);
}
或者监听 notch-detected 事件并执行一些 JS:
window.addEventListener('notch-detected', function(e) {
console.log("Notch detected, move shit around");
});