Fangen Sie das "Zoom" -Ereignis des Browsers in JavaScript ab

162

Ist es möglich, mithilfe von JavaScript zu erkennen, wann der Benutzer den Zoom einer Seite ändert? Ich möchte einfach ein "Zoom" -Ereignis abfangen und darauf reagieren (ähnlich wie bei window.onresize).

Vielen Dank.

user123093
quelle
13
Ich glaube, dass die neueren Browser das Ereignis onresize auslösen, wenn die Seite gezoomt wird.
Epascarello
1
Ich habe ein ähnliches Problem, möchte aber nicht nur wissen, wann der Zoom geändert wird, sondern auch den Wert des Zooms, wenn meine Seite geladen wird.
Nosredna
3
Wirklich kein Duplikat. Hier geht es darum, das Ereignis zu erfassen und nicht die Zoomstufe zu bestimmen.
Assaf Lavie
5
@epascarello - ja, aber es macht meinen Kommentar nicht ungültig
HorusKol
7
Ich möchte bestätigen, dass in den neuesten Browsern "Onresize" auftritt. Bisher sehe ich, dass Newset Chrome (33), FF (28), IE (11 und 11 im 9. Modus) das Ereignis beim Vergrößern oder Verkleinern korrekt auslösen.
Brock

Antworten:

77

Es gibt keine Möglichkeit, aktiv zu erkennen, ob ein Zoom vorhanden ist. Ich habe hier einen guten Eintrag gefunden, wie Sie versuchen können, ihn zu implementieren.

Ich habe zwei Möglichkeiten gefunden, um die Zoomstufe zu erkennen. Eine Möglichkeit, Änderungen der Zoomstufe zu erkennen, besteht darin, dass Prozentwerte nicht gezoomt werden. Ein Prozentwert ist relativ zur Breite des Ansichtsfensters und wird daher vom Seitenzoom nicht beeinflusst. Wenn Sie zwei Elemente einfügen, eines mit einer Position in Prozent und eines mit derselben Position in Pixel, werden sie beim Zoomen der Seite auseinander verschoben. Finden Sie das Verhältnis zwischen den Positionen beider Elemente und Sie haben die Zoomstufe. Siehe Testfall. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

Sie können dies auch mit den Tools des obigen Beitrags tun. Das Problem ist, dass Sie mehr oder weniger fundierte Vermutungen anstellen, ob die Seite gezoomt wurde oder nicht. Dies funktioniert in einigen Browsern besser als in anderen.

Es gibt keine Möglichkeit festzustellen, ob die Seite gezoomt ist, wenn sie Ihre Seite beim Zoomen lädt.

Ian Elliott
quelle
1
Man kann die Größenparameter im Onload-Handler für den Körper überprüfen. Seltsamerweise scheint es beim Debuggen von IE8 vs. 9, dass dem Onresize-Handler für den Body das Dokument in IE8 übergeben wird, während IE9 das Fenster übergibt, ebenso wie Chrome.
Walter K
Wenn Sie die beiden Elemente an genau denselben Positionen platzieren und die Seite beim Zoomen geladen wird, würde es dann keine Verschiebung zwischen den beiden Elementen geben? Würde dies nicht sagen, ob die Seite bereits gezoomt wurde oder nicht?
Vijayant
auchdocument.body.offsetWidth
Samy Bencherif
Die Verwendung einer solchen Methode wird auch ausgelöst, wenn ein Benutzer die Größe des Fensters ändert. Warum also nicht einfach den Listener für die Größenänderung von Ereignissen verwenden? In diesem Fall ist es auch eine praktikable Lösung.
Hewiefreeman
12

Ich verwende dieses JavaScript, um auf Zoom- "Ereignisse" zu reagieren.
Es fragt die Fensterbreite ab. (Wie auf dieser Seite etwas vorgeschlagen (auf die Ian Elliott verlinkt hat): http://novemberborn.net/javascript/page-zoom-ff3 [Archiv] )

Getestet mit Chrome, Firefox 3.6 und Opera, nicht mit IE.

Grüße, 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);
})();
KajMagnus
quelle
8
Was ist mit den Fehlalarmen bei Fenstergrößenänderungen?
GCB
5
Sie können diese Fälle jedoch herausfiltern, wenn Sie auch einen Onresize-Handler implementieren. Die Grundlagen für eine Lösung sind also hier, würde ich sagen.
Stijn de Witt
@StijndeWitt Nachdem ich dies gelesen habe, fange ich an, den vorgeschlagenen Pfad zu verstehen. Jetzt arbeite ich an einer Lösung zum Herausfiltern von Größenänderungsereignissen, insbesondere auf Mobilgeräten. Jemand?
Lowtechsun
Vielleicht könnten Sie einen Lückenwert verwenden, um die Größe und den Zoom zu unterscheiden? Ich meine, der Zoom ändert die Fensterbreite sofort um> x Pixel.
Sebastien
1
False Positives sind ein Problem, ja. Würde es nicht 99,99% aller Fehlalarme beseitigen, indem geprüft würde, ob das Seitenverhältnis beibehalten wurde? Lassen Sie das Skript das letzte Verhältnis merken und das neue Verhältnis berechnen und prüfen, ob diese gleich sind. Kombinieren Sie das mit einer anderen Breite und Sie sollten eine gute Basis haben
Biepbot Von Stirling
11

Gute Nachrichten jedereinige Leute! Neuere Browser lösen ein Ereignis zum Ändern der Fenstergröße aus, wenn der Zoom geändert wird.

Ben
quelle
Chrome und Firefox für Android lösen das Größenänderungsereignis beim Zoomen nicht aus.
Lowtechsun
5
Dies ist keine gute Nachricht, wenn Sie nicht möchten, dass das Zoomen das Größenänderungsereignis auslöst.
Reahreic
12
Bessere Nachrichten wären ein tatsächliches Zoomereignis, das sich vom Größenänderungsereignis unterscheidet.
Vincent
3
Beides stimmt. Bearbeitet.
Ben
ist es möglich, den Zoom auch irgendwie einzustellen?
Oldboy
9

Definieren wir px_ratio wie folgt:

px-Verhältnis = Verhältnis von physischem Pixel zu CSS-px.

Wenn eine Seite gezoomt wird, werden die Pixel des Ansichtsfensters (px unterscheidet sich von Pixel) verringert und sollten an den Bildschirm angepasst werden, damit das Verhältnis (physisches Pixel / CSS_px) größer wird.

Beim Ändern der Fenstergröße wird jedoch die Bildschirmgröße ebenso reduziert wie die Pixel. so bleibt das Verhältnis erhalten.

Zoomen: Windows.resize-Ereignis auslösen -> und px_ratio ändern

aber

Größenänderung: Windows.resize-Ereignis auslösen -> ändert px_ratio nicht

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

Der entscheidende Punkt ist der Unterschied zwischen CSS PX und Physical Pixel.

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

Abilogos
quelle
Dies sollte die akzeptierte Antwort IMO sein. Funktioniert bisher einwandfrei, danke! Wenn jemand interessiert ist, wird es in ein benutzerdefiniertes Ereignis eingepackt . Gist.github.com/souporserious/b44ea5d04c38c2e7ff32cd1912a17cd0 .
suppige
6

Das funktioniert bei mir:

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

Es wird nur auf IE8 benötigt. Alle anderen Browser generieren natürlich ein Größenänderungsereignis.

Bill Keese
quelle
3

Es gibt ein geschicktes Plugin yonran, das die Erkennung übernimmt . Hier ist seine zuvor beantwortete Frage zu StackOverflow. Es funktioniert für die meisten Browser. Die Anwendung ist so einfach:

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

Demo

Starx
quelle
Funktioniert nicht unter Firefox für Android 4.4.2. Aktivieren Sie auch in FF für Handys die Always enable zoomSchaltfläche in der Option Eingabehilfen. Die Demo reagiert nicht auf die Änderung.
Lowtechsun
2

Ich möchte eine Verbesserung der vorherigen Lösung vorschlagen, indem Änderungen an der Fensterbreite nachverfolgt werden. Anstatt Ihr eigenes Array von Ereignis-Listenern beizubehalten, können Sie das vorhandene Javascript-Ereignissystem verwenden und bei einer Änderung der Breite Ihr eigenes Ereignis auslösen und Ereignishandler daran binden.

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

function pollZoomFireEvent() 
{ 

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

Gas / Entprellen kann dabei helfen, die Anrufrate Ihres Handlers zu reduzieren.

Alexey
quelle
1
Das Drosseln / Entprellen ist nur dann sinnvoll, wenn die Abfrage durch andere Ereignisse (z. B. Mausbewegung oder Tastendruck) ausgelöst wird.
FuzzyTew
1

Sie können auch die Größenänderung des Texts und den Zoomfaktor abrufen, indem Sie ein Div einfügen, das mindestens einen nicht unterbrechbaren Bereich (möglicherweise ausgeblendet) enthält, und dessen Höhe regelmäßig überprüfen. Wenn sich die Höhe ändert, hat sich die Textgröße geändert (und Sie wissen, wie viel - dies wird übrigens auch ausgelöst, wenn das Fenster im Ganzseitenmodus gezoomt wird und Sie immer noch den richtigen Zoomfaktor bei gleicher Höhe / erhalten Höhenverhältnis).

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

Unter iOS 10 ist es möglich, dem touchmoveEreignis einen Ereignis-Listener hinzuzufügen und festzustellen, ob die Seite mit dem aktuellen Ereignis gezoomt wurde.

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

alwe
quelle
1

Obwohl dies eine 9 Jahre alte Frage ist, bleibt das Problem bestehen!

Ich habe die Größenänderung erkannt, während ich das Zoomen in einem Projekt ausgeschlossen habe. Daher habe ich meinen Code so bearbeitet, dass sowohl die Größenänderung als auch das Zoomen exklusiv voneinander erkannt werden. Es funktioniert die meiste Zeit, also wenn die meisten für Ihr Projekt gut genug ist, sollte dies hilfreich sein! Es erkennt 100% der Zeit das Zoomen in dem, was ich bisher getestet habe. Das einzige Problem ist, dass wenn der Benutzer verrückt wird (dh das Fenster spastisch in der Größe ändert) oder das Fenster verzögert wird, es möglicherweise als Zoom anstelle einer Fenstergröße ausgelöst wird.

Es erkennt eine Änderung der Größe window.outerWidthoder window.outerHeightals Fenstergröße, während eine Änderung der Fenstergröße window.innerWidthoder window.innerHeightunabhängig von der Fenstergröße als Zoom erkannt wird.

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

Hinweis: Meine Lösung ist wie die von KajMagnus, aber das hat bei mir besser funktioniert.

dandeto
quelle
2
Ich werde nicht abstimmen, weil ich sehe, dass Sie eine Lösung haben, die funktioniert, und ich verstehe, was Ihr Code tut, aber ich würde nicht empfehlen, eine magische Zahl zu verwenden, z. B. 0.05ohne zumindest eine gute Erklärung zu liefern. ;-) Ich weiß zum Beispiel, dass 10% in Chrome der kleinste Betrag ist, den der Browser auf jeden Fall zoomt, aber es ist nicht klar, dass dies für andere Browser gilt. Stellen Sie immer sicher, dass Ihr Code getestet wird, und seien Sie bereit, ihn zu verteidigen oder zu verbessern.
Nolo
interessanter Ansatz
Oldboy
1

Hier ist eine saubere Lösung:

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

Fuweichin
quelle
Dies scheint eine ziemlich nette Lösung zu sein, und mit einem Proxy müssten Sie nicht einmal die Witwen-Eigenschaft mit Ihrem Interceptor überladen. Wissen wir sicher, dass das Aktualisieren des DPR das ist, was alle Browser tun / tun sollten, wenn der Benutzer gezoomt hat? äh .. kratz diese Idee - Fenster kann nicht Proxy sein, vielleicht gibt es eine Lösung mit "matchMedia", aber da es nur eine wahre / falsche Sache ist, bin ich mir nicht sicher, wie Sie auf Änderungen an einem analogen Wert wie dem testen würden DPR ...
Jon z
0

Das Größenänderungsereignis funktioniert in modernen Browsern, indem das Ereignis angehängtwindow und dann die Werte des bodyoder eines anderen Elements mit beispielsweise ( angehängt .getBoundingClientRect () ) gelesen werden .

In einigen früheren Browsern war es möglich, Größenbehandlungsereignishandler für jedes HTML-Element zu registrieren. Es ist weiterhin möglich, Attribute für die Größenänderung festzulegen oder mit addEventListener () einen Handler für ein beliebiges Element festzulegen. Größenänderungsereignisse werden jedoch nur für das Fensterobjekt ausgelöst (dh von document.defaultView zurückgegeben). Nur für das Fensterobjekt registrierte Handler erhalten Größenänderungsereignisse .

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

Eine andere Alternative : die ResizeObserver-API

Abhängig von Ihrem Layout können Sie darauf achten, die Größe eines bestimmten Elements zu ändern.

Dies funktioniert gut bei «reaktionsschnellen» Layouts, da die Größe der Containerbox beim Zoomen geändert wird.

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>


Achten Sie darauf , Javascript-Aufgaben nicht durch Benutzergestenereignisse zu überladen. Verwenden Sie requestAnimationFrame, wenn Sie Neuzeichnungen benötigen.

NVRM
quelle
0

Laut MDN ist "matchMedia" der richtige Weg, dies zu tun. Https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

Es ist ein bisschen pingelig, weil jede Instanz jeweils nur einen MQ sehen kann. Wenn Sie also daran interessiert sind einer Änderung der , müssen Sie eine Reihe von Übereinstimmungen vornehmen. Da der Browser jedoch für die Ausgabe der Ereignisse verantwortlich ist, ist dies wahrscheinlich Noch leistungsfähiger als das Abrufen, und Sie können den Rückruf drosseln oder entprellen oder an einen Animationsrahmen oder etwas anderes anheften - hier ist eine Implementierung, die ziemlich bissig erscheint. Sie können jederzeit _throttle oder was auch immer eintauschen, wenn Sie bereits davon abhängig sind.

Führen Sie das Code-Snippet aus und zoomen Sie in Ihrem Browser hinein und heraus. Beachten Sie den aktualisierten Wert im Markup - ich habe dies nur in Firefox getestet! Ich weiß, ob Sie Probleme sehen.

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>

Jon z
quelle
-4

Ich antworte auf einen 3 Jahre alten Link, aber ich denke, hier ist eine akzeptablere Antwort.

Erstellen Sie eine CSS-Datei als,

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

Z.B:-

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

Mit dem obigen Code wird die Schriftgröße auf 10 Pixel festgelegt, wenn der Bildschirm auf ca. 125% gezoomt wird. Sie können nach unterschiedlichen Zoomstufen suchen, indem Sie den Wert von '1000px' ändern.

Saumil
quelle
Wie ist die Beziehung zwischen dem max-widthund dem Zoomverhältnis?
Seebiscuit
Dieser Code wird auf jedem <1000px-Bildschirm ausgeführt und hat nichts mit Zoom zu tun
Artur Stary
@ArturStary Es gibt keine Möglichkeit zu erkennen, ob der Browser gezoomt ist, aber es gibt viele Problemumgehungen, und eine davon habe ich in meiner Antwort erwähnt. Außerdem habe ich gesagt, dass Sie den Wert von 1000px ändern können, um nach verschiedenen Bildschirmgrößen zu suchen, die den Effekt einer unterschiedlichen
Zoomstufe ergeben