JavaScriptでブラウザの「ズーム」イベントをキャッチ


162

JavaScriptを使用して、ユーザーがページのズームを変更したことを検出することはできますか?「ズーム」イベントをキャッチしてそれに応答したいだけです(window.onresizeイベントに似ています)。

ありがとう。


13
新しいブラウザは、ページがズームされたときにonresizeイベントを発生させると思います。
epascarello、2009年

1
同様の問題がありますが、ズームが変更されたときだけでなく、ページが読み込まれたときのズームの値も知りたいです。
Nosredna、2009年

3
本当に重複していません。ここでの問題は、イベントをキャッチすることであり、ズームレベルを決定することではありません。
Assaf Lavie 2012

5
@epascarello-はい、しかしそれは私のコメントを無効にしません
HorusKol

7
最新のブラウザで発生する「onresize」について確認したいのですが。これまでのところ、ズームインまたはズームアウトすると、新しいセットのChrome(33)、FF(28)、IE(9thモードの11および11)がすべて正しくトリガーされます。
ブロック14

回答:


77

ズームがあるかどうかを積極的に検出する方法はありません。私はあなたがそれをどのように実装しようと試みることができるかについての良いエントリーをここに見つけました。

ズームレベルを検出する方法は2つあります。ズームレベルの変更を検出する1つの方法は、パーセント値がズームされないという事実に依存しています。パーセンテージ値はビューポートの幅を基準にしているため、ページズームの影響を受けません。2つの要素を挿入する場合、1つはパーセンテージでの位置、もう1つは同じ位置でのピクセルで、ページがズームされると離れます。両方の要素の位置の比率を見つけると、ズームレベルがわかります。テストケースを参照してください。 http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3

上記の投稿のツールを使用してそれを行うこともできます。問題は、ページがズームされているかどうかについて、知識に基づいた推測を行っていることです。これは他のブラウザよりもいくつかのブラウザでうまく機能します。

ズーム中にページが読み込まれた場合、ページがズームされているかどうかを確認する方法はありません。


1
本文のonloadハンドラー内でサイズパラメーターを確認できます。不思議なことに、IE8と9のデバッグでは、Chromeと同様に、IE9がウィンドウを渡すのに対して、ボディのonresizeハンドラーはIE8のドキュメントを渡されるように見えます。
Walter K

2つの要素を正確に同じ位置に配置し、ズーム中にページが読み込まれる場合、2つの要素の間にずれがないでしょうか?これは、ページが既にズームされているかどうかを教えてくれませんか?
-vijayant

またdocument.body.offsetWidth
Samy Bencherif 2017

このようなメソッドを使用すると、ユーザーがウィンドウのサイズを変更したときにも起動するので、なぜresizeイベントリスナーを使用しないのですか?その場合、それは実行可能な解決策でもあります。
hewiefreeman 2017

12

このJavaScriptを使用して、ズームの「イベント」に対応しています。
ウィンドウ幅をポーリングします。(このページ(Ian Elliottがリンク)でいくらか提案されているように:http : //novemberborn.net/javascript/page-zoom-ff3 [archive]

IEではなく、Chrome、Firefox 3.6、Operaでテスト済み。

よろしく、マグナス

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
ウィンドウのサイズ変更による誤検知はどうですか?
gcb

5
しかし、onresizeハンドラーも実装すると、これらのケースを除外できます。ソリューションの基本はここにあります。
Stijn de Witt

@StijndeWitt これを読んだ後私は提案されたパスを理解し始めており、特にモバイルで、サイズ変更イベントをフィルタリングして解決策に取り組んでいます。誰でも?
lowtechsun 2017年

おそらくギャップ値を使用して、サイズ変更とズームを区別できますか?つまり、ズームは瞬時にウィンドウの幅を> xピクセルだけ変更します。
セバスチャン2017年

1
そうです、誤検知は問題です。アスペクト比が維持されているかどうかをチェックすることで、すべての誤検知の99.99%を排除しませんか?スクリプトに最後の比率を記憶させ、新しい比率を計算し、それらが同じかどうかを確認します。幅が異なっているとして、あなたが良い基盤を持っている必要があることをコンバイン
Biepbotフォン・スターリング

11

良いニュース 全員人によっては!新しいブラウザーは、ズームが変更されるとウィンドウのサイズ変更イベントをトリガーします。


ChromeとFirefox for Androidは、ズーム時にサイズ変更イベントをトリガーしません。
lowtechsun 2017年

5
ズームでサイズ変更イベントをトリガーしたくない場合、これは良いニュースではありません。
Reahreic 2017

12
より良いニュースは、サイズ変更イベントとは異なり、実際のズームイベントです。
ビンセント

3
どちらも正しい。編集。
ベン

どういうわけかズームも設定できますか?
オールドボーイ、

9

以下のようにpx_ratioを定義してみましょう:

px比率= CSSピクセルに対する物理ピクセルの比率。

いずれかのズームページの場合、ビューポートピクセル(pxはピクセルとは異なります)が減少し、画面にフィットするため、比率(物理ピクセル/ CSS_px)を大きくする必要があります。

しかし、ウィンドウのサイズ変更では、画面サイズとピクセルが縮小されます。したがって、比率は維持されます。

ズーム:windows.resizeイベントをトリガー->そしてpx_ratioを変更

だが

サイズ変更: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;
    }
}

重要な点は、CSS PXと物理ピクセルの違いです。

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


これは、受け入れられた回答IMOである必要があります。これまでのところ問題なく動作します。ありがとうございます。誰かがgist.github.com/souporserious/b44ea5d04c38c2e7ff32cd1912a17cd0に興味がある場合は、カスタムイベントにまとめました。
souporserious

6

これは私にとってはうまくいきます:

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

IE8でのみ必要です。他のすべてのブラウザは自然にサイズ変更イベントを生成します。


3

yonran検出を行うことができる、そこから構築された気の利いたプラグインがあります。StackOverflowに関する彼の以前に回答された質問は次のとおりです。ほとんどのブラウザで動作します。アプリケーションはこれと同じくらい簡単です:

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

デモ


Android 4.4.2向けFirefoxでは機能しません。モバイル向けのFFでも、Always enable zoom[ユーザー補助]オプションのボタンをチェックします。デモは変更に反応しません。
lowtechsun 2017年

2

ウィンドウ幅の変更を追跡することで、以前のソリューションを改善することを提案します。独自のイベントリスナーの配列を保持する代わりに、既存のJavaScriptイベントシステムを使用して、幅が変更されたときに独自のイベントをトリガーし、それにイベントハンドラーをバインドできます。

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

function pollZoomFireEvent() 
{ 

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

スロットル/デバウンスは、ハンドラーの呼び出し率を減らすのに役立ちます。


1
スロットル/デバウンスは、ポーリングが他のイベント(マウスの動きやキーアップなど)によってトリガーされた場合にのみ役立ちます。
fuzzyTew 2011年

1

また、テキストのサイズ変更イベントとズームファクターを取得することもできます。これには、少なくとも分割不可能なスペース(おそらく非表示)を含むdivを挿入し、その高さを定期的に確認します。高さが変わると、テキストのサイズが変わります(そして、あなたはどれだけ知っています-偶然にも、ウィンドウが全画面モードでズームされても、同じ高さで正しいズーム係数が得られます/高さの比率)。


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

1

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


1

これは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の解決策に似ていますが、これは私にとってはうまくいきました。


2
私はあなたが機能する解決策を持っているのを見ることができ、あなたのコードが何をしているのか理解しているので、私は反対票を投じません0.05。;-)たとえば、Chromeでは具体的に10%がブラウザがズームする最小量であることは知っていますが、これが他のブラウザにも当てはまることは明らかではありません。fyi、常にコードがテストされていることを確認し、コードを防御または改善する準備をしてください。
NOLO

興味深いアプローチ
オールドボーイ、

1

ここにクリーンなソリューションがあります:

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


これはかなり良い解決策のように見えますが、プロキシを使用すると、インターセプターでwidowプロパティを変更する必要さえありません。ユーザーがズームしたときに、すべてのブラウザーがDPRの更新を行う必要があることを私たちは知っていますか?er ..そのアイデアをスクラッチします-ウィンドウはプロキシできません。「matchMedia」を使用した解決策が存在する可能性がありますが、それは真/偽の問題であるため、アナログ値への変更をどのようにテストするかわかりませんDPR ...
ジョンz

0

resizeイベントは、にイベントをアタッチし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")
}

その他の代替策ResizeObserver API

レイアウトによっては、特定の要素のサイズ変更を監視できます。

コンテナボックスはズームするとサイズが変更されるため、これは「レスポンシブ」レイアウトでうまく機能します。

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を使用してください。


0

MDNによると、「matchMedia」はこれを行う適切な方法ですhttps://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes

各インスタンスは一度に1つのMQを見ることができるので、あなたが興味を持っているそうだとすれば、それは、ビット気難しいだ任意のあなたはマッチャーの束を作るために必要なズームレベルの変更..しかし、ブラウザがイベントを発するに担当しているので、それはおそらくですポーリングよりもさらにパフォーマンスが高く、コールバックを抑制またはデバウンスしたり、アニメーションフレームなどに固定したりできます。ここでは、実装がかなりスッキリしているようです。_throttleなどに既に依存している場合は、自由に入れ替えてください。

コードスニペットを実行し、ブラウザーでズームインおよびズームアウトします。マークアップの更新された値に注意してください-これはFirefoxでのみテストしました!lemmeは、問題があるかどうかを確認します。

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

私は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;
    }
}

上記のコードは、画面が約125%にズームされたときにフォントのサイズを「10px」にします。「1000px」の値を変更することで、さまざまなズームレベルを確認できます。


max-widthズーム比の関係は何ですか?
Seebiscuit 2016年

このコードは各<1000px画面で実行され、ズームとは関係ありません
Artur Stary

@ArturStaryブラウザがズームされているかどうかを検出する方法はありませんが、多くの回避策があり、そのうちの1つは私の回答で述べたものです。さらに、1000pxの値を変更して、さまざまな画面サイズをチェックして、さまざまなズームレベルの効果が得られると
言った
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.