javascript

Новое API браузера, определение масштаба отображения (и не только)

  • среда, 4 октября 2017 г. в 03:13:58
https://habrahabr.ru/post/339256/
  • JavaScript


image

В веб-разработке нередки моменты, когда требуется отслеживать что именно видит на своём устройстве пользователь. В первую очередь это относится, конечно, к масштабу устройства.
Я работаю над встраиваемой мини-CRM и понятия не имею как будет выглядеть сайт. Внизу страницы плавает элемент управления, всегда занимающий комфортную для касания часть экрана. Вряд ли пользователь мобильного телефона будет увеличивать масштаб чтобы оценить эстетику шрифта нашем виджете, а вот чтобы разобрать текст неоптимизированного для мобильных устройств сайта — запросто. Поэтому, чтобы не перекрывать пользователю содержимое сайта, виджет прячется при масштабировании.

Сейчас задача определения масштаба решается, мягко говоря, непросто, и появление нормального API было бы весьма кстати.

Если вкратце, нормального метода для определения масштаба попросту говоря нет. Все существующие основаны на замере отношения линейных размеров элемента с шириной 100% к размеру экрана, что-то вроде

var scale = div1.сlientWidth / document.documentElement.clientWidth;


Но работает это не всегда и с оговорками. Например, скроллбар может сильно спутать карты.

Ещё один вариант — отношение window.innerWidth / window.outerWidth. Мобильные браузеры смеются над этим приёмом. Большинство. А для некоторых работает.

Вообще всем известно, что Javascript-разработчик должен страдать. Чтобы понять актуальность темы предлагаю вам ознакомиться с этим вопросом на Stackoverflow

Выход visualViewport API решает все подобные проблемы. К сожалению, совместимость пока что никакая, хотя все крупные браузеры планируют поддерживать эту фичу. Тем не менее, лично я счёл необходимым поменять код проекта таким образом, чтобы текущие методы проверки срабатывали только если браузер не поддерживает visualViewport. Очень надеюсь, что ревертить его не станут.

Интерфейс умеет немного, но очень важного и полезного. Рассмотрим его подробнее.
Все свойства, как вы наверное догадались, read-only. Никаких способов набезобразничать разработчики не предоставили. Итак, общий вид:

 visualViewport = {
    double offsetLeft;
    double offsetTop;
    double pageLeft; 
    double pageTop; 
    double width; 
    double height;
    double scale;
} 

Иллюстрация номер один, гипотетический сайт парада андроидов:



Немного не по порядку, зато по важности. Свойства width и height отвечают за линейные размеры изображения с учётом масштаба, то есть сколько пикселей рендера на устройстве поместилось в ширину и высоту окна с учётом масштабирования пользователя.

Два параметра pageLeft и pageTop это координаты верхнего левого угла изображения на экране устройства. Вимание, без учёта масштаба! Возможно понятнее будет такая формулировка: pageLeft и pageTop это координаты пикселя, отображаемого верхним левым в окне, без учёта масштаба окна.

Чтобы объяснить свойства offsetLeft и offsetTop придётся снова посмотреть на парад. Мы переместили экран на группу андроидов и решили увеличить их. На экране зелёным я отметил прямоугольник до масштабирования, красным — то, что видим в окне браузера.

image

Свойства offsetLeft и offsetTop указывают смещение в пикселях левого верхнего угла масштабированного отображения относительно немасштабированного. Если вы поняли, это с первого раза то могу только поаплодировать. Если не поняли, то просто понаблюдайте за изменением этих свойств при изменении масштаба и точки просмотра.

И последнее свойство, scale. Я не смог подобрать нужную иллюстрацию, просто потому, что не знаю как это проиллюстрировать.Свойство scale возвращает отношение размера окна при width=device-width к его размеру при текущем масштабе.

Объект поддерживает интуитивно понятные события scroll и resize. Приведу пример кода чтобы лучше запомнилось:

window.visualViewport.addEventListener('scroll', () => {alert("Was scrolled!")});


Стоит отметить один нюанс — scroll, по видимому, отслеживает без каких-либо условий изменение pageLeft и pageTop, так что при масштабировании это событие тоже почти всегда происходит.

Вот собственно и всё. Долгие рассуждения про семь свойств и два события развести не получится.

К моему удивлению, появление visualViewport прошло практически незамеченным. Надеюсь что теперь обратите своё внимание на этот полезный инструмент.