Поймать браузер "зум" событие в JavaScript

Можно ли с помощью JavaScript определить, когда пользователь изменяет масштаб страницы? Я просто хочу поймать событие "zoom" и ответить на него (аналогично событию window.onresize).

Благодарю.

12 ответов

Решение

Там нет никакого способа, чтобы активно обнаружить, если есть зум. Здесь я нашел хорошую запись о том, как вы можете попытаться реализовать это.

Я нашел два способа определения уровня масштабирования. Один из способов обнаружения изменений уровня масштабирования основан на том факте, что процентные значения не увеличиваются. Процентное значение относится к ширине области просмотра и, следовательно, не зависит от масштаба страницы. Если вы вставите два элемента, один с позицией в процентах, а другой с одинаковой позицией в пикселях, они будут раздвигаться при увеличении страницы. Найдите соотношение между позициями обоих элементов, и вы получите уровень масштабирования. Смотрите тестовый пример. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

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

Невозможно определить, увеличена ли страница, если они загружают вашу страницу во время увеличения.

У меня была эта проблема и наконец. У меня есть решение. это просто и работает для меня. ("Mozilla/5.0 (X11; Linux x86_64;Gecko/20100101 Firefox/50.0)".

отношение px = отношение физического пикселя к CSS; при любом увеличении пиксели окна просмотра уменьшаются и должны соответствовать экрану, поэтому соотношение должно увеличиваться. но при изменении размера окна уменьшается размер экрана, а также размеры пикселей. поэтому соотношение сохранится.

масштабирование: вызвать событие windows.resize -> и изменить px_ratio resizing: изменить событие windows.resize -> не изменить px_ratio

//for zoom detection
px_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;

$(window).resize(function(){isZooming();});

function isZooming(){
    var newPx_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
    if(newPx_ratio != px_ratio){
        px_ratio = newPx_ratio;
        console.log("zooming");
        return true;
    }else{
        console.log("just resizing");
        return false;
    }
}

Хорошие новости каждый некоторые люди! Новые браузеры будут вызывать событие изменения размера окна при изменении масштаба.

Я использую этот кусок JavaScript, чтобы реагировать на "события" Zoom.
Опрашивает ширину окна. (Как несколько предложено на этой странице (на которую ссылается Ян Эллиотт): http://novemberborn.net/javascript/page-zoom-ff3 [архив])

Протестировано с Chrome, Firefox 3.6 и Opera, а не IE.

С уважением, Магнус

var zoomListeners = [];

(function(){
  // Poll the pixel width of the window; invoke zoom listeners
  // if the width has been changed.
  var lastWidth = 0;
  function pollZoomFireEvent() {
    var widthNow = jQuery(window).width();
    if (lastWidth == widthNow) return;
    lastWidth = widthNow;
    // Length changed, user must have zoomed, invoke listeners.
    for (i = zoomListeners.length - 1; i >= 0; --i) {
      zoomListeners[i]();
    }
  }
  setInterval(pollZoomFireEvent, 100);
})();

Это работает для меня:

        var deviceXDPI = screen.deviceXDPI;
        setInterval(function(){
            if(screen.deviceXDPI != deviceXDPI){
                deviceXDPI = screen.deviceXDPI;
                ... there was a resize ...
            }
        }, 500);

Это нужно только на IE8. Все остальные браузеры, естественно, генерируют событие изменения размера.

Хотя это 9-летний вопрос, проблема сохраняется!

Я обнаружил изменение размера при исключении увеличения в проекте, поэтому я отредактировал свой код, чтобы он работал для определения как изменения размера, так и изменения масштаба друг от друга. Это работает большую часть времени, поэтому, если большинство достаточно хорошо для вашего проекта, то это должно быть полезно! Он обнаруживает увеличение в 100% случаев в том, что я тестировал до сих пор. Единственная проблема заключается в том, что если пользователь сходит с ума (то есть из-за резкого изменения размера окна) или задержки окна, он может срабатывать как увеличение вместо изменения размера окна.

Это работает, обнаруживая изменение в window.outerWidth или же window.outerHeight как изменение размера окна при обнаружении изменения в window.innerWidth или же window.innerHeight независимо от изменения размера окна в качестве увеличения.

//init object to store window properties
var windowSize = {
  w: window.outerWidth,
  h: window.outerHeight,
  iw: window.innerWidth,
  ih: window.innerHeight
};

window.addEventListener("resize", function() {
  //if window resizes
  if (window.outerWidth !== windowSize.w || window.outerHeight !== windowSize.h) {
    windowSize.w = window.outerWidth; // update object with current window properties
    windowSize.h = window.outerHeight;
    windowSize.iw = window.innerWidth;
    windowSize.ih = window.innerHeight;
    console.log("you're resizing"); //output
  }
  //if the window doesn't resize but the content inside does by + or - 5%
  else if (window.innerWidth + window.innerWidth * .05 < windowSize.iw ||
    window.innerWidth - window.innerWidth * .05 > windowSize.iw) {
    console.log("you're zooming")
    windowSize.iw = window.innerWidth;
  }
}, false);

Примечание: мое решение похоже на решение KajMagnus, но для меня это сработало лучше.

Есть отличный плагин, построенный из yonran что может сделать обнаружение. Вот его ранее отвеченный вопрос о Stackru. Это работает для большинства браузеров. Приложение так просто, как это:

window.onresize = function onresize() {
  var r = DetectZoom.ratios();
  zoomLevel.innerHTML =
    "Zoom level: " + r.zoom +
    (r.zoom !== r.devicePxPerCssPx
        ? "; device to CSS pixel ratio: " + r.devicePxPerCssPx
        : "");
}

демонстрация

Согласно MDN, "matchMedia" - правильный способ сделать это https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio

это немного привередливо, потому что каждый экземпляр может просматривать только один MQ за раз, поэтому, если вас интересует какое-либо изменение уровня масштабирования, вам нужно сделать кучу сопоставлений... но поскольку браузер отвечает за создание событий, это, вероятно, все еще более производительный, чем опрос, и вы можете задросселировать или отклонять обратный вызов или прикреплять его к кадру анимации или чему-то еще - вот реализация, которая кажется довольно быстрой, не стесняйтесь менять _throttle или что-то еще, если вы уже зависите от этого.

Запустите фрагмент кода и увеличивайте и уменьшайте масштаб в браузере, обратите внимание на обновленное значение в разметке - я тестировал это только в Firefox! дайте мне знать, если вы заметите какие-либо проблемы.

const el = document.querySelector('#dppx')

if ('matchMedia' in window) {
  function observeZoom(cb, opts) {
    opts = {
      // first pass for defaults - range and granularity to capture all the zoom levels in desktop firefox
      ceiling: 3,
      floor: 0.3,
      granularity: 0.05,
      ...opts
    }
    const precision = `${opts.granularity}`.split('.')[1].length

    let val = opts.floor
    const vals = []
    while (val <= opts.ceiling) {
      vals.push(val)
      val = parseFloat((val + opts.granularity).toFixed(precision))
    }

    // construct a number of mediamatchers and assign CB to all of them
    const mqls = vals.map(v => matchMedia(`(min-resolution: ${v}dppx)`))

    // poor person's throttle
    const throttle = 3
    let last = performance.now()
    mqls.forEach(mql => mql.addListener(function() {
      console.debug(this, arguments)
      const now = performance.now()
      if (now - last > throttle) {
        cb()
        last = now
      }
    }))
  }

  observeZoom(function() {
    el.innerText = window.devicePixelRatio
  })
} else {
  el.innerText = 'unable to observe zoom level changes, matchMedia is not supported'
}
<div id='dppx'>--</div>

Событие изменения размера работает в современных браузерах, прикрепляя событие кwindow, а затем считывая значенияbody, или другой элемент, например (.getBoundingClientRect()).

В некоторых более ранних браузерах можно было зарегистрировать обработчики событий изменения размера для любого элемента HTML. По-прежнему можно установить атрибуты onresize или использовать addEventListener() для установки обработчика для любого элемента. Однако события изменения размера запускаются только для объекта окна (то есть возвращаются document.defaultView). Только обработчики, зарегистрированные в объекте окна, будут получать события изменения размера.

window.addEventListener("resize", getSizes, false)
        
function getSizes(){
  let body = document.body
  console.log(body.clientWidth +"px x "+ body.clientHeight + "px")
}

Другая альтернатива: API ResizeObserver

В зависимости от вашего макета вы можете следить за изменением размера конкретного элемента.

Это хорошо работает с "адаптивными" макетами, потому что размер контейнера изменяется при масштабировании.

function watchBoxchange(e){
 // console.log(e[0].contentBoxSize.inlineSize+" "+e[0].contentBoxSize.blockSize)
 info.textContent = e[0].contentBoxSize.inlineSize+" * "+e[0].contentBoxSize.blockSize + "px"
}

new ResizeObserver(watchBoxchange).observe(fluid)
#fluid {
  width: 200px;
  height:100px;
  overflow: auto;
  resize: both;
  border: 3px black solid;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-size: 8vh
}
<div id="fluid">
   <info id="info"></info> 
</div>


Будьте осторожны, чтобы не перегружать задачи javascript событиями пользовательских жестов. Используйте requestAnimationFrame всякий раз, когда вам нужно перерисовать.

Вот чистое решение:

// polyfill window.devicePixelRatio for IE
if(!window.devicePixelRatio){
  Object.defineProperty(window,'devicePixelRatio',{
    enumerable: true,
    configurable: true,
    get:function(){
      return screen.deviceXDPI/screen.logicalXDPI;
    }
  });
}
var oldValue=window.devicePixelRatio;
window.addEventListener('resize',function(e){
  var newValue=window.devicePixelRatio;
  if(newValue!==oldValue){
    // TODO polyfill CustomEvent for IE
    var event=new CustomEvent('devicepixelratiochange');
    event.oldValue=oldValue;
    event.newValue=newValue;
    oldValue=newValue;
    window.dispatchEvent(event);
  }
});

window.addEventListener('devicepixelratiochange',function(e){
  console.log('devicePixelRatio changed from '+e.oldValue+' to '+e.newValue);
});

Я хотел бы предложить улучшение предыдущего решения с отслеживанием изменений ширины окна. Вместо сохранения собственного массива слушателей событий вы можете использовать существующую систему событий javascript и запускать собственное событие при изменении ширины, а также привязывать к нему обработчики событий.

$(window).bind('myZoomEvent', function() { ... });

function pollZoomFireEvent() 
{ 

    if ( ... width changed ... ) {
        $(window).trigger('myZoomEvent');
    }
}

Throttle / debounce может помочь в снижении скорости вызовов вашего обработчика.

На iOS 10 можно добавить прослушиватель событий в touchmove событие и определить, масштабируется ли страница с текущим событием.

var prevZoomFactorX;
var prevZoomFactorY;
element.addEventListener("touchmove", (ev) => {
  let zoomFactorX = document.documentElement.clientWidth / window.innerWidth;
  let zoomFactorY = document.documentElement.clientHeight / window.innerHeight;
  let pageHasZoom = !(zoomFactorX === 1 && zoomFactorY === 1);

  if(pageHasZoom) {
    // page is zoomed
    
    if(zoomFactorX !== prevZoomFactorX || zoomFactorY !== prevZoomFactorY) {
      // page is zoomed with this event
    }
  }
  prevZoomFactorX = zoomFactorX;
  prevZoomFactorY = zoomFactorY;
});

<script>
var zoomv = function() {
  if(topRightqs.style.width=='200px){
  alert ("zoom");
  }
};
zoomv();
</script>

Вы также можете получить события изменения размера текста и коэффициент масштабирования, введя элемент div, содержащий по крайней мере неразрывный пробел (возможно, скрытый), и регулярно проверяя его высоту. Если высота изменяется, размер текста изменился (и вы знаете, сколько - это также срабатывает, кстати, если окно масштабируется в полностраничном режиме, и вы все равно получите правильный коэффициент масштабирования с той же высотой / соотношение высоты).

Вот собственный способ (основные фреймворки не могут масштабировать Chrome, потому что они не поддерживают пассивное поведение событий)


//For Google Chrome
document.addEventListener("mousewheel", event => {
  console.log(`wheel`);
  if(event.ctrlKey == true)
  {
    event.preventDefault();
    if(event.deltaY > 0) {
      console.log('Down');
    }else {
      console.log('Up');
    }
  }
}, { passive: false });

// For Mozilla Firefox
document.addEventListener("DOMMouseScroll", event => {
  console.log(`wheel`);
  if(event.ctrlKey == true)
  {
    event.preventDefault();
    if(event.detail > 0) {
      console.log('Down');
    }else {
      console.log('Up');
    }
  }
}, { passive: false });

Я отвечаю на 3-летнюю ссылку, но я думаю, что это более приемлемый ответ,

Создайте файл.css как,

@media screen and (max-width: 1000px) 
{
       // things you want to trigger when the screen is zoomed
}

НАПРИМЕР:-

@media screen and (max-width: 1000px) 
{
    .classname
    {
          font-size:10px;
    }
}

Приведенный выше код делает размер шрифта "10 пикселей", когда экран увеличен примерно до 125%. Вы можете проверить другой уровень масштабирования, изменив значение "1000px".

Другие вопросы по тегам