Tangkap acara "zoom" browser dalam JavaScript

162

Apakah mungkin mendeteksi, menggunakan JavaScript, ketika pengguna mengubah zoom pada halaman? Saya hanya ingin menangkap acara "zoom" dan menanggapinya (mirip dengan acara window.onresize).

Terima kasih.

pengguna123093
sumber
13
Saya percaya bahwa peramban yang lebih baru memecat acara yang terlalu besar ketika halaman diperbesar.
epascarello
1
Saya memiliki masalah yang serupa, tetapi saya tidak hanya ingin tahu kapan zoom diubah, saya ingin tahu nilai zoom saat halaman saya dimuat, juga.
Nosredna
3
Benar-benar bukan duplikat. Pertanyaannya di sini adalah tentang menangkap acara, bukan menentukan level zoom.
Assaf Lavie
5
@epascarello - ya, tapi itu tidak membatalkan komentar saya
HorusKol
7
Saya ingin mengonfirmasi tentang 'onresize' yang terjadi di browser terbaru. Sejauh ini saya melihat Chrome yang baru disetel (33), FF (28), IE (11 dan 11 dalam Mode ke-9) semuanya memicu acara dengan benar ketika Anda memperbesar atau memperkecil.
Brock

Jawaban:

77

Tidak ada cara untuk secara aktif mendeteksi jika ada zoom. Saya menemukan entri yang bagus di sini tentang bagaimana Anda dapat mencoba mengimplementasikannya.

Saya telah menemukan dua cara mendeteksi tingkat zoom. Salah satu cara untuk mendeteksi perubahan level zoom bergantung pada fakta bahwa nilai persentase tidak diperbesar. Nilai persentase relatif terhadap lebar viewport, dan karenanya tidak terpengaruh oleh pembesaran halaman. Jika Anda menyisipkan dua elemen, satu dengan posisi dalam persentase, dan satu dengan posisi yang sama dalam piksel, mereka akan bergerak terpisah ketika halaman diperbesar. Temukan rasio antara posisi kedua elemen dan Anda sudah mendapatkan level zoom. Lihat test case. http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

Anda juga bisa melakukannya menggunakan alat dari posting di atas. Masalahnya adalah Anda lebih atau kurang membuat dugaan tentang apakah halaman tersebut diperbesar atau tidak. Ini akan bekerja lebih baik di beberapa browser daripada yang lain.

Tidak ada cara untuk mengetahui apakah halaman diperbesar jika mereka memuat halaman Anda saat diperbesar.

Ian Elliott
sumber
1
Satu dapat memeriksa parameter ukuran di dalam handler onload untuk tubuh. Anehnya, dalam debugging IE8 vs 9 tampaknya penangan yang terlalu besar untuk tubuh melewati dokumen di IE8, sementara IE9 melewati jendela, seperti halnya Chrome.
Walter K
Jika Anda menempatkan kedua elemen di posisi yang sama persis dan halaman dimuat saat diperbesar, tidakkah akan ada perpindahan antara kedua elemen? Bukankah ini akan memberi tahu jika halaman sudah diperbesar atau tidak?
vijayant
jugadocument.body.offsetWidth
Samy Bencherif
Menggunakan metode seperti ini juga akan diaktifkan ketika pengguna mengubah ukuran jendela, jadi mengapa tidak menggunakan pendengar acara ukuran saja? Dalam hal ini juga merupakan solusi yang layak.
hewiefreeman
12

Saya menggunakan bagian JavaScript ini untuk bereaksi terhadap Zoom "acara".
Itu polling lebar jendela. (Seperti yang disarankan pada halaman ini (yang dikaitkan dengan Ian Elliott): http://novemberborn.net/javascript/page-zoom-ff3 [arsip] )

Diuji dengan Chrome, Firefox 3.6 dan Opera, bukan IE.

Salam, 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
sumber
8
bagaimana dengan positif palsu dengan ukuran jendela?
gcb
5
Tapi Anda bisa menyaring kasus-kasus itu ketika Anda juga menerapkan penangan onresize. Jadi dasar-dasar untuk sebuah solusi ada di sini.
Stijn de Witt
@StijndeWitt Setelah membaca ini saya mulai memahami jalur yang diusulkan, sekarang saya sedang mengerjakan solusi dengan memfilter peristiwa pengubahan ukuran, terutama pada ponsel. Siapa saja?
lowtechsun
Mungkin Anda bisa menggunakan nilai celah untuk membedakan ukuran dan memperbesar? Maksud saya zoom akan langsung mengubah lebar jendela> x piksel.
Sebastien
1
Positif palsu adalah masalah, ya. Tidakkah akan menghilangkan 99,99% dari semua positif palsu dengan memeriksa apakah rasio aspek dipertahankan? Buat skrip mengingat rasio terakhir dan hitung rasio baru & periksa apakah sama. Gabungkan bahwa dengan lebar berbeda dan Anda harus memiliki dasar yang baik
Biepbot Von Stirling
11

Kabar baik semua orangbeberapa orang! Peramban yang lebih baru akan memicu peristiwa pengubahan ukuran jendela saat zoom diubah.

Ben
sumber
Chrome dan Firefox untuk Android tidak akan memicu acara pengubahan ukuran pada zoom.
lowtechsun
5
Ini bukan kabar baik jika Anda tidak ingin memperbesar untuk memicu acara pengubahan ukuran.
Reahreic
12
Berita yang lebih baik akan menjadi acara zoom aktual, berbeda dari acara pengubahan ukuran.
Vincent
3
Keduanya benar. Diedit.
Ben
apakah mungkin juga mengatur zoom?
oldboy
9

Mari kita mendefinisikan px_ratio seperti di bawah ini:

px rasio = rasio pixel fisik ke css px.

jika ada yang memperbesar Halaman, viewport pxes (px berbeda dari pixel) berkurang dan harus sesuai dengan layar sehingga rasio (pixel fisik / CSS_px) harus menjadi lebih besar.

tetapi di window Resizing, ukuran layar berkurang dan juga pxes. jadi rasio akan dipertahankan.

zooming: memicu windows.resize event -> dan ubah px_ratio

tapi

mengubah ukuran: memicu windows.resize acara -> tidak mengubah 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;
    }
}

Poin kuncinya adalah perbedaan antara CSS PX dan Physical Pixel.

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

Abilogos
sumber
Ini harus menjadi jawaban yang diterima IMO. Sejauh ini berfungsi dengan sempurna, terima kasih! Membungkusnya menjadi acara khusus jika ada yang tertarik gist.github.com/souporserious/b44ea5d04c38c2e7ff32cd1912a17cd0 .
suporserius
6

Ini bekerja untuk saya:

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

Itu hanya diperlukan di IE8. Semua browser lain secara alami menghasilkan acara pengubahan ukuran.

Bill Keese
sumber
3

Ada plugin bagus yang dibangun dari yonranyang dapat melakukan deteksi. Ini pertanyaannya yang sebelumnya dijawab di StackOverflow. Ini berfungsi untuk sebagian besar browser. Aplikasi sesederhana ini:

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
sumber
Tidak berfungsi di Firefox untuk Android 4.4.2. Juga di FF untuk seluler, centang Always enable zoomtombol di opsi Aksesibilitas. Demo tidak akan bereaksi terhadap perubahan.
lowtechsun
2

Saya ingin menyarankan peningkatan solusi sebelumnya dengan melacak perubahan lebar jendela. Alih-alih mempertahankan susunan acara pendengar Anda sendiri, Anda dapat menggunakan sistem acara javascript yang ada dan memicu acara Anda sendiri pada perubahan lebar, dan mengikat pengatur acara untuk itu.

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

function pollZoomFireEvent() 
{ 

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

Throttle / debounce dapat membantu mengurangi tingkat panggilan handler Anda.

Alexey
sumber
1
Throttle / debounce hanya berguna jika polling dipicu oleh beberapa peristiwa lain (misalnya gerakan mouse atau keyup).
fuzzyTew
1

Anda juga bisa mendapatkan peristiwa pengubahan ukuran teks, dan faktor zoom dengan menyuntikkan div yang berisi setidaknya ruang yang tidak dapat dipecahkan (mungkin, disembunyikan), dan secara teratur memeriksa ketinggiannya. Jika tinggi berubah, ukuran teks telah berubah, (dan Anda tahu berapa banyak - ini juga menyala, secara kebetulan, jika jendela diperbesar dalam mode halaman penuh, dan Anda masih akan mendapatkan faktor zoom yang benar, dengan tinggi yang sama / rasio tinggi).

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

Di iOS 10 dimungkinkan untuk menambahkan pendengar acara ke touchmoveacara dan untuk mendeteksi, jika halaman diperbesar dengan acara saat ini.

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

terima kasih
sumber
1

Meskipun ini adalah pertanyaan lama 9 tahun, masalahnya tetap ada!

Saya telah mendeteksi ukuran sementara mengecualikan zoom dalam suatu proyek, jadi saya mengedit kode saya untuk membuatnya berfungsi untuk mendeteksi ukuran dan zoom eksklusif satu sama lain. Ini berfungsi sebagian besar waktu, jadi jika sebagian besar cukup baik untuk proyek Anda, maka ini akan sangat membantu! Ini mendeteksi zoom 100% dari waktu dalam apa yang telah saya uji sejauh ini. Satu-satunya masalah adalah bahwa jika pengguna menjadi gila (mis. Mengubah ukuran jendela secara spastik) atau jeda jendela, ia mungkin menyala sebagai zoom alih-alih ukuran jendela.

Ini bekerja dengan mendeteksi perubahan dalam window.outerWidthatau window.outerHeightsebagai pengubahan ukuran jendela saat mendeteksi perubahan dalam window.innerWidthatau window.innerHeightindependen dari pengubahan ukuran jendela sebagai pembesaran.

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

Catatan: Solusi saya seperti milik KajMagnus, tetapi ini telah bekerja lebih baik untuk saya.

dandeto
sumber
2
Saya tidak akan memilih karena saya melihat Anda memiliki solusi yang berfungsi, dan saya mengerti apa yang kode Anda lakukan, tetapi saya tidak akan merekomendasikan menggunakan nomor ajaib seperti 0.05tanpa setidaknya memberikan penjelasan yang baik. ;-) Misalnya, saya tahu bahwa di Chrome, khususnya, 10% adalah jumlah terkecil yang akan diperbesar peramban dalam kasus apa pun, tetapi tidak jelas bahwa ini berlaku untuk peramban lain. fyi, selalu pastikan kode Anda diuji, dan bersiaplah untuk mempertahankan atau memperbaikinya.
Nolo
pendekatan yang menarik
oldboy
1

Ini solusi bersih:

// 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
sumber
ini sepertinya solusi yang cukup bagus, dan dengan Proxy Anda bahkan tidak perlu mengalahkan properti janda dengan pencegat Anda - apakah kami tahu pasti bahwa memperbarui DPR adalah apa yang harus / dilakukan semua browser ketika pengguna memperbesar? er .. goreskan ide itu - jendela tidak dapat diproksi, mungkin ada solusi menggunakan "matchMedia" tetapi karena itu hanya hal yang benar / salah, saya tidak yakin bagaimana Anda akan menguji perubahan pada nilai analog seperti DPR ...
Jon z
0

Acara pengubahan ukuran bekerja pada browser modern dengan melampirkan acara tersebut di window, dan kemudian membaca nilai-nilai dari body, atau elemen lain dengan misalnya ( .getBoundingClientRect () ).

Di beberapa browser sebelumnya, dimungkinkan untuk mendaftarkan pengatur acara yang diubah ukurannya pada elemen HTML apa pun. Masih dimungkinkan untuk mengatur atribut yang terlalu besar atau menggunakan addEventListener () untuk mengatur handler pada elemen apa pun. Namun, peristiwa pengubahan ukuran hanya dipecat pada objek jendela (yaitu dikembalikan oleh document.defaultView). Hanya penangan yang terdaftar pada objek jendela yang akan menerima acara pengubahan ukuran .

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

Alternatif lain : API ResizeObserver

Tergantung tata letak Anda, Anda dapat menonton untuk mengubah ukuran pada elemen tertentu.

Ini berfungsi dengan baik pada tata letak «responsif», karena kotak kontainer diubah ukurannya saat zooming.

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>


Berhati-hatilah untuk tidak membebani tugas javascript dari acara gerakan pengguna. Gunakan requestAnimationFrame kapan pun Anda perlu menggambar ulang.

NVRM
sumber
0

Menurut MDN, "matchMedia" adalah cara yang tepat untuk melakukan ini https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

ini agak rewel karena setiap instance hanya dapat menonton satu MQ pada satu waktu, jadi jika Anda tertarik pada perubahan level zoom apa pun, Anda perlu membuat banyak pencocokan .. tetapi karena browser bertugas untuk memancarkan peristiwa, mungkin masih lebih berkinerja daripada jajak pendapat, dan Anda bisa mencekik atau melonggarkan panggilan balik atau menyematkannya ke bingkai animasi atau sesuatu - inilah implementasi yang tampaknya cukup tajam, jangan ragu untuk menukar di _throttle atau apa pun jika Anda sudah bergantung pada itu.

Jalankan cuplikan kode dan perbesar dan perkecil di peramban Anda, catat nilai yang diperbarui di markup - Saya hanya menguji ini di Firefox! biar tahu jika Anda melihat masalah.

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
sumber
-4

Saya membalas tautan berusia 3 tahun tetapi saya kira inilah jawaban yang lebih dapat diterima,

Buat file .css sebagai,

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

MISALNYA:-

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

Kode di atas membuat ukuran font '10px' ketika layar diperbesar menjadi sekitar 125%. Anda dapat memeriksa tingkat zoom yang berbeda dengan mengubah nilai '1000px'.

Saumil
sumber
Apa hubungan antara max-widthrasio zoom dan?
seebiscuit
Kode ini akan dieksekusi pada setiap layar <1000px dan tidak ada hubungannya dengan zoom
Artur Stary
@ ArturStary tidak ada cara untuk mendeteksi apakah browser diperbesar tetapi ada banyak solusi dan salah satunya adalah apa yang saya sebutkan dalam jawaban saya. Selain itu, saya memang mengatakan bahwa Anda dapat mengubah nilai 1000px untuk memeriksa ukuran layar yang berbeda yang akan memberikan efek tingkat zoom berbeda
Saumil