web-dev-qa-db-fra.com

Comment détecter le niveau de zoom de la page dans tous les navigateurs modernes?

  1. Comment détecter le niveau de zoom de la page dans tous les navigateurs modernes? Bien que ce thread indique comment faire cela dans IE7 et IE8, je ne trouve pas de bonne solution multi-navigateurs.

  2. Firefox enregistre le niveau de zoom de la page pour un accès ultérieur. Est-ce que je pourrais obtenir le niveau de zoom sur la première page de chargement? Quelque part que j'ai lu, cela fonctionne lorsqu'un changement de zoom se produit après la page est chargée.

  3. Existe-t-il un moyen de piéger l'événement 'zoom'?

J'ai besoin de cela car certains de mes calculs sont basés sur les pixels et peuvent fluctuer lors d'un zoom.


Exemple modifié donné par @tfl

Cette page alerte différentes valeurs de hauteur lors d’un zoom. [jsFiddle]

<html>
    <head>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js" type="text/javascript"/></script>
    </head>
    <body>
        <div id="xy" style="border:1px solid #f00; width:100px;">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque sollicitudin tortor in lacus tincidunt volutpat. Integer dignissim imperdiet mollis. Suspendisse quis tortor velit, placerat tempor neque. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent bibendum auctor lorem vitae tempor. Nullam condimentum aliquam elementum. Nullam egestas gravida elementum. Maecenas mattis molestie nisl sit amet vehicula. Donec semper tristique blandit. Vestibulum adipiscing placerat mollis.</div>
        <button onclick="alert($('#xy').height());">Show</button>
    </body>
</html>
275
understack

Maintenant, le désordre est encore plus grand que lorsque cette question a été posée pour la première fois. En lisant toutes les réponses et les articles de blog que j'ai pu trouver, voici un résumé. J'ai également mis en place cette page pour tester toutes ces méthodes de mesure du niveau de zoom .

Edit (2011-12-12): J'ai ajouté un projet pouvant être cloné: https://github.com/tombigel/detect-zoom

  • IE8: screen.deviceXDPI / screen.logicalXDPI (ou screen.systemXDPI / screen.logicalXDPI pour le niveau de zoom par rapport au zoom par défaut)
  • IE7: var body = document.body,r = body.getBoundingClientRect(); return (r.left-r.right)/body.offsetWidth; (grâce à cet exemple ou cette réponse )
  • FF3.5 UNIQUEMENT: screen.widthlargeur de l'écran d'interrogation du support (voir ci-dessous) (tire parti du fait que screen.width utilise des pixels de périphérique mais que MQ width utilise des pixels CSS - grâce à Largeurs de Quirksmode )
  • _/FF3.6: aucune méthode connue
  • FF4 +: recherche multimédia en requête binaire (voir ci-dessous)
  • WebKit: https://www.chromestatus.com/feature/5737866978131968 (merci à Teo dans les commentaires)
  • WebKit: mesure la taille préférée d'un div avec -webkit-text-size-adjust:none.
  • WebKit: (interrompu depuis r72591 ) document.width / jQuery(document).width() (merci à Dirk van Oosterbosch ci-dessus ). Pour obtenir le rapport en termes de pixels de périphérique (au lieu de rapport au zoom par défaut), multipliez par window.devicePixelRatio.
  • Vieux WebKit? (non vérifié): parseInt(getComputedStyle(document.documentElement,null).width) / document.documentElement.clientWidth (from this answer )
  • Opera: document.documentElement.offsetWidthwidth d'un position:fixed; width:100% div. à partir de maintenant ( Le tableau des largeurs de Quirksmode indique qu'il s'agit d'un bogue; innerWidth doit correspondre à CSS px). Nous utilisons l'élément position: fixed pour obtenir la largeur de la fenêtre y compris l'espace où se trouvent les barres de défilement}; document.documentElement.clientWidth exclut cette largeur. Ceci est cassé depuis quelque temps en 2011; Je ne sais plus comment obtenir le niveau de zoom dans Opera.
  • _/Autre: Solution Flash de Sebastian
  • Non fiable: écoute les événements de la souris et mesure le changement dans screenX/changement dans clientX

Voici une recherche binaire pour Firefox 4, car je ne connais aucune variable où il est exposé:

<style id=binarysearch></style>
<div id=dummyElement>Dummy element to test media queries.</div>
<script>
var mediaQueryMatches = function(property, r) {
  var style = document.getElementById('binarysearch');
  var dummyElement = document.getElementById('dummyElement');
  style.sheet.insertRule('@media (' + property + ':' + r +
                         ') {#dummyElement ' +
                         '{text-decoration: underline} }', 0);
  var matched = getComputedStyle(dummyElement, null).textDecoration
      == 'underline';
  style.sheet.deleteRule(0);
  return matched;
};
var mediaQueryBinarySearch = function(
    property, unit, a, b, maxIter, epsilon) {
  var mid = (a + b)/2;
  if (maxIter == 0 || b - a < epsilon) return mid;
  if (mediaQueryMatches(property, mid + unit)) {
    return mediaQueryBinarySearch(
        property, unit, mid, b, maxIter-1, epsilon);
  } else {
    return mediaQueryBinarySearch(
        property, unit, a, mid, maxIter-1, epsilon);
  }
};
var mozDevicePixelRatio = mediaQueryBinarySearch(
    'min--moz-device-pixel-ratio', '', a, b, maxIter, epsilon);
var ff35DevicePixelRatio = screen.width / mediaQueryBinarySearch(
    'min-device-width', 'px', 0, 6000, 25, .0001);
</script>
261
yonran

Pour moi, pour Chrome/Webkit, document.width / jQuery(document).width() ne fonctionnait pas. Lorsque j'ai créé une petite fenêtre et que j'ai zoomé sur mon site de manière à ce que des barres de défilement horizontales apparaissent, document.width / jQuery(document).width() n'était pas égal à 1 au zoom par défaut. En effet, document.width inclut une partie du document en dehors de la fenêtre d'affichage.

Utiliser window.innerWidth et window.outerWidth a fonctionné. Pour une raison quelconque, dans Chrome, outerWidth est mesuré en pixels d'écran et innerWidth en css pixels.

var screenCssPixelRatio = (window.outerWidth - 8) / window.innerWidth;
if (screenCssPixelRatio >= .46 && screenCssPixelRatio <= .54) {
  zoomLevel = "-4";
} else if (screenCssPixelRatio <= .64) {
  zoomLevel = "-3";
} else if (screenCssPixelRatio <= .76) {
  zoomLevel = "-2";
} else if (screenCssPixelRatio <= .92) {
  zoomLevel = "-1";
} else if (screenCssPixelRatio <= 1.10) {
  zoomLevel = "0";
} else if (screenCssPixelRatio <= 1.32) {
  zoomLevel = "1";
} else if (screenCssPixelRatio <= 1.58) {
  zoomLevel = "2";
} else if (screenCssPixelRatio <= 1.90) {
  zoomLevel = "3";
} else if (screenCssPixelRatio <= 2.28) {
  zoomLevel = "4";
} else if (screenCssPixelRatio <= 2.70) {
  zoomLevel = "5";
} else {
  zoomLevel = "unknown";
}
44
user800583

Tu peux essayer

var browserZoomLevel = Math.round(window.devicePixelRatio * 100);

Cela vous donnera le pourcentage de zoom du navigateur. 

Pour attraper un événement de zoom, vous pouvez utiliser

$(window).resize(function() { 
// your code 
});
39
user1080381

Mon collègue et moi avons utilisé le script de https://github.com/tombigel/detect-zoom . En outre, nous avons également créé dynamiquement un élément svg et vérifié sa propriété currentScale. Cela fonctionne très bien sur Chrome et probablement avec la plupart des navigateurs. Sur FF, la fonctionnalité "Zoom uniquement sur le texte" doit être désactivée. SVG est supporté sur la plupart des navigateurs. Au moment de la rédaction de cet article, testé sur IE10, FF19 et Chrome28.

var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
svg.setAttribute('version', '1.1');
document.body.appendChild(svg);
var z = svg.currentScale;
... more code ...
document.body.removeChild(svg);
15
Jay

J'ai trouvé cet article extrêmement utile. Grand merci à Yonran. Je souhaitais transmettre certaines connaissances supplémentaires acquises lors de la mise en œuvre de certaines des techniques qu’il avait fournies. Dans FF6 et Chrome 9, la prise en charge des requêtes multimédia de JS a été ajoutée, ce qui peut grandement simplifier l’approche d’interrogation multimédia nécessaire pour déterminer le zoom en FF. Voir la documentation à MDN ici . Pour mes besoins, je devais seulement savoir si le navigateur était agrandi ou réduit, je n'avais pas besoin du facteur de zoom réel. J'ai pu obtenir ma réponse avec une ligne de JavaScript:

var isZoomed = window.matchMedia('(max--moz-device-pixel-ratio:0.99), (min--moz-device-pixel-ratio:1.01)').matches;

En combinant cela avec les solutions IE8 + et Webkit, qui étaient également des lignes simples, j'ai été capable de détecter le zoom sur la grande majorité des navigateurs frappant notre application avec seulement quelques lignes de code.

11
brianh
zoom = ( window.outerWidth - 10 ) / window.innerWidth

C'est tout ce dont vous avez besoin.

10
Alex von Thorn

J'ai une solution pour cela à compter de janvier 2016. Testé dans les navigateurs Chrome, Firefox et MS Edge. 

Le principe est le suivant. Collectez 2 points MouseEvent éloignés. Chaque événement de souris est livré avec les coordonnées de l'écran et du document. Mesurer la distance entre les 2 points dans les deux systèmes de coordonnées. Bien qu'il existe des décalages fixes variables entre les systèmes de coordonnées dus au mobilier du navigateur, la distance entre les points doit être identique si la page n'est pas agrandie. La raison pour laquelle vous spécifiez "très éloigné" (je mets 12 pixels) est telle que de petits changements de zoom (par exemple 90% ou 110%) sont détectables.

Référence: https://developer.mozilla.org/en/docs/Web/Events/mousemove

Pas: 

  1. Ajouter un auditeur de mouvement de souris

    window.addEventListener("mousemove", function(event) {
        // handle event
    });
    
  2. Capturez 4 mesures à partir d'événements de souris:

    event.clientX, event.clientY, event.screenX, event.screenY
    
  3. Mesurer la distance d_c entre les 2 points du système client

  4. Mesurer la distance d_s entre les 2 points dans le système d’écran

  5. Si d_c! = D_s, le zoom est appliqué. La différence entre les deux vous indique la quantité de zoom.

N.B. Seuls les calculs de distance sont rarement utilisés, p. Ex. lorsque vous pouvez échantillonner un nouvel événement de souris très éloigné du précédent.

Limitations: Supposons que l'utilisateur bouge la souris au moins un peu et que le zoom est inconnaissable jusqu'à cette heure.

5
user1191311

Cela a très bien fonctionné pour les navigateurs Web (Chrome, Safari):

function isZoomed() {
    var width, mediaQuery;

    width = document.body.clientWidth;
    mediaQuery = '(max-width: ' + width + 'px) and (min-width: ' + width + 'px)';

    return !window.matchMedia(mediaQuery).matches;
}

Ne semble pas fonctionner dans Firefox cependant.

Cela fonctionne aussi dans WebKit:

var zoomLevel = document.width / document.body.clientWidth;
3
rudolfrck

Dans Internet Explorer 7, 8 et 9, cela fonctionne:

function getZoom() {
    var screen;

    screen = document.frames.screen;
    return ((screen.deviceXDPI / screen.systemXDPI) * 100 + 0.9).toFixed();
}

Le "+0,9" est ajouté pour éviter les erreurs d'arrondi (sinon, vous obtiendriez 104% et 109% lorsque le zoom du navigateur est défini sur 105% et 110% respectivement).

Dans IE6, le zoom n'existe pas, il est donc inutile de vérifier le zoom.

3
pench

En gros, nous avons:

  • window.devicePixelRatio qui prend en compte le zoom * au niveau du navigateur ainsi que le zoom système/la densité de pixels.
    * - le niveau de zoom sur Mac/Safari n'est pas pris en compte
  • questions des médias
  • vwvh unités CSS
  • L'événement resize, qui est déclenché lors d'un changement de niveau de zoom, provoque la modification de la taille effective de la fenêtre

cela devrait suffire pour _/normal UX. Si vous devez détecter un niveau de zoom, cela peut indiquer une mauvaise conception de l'interface utilisateur.

Pitch-zoom est plus difficile à suivre et n'est pas considéré pour le moment.

2
kirilloid

Ce que je suis venu avec est:

1) Créez un position:fixed<div> avec width:100% ( id = zoomdiv )

2) lors du chargement de la page:

zoomlevel=$("#zoomdiv").width()*1.0 / screen.availWidth

Et cela a fonctionné pour moi pour les zooms ctrl+ et ctrl-.

ou je peux ajouter la ligne à un événement $(window).onresize() pour obtenir le niveau de zoom actif


Code:

<script>
    var zoom=$("#zoomdiv").width()*1.0 / screen.availWidth;

    $(window).resize(function(){
        zoom=$("#zoomdiv").width()*1.0 / screen.availWidth;
        alert(zoom);    
    });
</script>
<body>
    <div id=zoomdiv style="width:100%;position:fixed;"></div>
</body>

P.S. : ceci est mon premier post, pardonnez les erreurs

2
Abhishek Borar

Sur les appareils mobile (avec Chrome pour Android ou Opera Mobile), vous pouvez détecter le zoom de window.visualViewport.scale . https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API

Détecter sur Safari: document.documentElement.clientWidth/window.innerWidth (retourne 1 si aucun zoom sur le périphérique).

2
JIm

Sur Chrome

var ratio = (screen.availWidth / document.documentElement.clientWidth);
var zoomLevel = Number(ratio.toFixed(1).replace(".", "") + "0");
1
Nicolas Giszpenc

Vos calculs sont toujours basés sur un nombre de pixels CSS. Ils sont juste une taille différente sur l'écran maintenant. C'est le point de zoom de la page entière.

Que voudriez-vous que se passe sur un navigateur sur un périphérique 192 ppp qui affiche donc normalement quatre pixels de périphérique pour chaque pixel d'une image? À un zoom de 50%, cet appareil affiche désormais un pixel d'image sur un pixel de périphérique.

1
Neil

Ceci est pour Chrome, à la suite de user800583 answer ...

J'ai passé quelques heures sur ce problème et je n'ai pas trouvé de meilleure approche, mais:

  • Il y a 16 'zoomLevel' et non 10
  • Lorsque Chrome est en plein écran/maximisé, le ratio est window.outerWidth/window.innerWidth, et dans le cas contraire, le ratio semble être (window.outerWidth-16)/window.innerWidth, mais le 1er cas peut être abordé par le second.

Alors je suis venu à ce qui suit ...

Mais cette approche a des limites: par exemple, si vous jouez à l’accordéon avec la fenêtre de l’application (agrandissez et réduisez rapidement la largeur de la fenêtre), vous obtiendrez des écarts entre les niveaux de zoom même si le zoom n’a pas changé mis à jour exactement dans le même temps).

var snap = function (r, snaps)
{
    var i;
    for (i=0; i < 16; i++) { if ( r < snaps[i] ) return i; }
};
var w, l, r;
w = window.outerWidth, l = window.innerWidth;
return snap((w - 16) / l,
            [ 0.29, 0.42, 0.58, 0.71, 0.83, 0.95, 1.05, 1.18, 1.38, 1.63, 1.88, 2.25, 2.75, 3.5, 4.5, 100 ],
);

Et si vous voulez le facteur:

var snap = function (r, snaps, ratios)
{
    var i;
    for (i=0; i < 16; i++) { if ( r < snaps[i] ) return eval(ratios[i]); }
};
var w, l, r;
w = window.outerWidth, l = window.innerWidth;
return snap((w - 16) / l,
            [ 0.29, 0.42, 0.58, 0.71, 0.83, 0.95, 1.05, 1.18, 1.38, 1.63, 1.88, 2.25, 2.75, 3.5, 4.5, 100 ],
            [ 0.25, '1/3', 0.5, '2/3', 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5 ]
);
0
jeum

Cette réponse est basée sur les commentaires selon lesquels devicePixelRatio ne revient pas correctement sur la réponse de user1080381.

J'ai constaté que cette commande revenait de manière incorrecte dans certains cas également lorsque vous travaillez avec un ordinateur de bureau, Surface Pro 3 et Surface Pro 4.

Ce que j’ai trouvé, c’est que cela fonctionnait sur mon bureau, mais les SP3 et SP4 donnaient des numéros différents l’un de l’autre et le bureau.

J'ai remarqué cependant que le SP3 revenait à une fois et demie le niveau de zoom que j'attendais. Lorsque j’ai jeté un œil aux paramètres d’affichage, le SP3 était réglé à 150% au lieu des 100% que j’avais sur mon bureau.

La solution aux commentaires devrait donc être de diviser le niveau de zoom renvoyé par l’échelle de la machine sur laquelle vous vous trouvez.

J'ai pu obtenir l'échelle dans les paramètres Windows en procédant comme suit:

ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DesktopMonitor");
double deviceScale = Convert.ToDouble(searcher.Get().OfType<ManagementObject>().FirstOrDefault()["PixelsPerXLogicalInch"]);
int standardPixelPerInch = 96;
return deviceScale / standardPixelPerInch;

Donc, dans le cas de mon SP3, voici comment ce code apparaît à un zoom de 100%:

devicePixelRatio = 1.5
deviceScale = 144
deviceScale / standardPixelPerInch = 1.5
devicePixelRatio / (deviceScale / standardPixelPerInch) = 1

Multiplier par 100 dans la réponse originale de user1080381 vous donnerait alors un zoom de 100 (%).

0
Cameron Weaver

J'ai cette solution pour mobile uniquement (testé avec Android):

jQuery(function($){

zoom_level = function(){

    $("body").prepend('<div class="overlay" ' +
                'style="position:fixed; top:0%; left:0%; ' +
                'width:100%; height:100%; z-index:1;"></div>');

    var ratio = $("body .overlay:eq(0)").outerWidth() / $(window).width();
    $("body .overlay:eq(0)").remove();

    return ratio;
}

alert(zoom_level());

});

Si vous voulez le niveau de zoom juste après le mouvement de pincement, vous devrez probablement définir un peu de délai en raison du délai de rendu (mais je ne suis pas sûr car je ne l'ai pas testé).

0
pmrotule

Si cela fonctionne actuellement, il doit encore être séparé par navigateur. Testé avec succès sur Chrome (75) et Safari (11.1) (aucune solution n'a encore été trouvée pour FF). La valeur du zoom est également correcte sur l'affichage de la rétine et les calculs sont déclenchés lors d'un événement de redimensionnement.

    private pixelRatio() {
      const styleString = "(min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 1.5),(-moz-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)";
      const chromeRatio = (Math.round((this.window.outerWidth / this.window.innerWidth)*100) / 100);
      const otherRatio = (Math.round(window.devicePixelRatio * 100) / 100);
      const resizeValue = (this.isChrome()) ? chromeRatio : otherRatio;

      return resizeValue || (this.window.matchMedia && this.window.matchMedia(styleString).matches ? 2 : 1) || 1;
    }


  private isChrome():boolean {
    return (!!this.window.chrome && !(!!this.window.opera || this.window.navigator.userAgent.indexOf(' Opera') >= 0))
  }

  private chrome() {
    const zoomChrome = Math.round(((this.window.outerWidth) / this.window.innerWidth)*100) / 100;
    return {
      zoom: zoomChrome,
      devicePxPerCssPx: zoomChrome1 * this.pixelRatio()
    };
  }
0
Yogi

Cela n’a pas été testé pour IE, mais si vous créez un élément elem avec

min-width: 100%

puis 

window.document.width / elem.clientWidth

vous donnera le niveau de zoom de votre navigateur (y compris le facteur document.body.style.zoom).

0