Złap zdarzenie „powiększenia” przeglądarki w JavaScript

162

Czy za pomocą JavaScript można wykryć, kiedy użytkownik zmienia powiększenie strony? Chcę po prostu złapać zdarzenie „zoom” i odpowiedzieć na nie (podobnie do zdarzenia window.onresize).

Dzięki.

user123093
źródło
13
Uważam, że nowsze przeglądarki uruchamiają zdarzenie onresize, gdy strona jest powiększana.
epascarello
1
Mam podobny problem, ale nie chcę tylko wiedzieć, kiedy zmienia się powiększenie, chcę też znać wartość powiększenia, gdy moja strona się ładuje.
Nosredna
3
Naprawdę nie jest duplikatem. Tutaj chodzi o złapanie zdarzenia, a nie o określenie poziomu przybliżenia.
Assaf Lavie
5
@epascarello - tak, ale to nie unieważnia mojego komentarza
HorusKol
7
Chciałbym potwierdzić, że w najnowszych przeglądarkach występuje zmiana rozmiaru. Jak dotąd widzę, że nowości Chrome (33), FF (28), IE (11 i 11 w trybie dziewiątym) poprawnie uruchamiają zdarzenie podczas powiększania lub pomniejszania.
Brock

Odpowiedzi:

77

Nie ma sposobu, aby aktywnie wykryć, czy istnieje powiększenie. Znalazłem tutaj dobry wpis o tym, jak możesz spróbować go wdrożyć.

Znalazłem dwa sposoby wykrywania poziomu powiększenia. Jeden ze sposobów wykrywania zmian poziomu powiększenia polega na tym, że wartości procentowe nie są powiększane. Wartość procentowa odnosi się do szerokości rzutni, a zatem nie ma wpływu na powiększenie strony. Jeśli wstawisz dwa elementy, jeden z pozycją w procentach, a drugi z tą samą pozycją w pikselach, będą się one rozsuwały po powiększeniu strony. Znajdź stosunek między pozycjami obu elementów i masz poziom powiększenia. Zobacz przypadek testowy. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

Możesz to również zrobić za pomocą narzędzi z powyższego postu. Problem polega na tym, że w mniejszym lub większym stopniu dokonujesz przemyślanych przypuszczeń, czy strona została powiększona. W niektórych przeglądarkach będzie to działać lepiej niż w innych.

Nie ma sposobu, aby stwierdzić, czy strona jest powiększona, jeśli wczytują ją podczas powiększania.

Ian Elliott
źródło
1
Można sprawdzić parametry rozmiaru wewnątrz procedury obsługi ładowania dla ciała. Co ciekawe, podczas debugowania IE8 w porównaniu z 9 wydaje się, że program obsługi zmiany rozmiaru treści jest przekazywany do dokumentu w IE8, podczas gdy IE9 przekazuje okno, podobnie jak Chrome.
Walter K
Jeśli umieścisz dwa elementy w dokładnie tych samych pozycjach, a strona zostanie załadowana podczas powiększania, czy nie wystąpi przesunięcie między dwoma elementami? Czy to nie powiedziałoby, czy strona została już powiększona, czy nie?
vijayant
takżedocument.body.offsetWidth
Samy Bencherif
Użycie takiej metody spowoduje również uruchomienie, gdy użytkownik zmieni rozmiar okna, więc dlaczego nie użyć po prostu detektora zdarzeń zmiany rozmiaru? W takim przypadku jest to również realne rozwiązanie.
hewiefreeman
12

Używam tego fragmentu JavaScript do reagowania na „zdarzenia” Zoom.
Sonduje szerokość okna. (Jak sugerowano na tej stronie (do której odsyłał Ian Elliott): http://novemberborn.net/javascript/page-zoom-ff3 [archiwum] )

Testowane w Chrome, Firefox 3.6 i Opera, a nie w IE.

Pozdrawiam 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
źródło
8
co z fałszywymi alarmami przy zmianie rozmiaru okna?
gcb
5
Ale możesz odfiltrować te przypadki, gdy zaimplementujesz również procedurę obsługi zmiany rozmiaru. Więc powiedziałbym, że podstawy rozwiązania są tutaj.
Stijn de Witt
@StijndeWitt Po przeczytaniu tego zaczynam rozumieć proponowaną ścieżkę, teraz pracuję nad rozwiązaniem z filtrowaniem zdarzeń zmiany rozmiaru, zwłaszcza na urządzeniach mobilnych. Ktoś?
lowtechsun
Może warto użyć wartości przerwy, aby odróżnić zmianę rozmiaru i powiększenie? Mam na myśli, że powiększenie natychmiast zmieni szerokość okna o> x pikseli.
Sebastien,
1
Fałszywe pozytywy to problem, tak. Czy nie wyeliminowałoby 99,99% wszystkich fałszywych trafień, sprawdzając, czy współczynnik proporcji został zachowany? Niech skrypt zapamięta ostatni współczynnik i obliczy nowy współczynnik i sprawdź, czy są takie same. Połącz to z inną szerokością i powinieneś mieć dobrą podstawę
Biepbot Von Stirling
11

Dobre wieści wszyscyniektórzy ludzie! Nowsze przeglądarki wyzwalają zdarzenie zmiany rozmiaru okna po zmianie powiększenia.

Ben
źródło
Chrome i Firefox dla Androida nie wyzwalają zdarzenia zmiany rozmiaru podczas powiększania.
lowtechsun
5
To nie jest dobra wiadomość, jeśli nie chcesz, aby powiększanie wywoływało zdarzenie zmiany rozmiaru.
Reahreic
12
Lepszą wiadomością byłoby faktyczne zdarzenie powiększenia, różniące się od zdarzenia zmiany rozmiaru.
Vincent
3
Obie prawdziwe. Edytowano.
Ben
czy można jakoś ustawić zoom?
oldboy
9

Określmy px_ratio jak poniżej:

współczynnik px = stosunek pikseli fizycznych do pikseli css.

jeśli któryś z powiększa Strona, piksele widoku (piksele różnią się od pikseli) zmniejszają się i powinny być dopasowane do ekranu, więc współczynnik (piksel fizyczny / CSS_px) musi się zwiększyć.

ale przy zmianie rozmiaru okna rozmiar ekranu zmniejsza się, podobnie jak piksele. więc stosunek się utrzyma.

powiększanie: uruchamianie zdarzenia windows.resize -> i zmiana px_ratio

ale

resizing: wyzwalanie zdarzenia windows.resize -> nie zmienia 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;
    }
}

Kluczową kwestią jest różnica między CSS PX a Physical Pixel.

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

Abilogos
źródło
To powinna być akceptowana odpowiedź IMO. Jak dotąd działa bez zarzutu, dzięki! Jeśli ktoś jest zainteresowany, zapakuj go w wydarzenie niestandardowe . Gist.github.com/souporserious/b44ea5d04c38c2e7ff32cd1912a17cd0 .
goryczkowy
6

To działa dla mnie:

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

Jest potrzebny tylko w IE8. Wszystkie inne przeglądarki w naturalny sposób generują zdarzenie zmiany rozmiaru.

Bill Keese
źródło
3

Istnieje sprytna wtyczka, yonranktóra umożliwia wykrywanie. Oto jego wcześniej udzielone pytanie w StackOverflow. Działa w większości przeglądarek. Aplikacja jest tak prosta:

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

Próbny

Starx
źródło
Nie działa w Firefoksie na Androida 4.4.2. Również w FF na urządzenia mobilne zaznacz Always enable zoomprzycisk w opcji Dostępność. Demo nie zareaguje na zmianę.
lowtechsun
2

Chciałbym zasugerować ulepszenie do poprzedniego rozwiązania ze śledzeniem zmian szerokości okna. Zamiast utrzymywać własną tablicę detektorów zdarzeń, możesz użyć istniejącego systemu zdarzeń javascript i wyzwolić własne zdarzenie po zmianie szerokości i powiązać z nim procedury obsługi zdarzeń.

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

function pollZoomFireEvent() 
{ 

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

Ograniczenie / odrzucenie może pomóc w zmniejszeniu wskaźnika wywołań twojego handlera.

Alexey
źródło
1
Throttle / debounce jest przydatne tylko wtedy, gdy odpytywanie jest wywoływane przez inne zdarzenia (np. Ruch myszy lub naciśnięcie klawisza).
fuzzyTew
1

Możesz również uzyskać zdarzenia zmiany rozmiaru tekstu i współczynnik powiększenia, wstawiając element div zawierający co najmniej nierozerwalną spację (prawdopodobnie ukrytą) i regularnie sprawdzając jego wysokość. Jeśli zmienia się wysokość, zmienił się rozmiar tekstu (i wiesz ile - to również uruchamia się, nawiasem mówiąc, jeśli okno zostanie powiększone w trybie pełnej strony, a nadal uzyskasz prawidłowy współczynnik powiększenia, o tej samej wysokości / stosunek wysokości).

Argo
źródło
1
<script>
var zoomv = function() {
  if(topRightqs.style.width=='200px){
  alert ("zoom");
  }
};
zoomv();
</script>
SchoolforDesign
źródło
1

W iOS 10 można dodać detektor zdarzenia do touchmovezdarzenia i wykryć, czy strona jest powiększona o aktualne zdarzenie.

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
źródło
1

Chociaż jest to pytanie sprzed 9 lat, problem nadal występuje!

Wykrywałem zmianę rozmiaru, jednocześnie wykluczając powiększenie projektu, więc zmodyfikowałem kod, aby działał tak, aby wykrywał zarówno zmianę rozmiaru, jak i powiększenie, wykluczające się wzajemnie. Działa przez większość czasu, więc jeśli większość jest wystarczająco dobra dla twojego projektu, to powinno być pomocne! Wykrywa powiększanie w 100% w tym, co do tej pory testowałem. Jedynym problemem jest to, że jeśli użytkownik wpadnie w szał (np. Spastycznie zmienia rozmiar okna) lub okno się opóźnia, może uruchomić się jako powiększenie zamiast zmiany rozmiaru okna.

Działa poprzez wykrywanie zmiany window.outerWidthlub window.outerHeightzmiany rozmiaru okna podczas wykrywania zmiany window.innerWidthlub window.innerHeightniezależności od zmiany rozmiaru okna jako powiększenia.

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

Uwaga: moje rozwiązanie jest podobne do rozwiązania KajMagnus, ale to działa lepiej dla mnie.

dandeto
źródło
2
Nie będę głosować, ponieważ widzę, że masz rozwiązanie, które działa, i rozumiem, co robi Twój kod, ale nie polecałbym używania magicznej liczby 0.05bez podania przynajmniej dobrego wyjaśnienia. ;-) Na przykład wiem, że w Chrome, konkretnie, 10% to najmniejsza wartość, jaką przeglądarka powiększy w każdym przypadku, ale nie jest jasne, czy dotyczy to innych przeglądarek. fyi, zawsze upewnij się, że Twój kod jest przetestowany i bądź przygotowany na jego obronę lub ulepszenie.
Nolo
ciekawe podejście
oldboy
1

Oto czyste rozwiązanie:

// 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
źródło
wydaje się to całkiem niezłym rozwiązaniem, a dzięki Proxy nie musiałbyś nawet przebijać właściwości wdowy swoim przechwytywaczem - czy wiemy na pewno, że aktualizowanie DPR jest tym, co robią / powinny robić wszystkie przeglądarki, gdy użytkownik powiększył? eee ... zerwij ten pomysł - nie można przekazać okna, być może istnieje rozwiązanie wykorzystujące „matchMedia”, ale ponieważ jest to tylko prawda / fałsz, nie jestem pewien, jak przetestować zmiany wartości analogowej, takiej jak DPR ...
Jon z
0

Zdarzenie resize działa w nowoczesnych przeglądarkach, dołączając zdarzenie do window, a następnie odczytując wartości bodyelementu lub innego elementu, na przykład ( .getBoundingClientRect () ).

W niektórych wcześniejszych przeglądarkach można było zarejestrować programy obsługi zdarzeń zmiany rozmiaru na dowolnym elemencie HTML. Nadal można ustawić atrybuty onresize lub użyć metody addEventListener (), aby ustawić procedurę obsługi dla dowolnego elementu. Jednak zdarzenia zmiany rozmiaru są uruchamiane tylko w obiekcie okna (tj. Zwracane przez document.defaultView). Tylko programy obsługi zarejestrowane w obiekcie okna będą otrzymywać zdarzenia zmiany rozmiaru .

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

Inna alternatywa : ResizeObserver API

W zależności od układu możesz obserwować zmianę rozmiaru określonego elementu.

Działa to dobrze w układach „responsywnych”, ponieważ rozmiar kontenera zmienia się podczas powiększania.

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>


Uważaj, aby nie przeciążać zadań javascript związanych ze zdarzeniami dotyczącymi gestów użytkownika. Użyj requestAnimationFrame, gdy potrzebujesz przerysowań.

NVRM
źródło
0

Według MDN „matchMedia” to właściwy sposób na zrobienie tego https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

jest to trochę skomplikowane, ponieważ każda instancja może oglądać tylko jeden MQ naraz, więc jeśli jesteś zainteresowany jakimkolwiek zmianą poziomu powiększenia, musisz wykonać kilka dopasowań ... ale ponieważ przeglądarka jest odpowiedzialna za emitowanie zdarzeń, prawdopodobnie wciąż bardziej wydajne niż odpytywanie, i możesz zdławić lub odrzucić wywołanie zwrotne lub przypiąć je do ramki animacji lub czegoś podobnego - oto implementacja, która wydaje się dość zgryźliwa, możesz zamienić _throttle lub cokolwiek innego, jeśli już na tym polegasz.

Uruchom fragment kodu i powiększaj i pomniejszaj w przeglądarce, zanotuj zaktualizowaną wartość w znacznikach - testowałem to tylko w przeglądarce Firefox! daj mi znać, jeśli zauważysz jakieś problemy.

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
źródło
-4

Odpowiadam na link sprzed 3 lat, ale wydaje mi się, że jest to bardziej akceptowalna odpowiedź,

Utwórz plik .css jako,

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

NA PRZYKŁAD:-

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

Powyższy kod sprawia, że ​​rozmiar czcionki wynosi „10px” przy powiększeniu ekranu do około 125%. Możesz sprawdzić inny poziom powiększenia, zmieniając wartość „1000px”.

Saumil
źródło
Jaki jest związek między max-width współczynnikiem powiększenia a współczynnikiem powiększenia?
seebiscuit
Ten kod będzie wykonywany na każdym ekranie <1000px i nie ma nic wspólnego z powiększaniem
Artur Stary
@ArturStary nie ma sposobu, aby wykryć, czy przeglądarka jest powiększona, ale istnieje wiele obejść, a jednym z nich jest to, o czym wspomniałem w mojej odpowiedzi. Co więcej, powiedziałem, że możesz zmienić wartość 1000px, aby sprawdzić różne rozmiary ekranu, co da efekt innego poziomu powiększenia
Saumil