Cattura l'evento "zoom" del browser in JavaScript


162

È possibile rilevare, utilizzando JavaScript, quando l'utente modifica lo zoom in una pagina? Voglio semplicemente catturare un evento "zoom" e rispondere ad esso (simile all'evento window.onresize).

Grazie.


13
Credo che i browser più recenti attivino l'evento onresize quando la pagina viene ingrandita.
epascarello,

1
Ho un problema simile, ma non voglio solo sapere quando viene modificato lo zoom, ma voglio anche conoscere il valore dello zoom al caricamento della mia pagina.
Nosredna,

3
Davvero non un duplicato. La domanda qui riguarda l'acquisizione dell'evento, non la determinazione del livello di zoom.
Assaf Lavie,

5
@epascarello - sì, ma non invalida il mio commento
HorusKol il

7
Vorrei confermare che "onresize" si verifica nei browser più recenti. Finora ho visto i nuovi set di Chrome (33), FF (28), IE (11 e 11 in 9a modalità) che attivano correttamente l'evento quando si ingrandisce o si riduce.
Brock

Risposte:


77

Non c'è modo di rilevare attivamente se c'è uno zoom. Ho trovato una buona voce qui su come puoi tentare di implementarlo.

Ho trovato due modi per rilevare il livello di zoom. Un modo per rilevare le variazioni del livello di zoom si basa sul fatto che i valori percentuali non vengono ingranditi. Un valore percentuale è relativo alla larghezza della finestra e quindi non è influenzato dallo zoom della pagina. Se inserisci due elementi, uno con una posizione in percentuale e uno con la stessa posizione in pixel, si sposteranno quando viene ingrandita la pagina. Trova il rapporto tra le posizioni di entrambi gli elementi e hai il livello di zoom. Vedi test case. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

Puoi anche farlo usando gli strumenti del post sopra. Il problema è che stai più o meno facendo ipotesi ponderate sull'eventuale zoom della pagina. Funzionerà meglio in alcuni browser rispetto ad altri.

Non c'è modo di sapere se la pagina viene ingrandita se caricano la pagina durante lo zoom.


1
Si possono verificare i parametri di dimensione all'interno del gestore onload per il corpo. Curiosamente, nel debug di IE8 contro 9 sembra che il gestore onresize per il corpo passi il documento in IE8, mentre IE9 passa la finestra, così come Chrome.
Walter K,

Se si posizionano i due elementi esattamente nella stessa posizione e la pagina viene caricata durante lo zoom, non vi sarebbe uno spostamento tra i due elementi? Questo non direbbe se la pagina era già ingrandita o meno?
vijayant,

anchedocument.body.offsetWidth
Samy Bencherif il

L'uso di un metodo come questo si attiva anche quando un utente ridimensiona la finestra, quindi perché non usare semplicemente il listener di eventi di ridimensionamento? Nel qual caso è anche una soluzione praticabile.
Hewiefreeman,

12

Sto usando questo pezzo di JavaScript per reagire agli "eventi" di Zoom.
Esegue il polling della larghezza della finestra. (Come suggerito in qualche modo in questa pagina (a cui Ian Elliott si collegava): http://novemberborn.net/javascript/page-zoom-ff3 [archivio] )

Testato con Chrome, Firefox 3.6 e Opera, non IE.

Saluti, Magnus

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);
})();

8
che dire dei falsi positivi con il ridimensionamento delle finestre?
gcb,

5
Ma è possibile filtrare quei casi quando si implementa anche un gestore onresize. Quindi le basi per una soluzione sono qui direi.
Stijn de Witt,

@StijndeWitt Dopo aver letto questo sto iniziando a capire il percorso proposto, ora sto lavorando a una soluzione con il filtraggio degli eventi di ridimensionamento, specialmente sui dispositivi mobili. Chiunque?
lowtechsun

Forse potresti usare un valore di gap per differenziare il ridimensionamento e lo zoom? Voglio dire, lo zoom cambierà istantaneamente la larghezza della finestra di> x pixel.
Sebastien,

1
I falsi positivi sono un problema, sì. Non eliminerebbe il 99,99% di tutti i falsi positivi controllando se le proporzioni fossero mantenute? Chiedi allo script di ricordare l'ultimo rapporto e calcola il nuovo rapporto e controlla se sono uguali. Combina che con larghezza diversa e dovresti avere una buona base
Biepbot Von Stirling

11

Buone notizie tuttialcune persone! I browser più recenti attiveranno un evento di ridimensionamento della finestra quando si modifica lo zoom.


Chrome e Firefox per Android non attiveranno l'evento di ridimensionamento sullo zoom.
lowtechsun

5
Questa non è una buona notizia se non si desidera che lo zoom attivi l'evento di ridimensionamento.
Reahreic,

12
Le notizie migliori sarebbero un evento di zoom reale, distinto dall'evento di ridimensionamento.
Vincent,

3
Entrambi veri. Modificato.
Ben

è possibile anche impostare lo zoom in qualche modo?
oldboy,

9

Definiamo px_ratio come di seguito:

Rapporto px = rapporto tra pixel fisici e px pixel.

se uno qualsiasi ingrandisce la Pagina, il pxes del viewport (px è diverso dal pixel) si riduce e dovrebbe adattarsi allo schermo, quindi il rapporto (pixel fisico / CSS_px) deve aumentare.

ma nella finestra Ridimensionamento, la dimensione dello schermo si riduce così come i px. quindi il rapporto manterrà.

zoom: attiva l'evento windows.resize -> e modifica px_ratio

ma

ridimensionamento: attiva l'evento windows.resize -> non cambia 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;
    }
}

Il punto chiave è la differenza tra CSS PX e Physical Pixel.

https://gist.github.com/abilogos/66aba96bb0fb27ab3ed4a13245817d1e


Questa dovrebbe essere la risposta accettata IMO. Finora funziona perfettamente, grazie! Lo abbiamo inserito in un evento personalizzato se qualcuno è interessato gist.github.com/souporserious/b44ea5d04c38c2e7ff32cd1912a17cd0 .
souporserious

6

Questo funziona per me:

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

È necessario solo su IE8. Tutti gli altri browser generano naturalmente un evento di ridimensionamento.


3

È stato creato un plug-in elegante yonranche può fare il rilevamento. Ecco la sua domanda precedentemente risposta su StackOverflow. Funziona per la maggior parte dei browser. L'applicazione è semplice come questa:

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
        : "");
}

dimostrazione


Non funziona su Firefox per Android 4.4.2. Anche in FF per dispositivi mobili selezionare il Always enable zoompulsante nell'opzione Accessibilità. La demo non reagirà al cambiamento.
lowtechsun

2

Vorrei suggerire un miglioramento alla soluzione precedente con il rilevamento delle modifiche alla larghezza della finestra. Invece di mantenere il proprio array di listener di eventi, è possibile utilizzare il sistema di eventi javascript esistente e attivare il proprio evento in caso di modifica della larghezza e associare i gestori di eventi ad esso.

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

function pollZoomFireEvent() 
{ 

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

Acceleratore / rimbalzo può aiutare a ridurre la frequenza delle chiamate del gestore.


1
Acceleratore / rimbalzo è utile solo se il polling è attivato da altri eventi (ad es. Movimento del mouse o keyup).
fuzzy:

1

Puoi anche ottenere gli eventi di ridimensionamento del testo e il fattore di zoom iniettando un div contenente almeno uno spazio non interrompibile (possibilmente, nascosto) e controllando regolarmente la sua altezza. Se l'altezza cambia, la dimensione del testo è cambiata, (e sai quanto - anche questo si attiva, per inciso, se la finestra viene ingrandita in modalità pagina intera e otterrai comunque il fattore di zoom corretto, con la stessa altezza / rapporto di altezza).


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

1

Su iOS 10 è possibile aggiungere un listener di touchmoveeventi all'evento e rilevare se la pagina viene ingrandita con l'evento corrente.

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


1

Anche se questa è una domanda di 9 anni, il problema persiste!

Ho rilevato il ridimensionamento escludendo lo zoom in un progetto, quindi ho modificato il mio codice per farlo funzionare per rilevare sia il ridimensionamento che lo zoom in modo esclusivo l'uno dall'altro. Funziona la maggior parte delle volte, quindi se la maggior parte è abbastanza buona per il tuo progetto, questo dovrebbe essere utile! Rileva lo zoom il 100% delle volte in ciò che ho testato finora. L'unico problema è che se l'utente impazzisce (ad es. Ridimensionando spasticamente la finestra) o se la finestra è in ritardo, potrebbe attivarsi come uno zoom anziché un ridimensionamento della finestra.

Funziona rilevando una modifica window.outerWidtho window.outerHeightcome ridimensionamento della finestra mentre rileva una modifica window.innerWidtho window.innerHeightindipendente dal ridimensionamento della finestra come zoom.

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

Nota: la mia soluzione è come quella di KajMagnus, ma per me ha funzionato meglio.


2
Non voterò verso il basso perché vedo che hai una soluzione che funziona e capisco cosa fa il tuo codice, ma non consiglierei di usare un numero magico come 0.05senza almeno fornire una buona spiegazione. ;-) Ad esempio, so che in Chrome, in particolare, il 10% è la quantità minima che il browser eseguirà lo zoom in ogni caso, ma non è chiaro che questo sia vero per altri browser. a proposito, assicurati sempre che il tuo codice sia testato e preparati a difenderlo o migliorarlo.
Nolo,

approccio interessante
oldboy

1

Ecco una soluzione pulita:

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


questa sembra una soluzione piuttosto carina, e con un proxy non avresti nemmeno bisogno di ostruire la proprietà della vedova con il tuo intercettore - sappiamo con certezza che l'aggiornamento del DPR è ciò che tutti i browser fanno / dovrebbero fare quando l'utente ha ingrandito? ehm ... gratta l'idea - non è possibile eseguire il proxy della finestra, forse esiste una soluzione utilizzando "matchMedia" ma poiché è solo una cosa vera / falsa, non sono sicuro di come testeresti le modifiche a un valore analogico come il DPR ...
Jon z

0

L'evento di ridimensionamento funziona sui browser moderni collegando l'evento windowe quindi leggendo i valori bodydell'elemento, o altro, ad esempio ( .getBoundingClientRect () ).

In alcuni browser precedenti era possibile registrare i gestori di eventi di ridimensionamento su qualsiasi elemento HTML. È ancora possibile impostare attributi onresize o utilizzare addEventListener () per impostare un gestore su qualsiasi elemento. Tuttavia, gli eventi di ridimensionamento vengono generati solo sull'oggetto window (ovvero restituito da document.defaultView). Solo i gestori registrati sull'oggetto window riceveranno eventi di ridimensionamento .

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

Un'altra alternativa : l'API ResizeObserver

A seconda del layout, puoi guardare per ridimensionare un elemento particolare.

Funziona bene su layout «reattivi», perché il riquadro contenitore viene ridimensionato durante lo zoom.

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>


Fare attenzione a non sovraccaricare le attività javascript dagli eventi dei gesti degli utenti. Utilizzare requestAnimationFrame ogni volta che è necessario ridisegnare.


0

Secondo MDN, "matchMedia" è il modo corretto di farlo https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

è un po 'pignolo perché ogni istanza può guardare solo un MQ alla volta, quindi se sei interessato a qualsiasi modifica del livello di zoom devi fare un sacco di abbinamenti .. ma poiché il browser è responsabile dell'emissione degli eventi è probabilmente ancora più performante del polling e potresti rallentare o rimbalzare il callback o appuntarlo a un frame di animazione o qualcosa del genere - ecco un'implementazione che sembra piuttosto scattante, sentiti libero di scambiare in _throttle o qualunque altra cosa se sei già dipendente da quello.

Esegui lo snippet di codice e ingrandisci e rimpicciolisci nel tuo browser, osserva il valore aggiornato nel markup: l'ho provato solo su Firefox! fammi sapere se riscontri problemi.

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>


-4

Sto rispondendo a un link di 3 anni, ma immagino che qui sia una risposta più accettabile,

Crea il file .css come,

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

PER ESEMPIO:-

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

Il codice sopra riportato rende la dimensione del carattere '10px' quando lo schermo viene ingrandito a circa il 125%. Puoi controllare diversi livelli di zoom cambiando il valore di '1000px'.


Qual è la relazione tra il max-widthrapporto di zoom e?
SeeBiscuit,

Questo codice verrà eseguito su ogni schermata <1000 px e non ha nulla a che fare con lo zoom
Artur Stary,

@ArturStary non c'è modo di rilevare se il browser è ingrandito ma ci sono molte soluzioni alternative e uno di questi è quello che ho menzionato nella mia risposta. Inoltre, ho detto che è possibile modificare il valore di 1000 px per verificare la presenza di schermi di dimensioni diverse che daranno l'effetto di un diverso livello di zoom
Saumil,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.