Обнаружение мобильного устройства "выемка"

С запуском iPhone X неизбежно, я пытаюсь опередить игру и подготовить некоторые из своих веб-приложений для обработки любых изменений дизайна, самым большим из которых является новая "надрезка", в которой размещена передняя камера.

Мне было интересно, есть ли какие-либо способы обнаружения этого в Javascript, или, вероятно, будет каким-то образом.

Интересно, что Крис Койер написал статью о "Notch" и CSS, благодаря чему я обнаружил константу safe-area-inset-right. Есть ли способ, к которому это можно получить в Javascript, и это надежный тест.

if (window.constant.safeAreaInsetRight) {
  var notch = true;
}

Ответ 1

Это может быть немного взломанным, однако, получение доступных высот и ширины экрана и их соответствие этим спецификациям позволят нам определить, является ли это iPhone X.

Обратите внимание:

В портретной ориентации ширина дисплея на iPhone X соответствует ширину 4,7 "дисплеев iPhone 6, iPhone 7 и iPhone 8. Однако дисплей на iPhone X составляет 145pt выше, чем 4,7" дисплей...

введите описание изображения здесь

Итак, во-первых, вы хотите проверить, является ли это iPhone через userAgent, во-вторых, вы должны проверить область фактического экрана (исключая ориентацию, которая по умолчанию соответствует портрету), наконец, когда мы знаем, что это iPhoneX через его размеры экрана вы можете определить ориентацию (на основе таблицы под диаграммой iPhone X выше)

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
    }
  }
}

Ссылки:

avilHeight

avilWidth

Характеристики iPhone

Что касается решения CSS, я вчера нашел интересную статью о нем, которая может быть полезной

Предположим, у вас есть панель заголовка с фиксированной позицией, а ваш CSS для iOS 10 выглядит примерно так:

header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 44px;

    padding-top: 20px; /* Status bar height */
}

Чтобы настроить эту настройку автоматически для iPhone X и других iOS 11 устройств, вы должны добавить в свой видовой экран параметр viewport-fit = cover метатег и изменить CSS для ссылки на константу:

header {
    /* ... */

    /* Status bar height on iOS 10 */
    padding-top: 20px;

    /* Status bar height on iOS 11+ */
    padding-top: constant(safe-area-inset-top);
}

Важно сохранить резервную стоимость для более старых устройств, которые не знаю, как интерпретировать синтаксис constant(). Вы также можете использовать константы в выражениях CSS calc().

Статья

Ответ 2

// 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;
  }

Ответ 3

Так как ответ @youssef-makboul и как комментируется @hjellek, iOS изменилась с синтаксиса constant() на env(), и резерв необходим для поддержки этого подхода во всех версиях iOS iPhone 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;
};

Ответ 4

Я ударил это недавно. Вы можете установить значение переменной среды 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")

Полная информация здесь:https://benfrain.com/how-to-get-the-value-of-phone-notches-environment-variables-env-in-javascript-from-css/

Ответ 5

Несколько вещей для добавления:

Убедитесь, что у вас есть следующее в index.html

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">

Дополнительно:

Отличная статья об этом здесь: CSS Tricks Notch

Ответ 6

Я использую это:

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 это глобальная интерфейсная библиотека машинописи:

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 */
  }

}