14

I found differencies between browsers how they report computed style dimensions when browser window is zoomed. The JSBIN example is in http://jsbin.com/pilohonevo/2/. The code is as follows:

$(window).resize(function()
{
  var width1=$(".class1").css("width");
  $(".class1").css("width",width1);

  var width2="200px";
  $(".class2").css("width",width2);

  var width3=$(".class3").css("width");

  $("#width1").html(width1);
  $("#width2").html(width2);
  $("#width3").html(width3);

  $("#overflow1").html($(".overflow1")[0].scrollWidth);
  $("#overflow2").html($(".overflow2")[0].scrollWidth);
  $("#overflow3").html($(".overflow3")[0].scrollWidth);
});

When you zoom to minimum by pressing CMD- few times and then back to 100% by pressing CMD+ few times, in Chrome (Mac Version 38.0.2125.111), you get the following values:

enter image description here

The white DIV 1 reports its width as 203px, although DIV 2 and 3 reports 200px. Also scrollWidth is 203, which is wrong as well. This means that you cannot use getComputedStyle or jQuerys .css() to get dimensions if you are not sure that browser window is not zoomed. And because zooming is not cancelable you can never be sure and you can never trust to those dimensions. I tested also $(elem).scrollLeft() and $(elem).scrollTop() and those are unreliable as well when zoomed.

So a workaround can be to use "raw" values, not "computed" values.

Is there a cross-browser javascript or jQuery method to get something like getUnComputedStyle() which determines dimensions using raw values from stylesheets and/or style attribute, because they are the only ones that are zoom-safe?

Determining zoom level and make corrections based on that is unreliable according to my tests, because there are browser differencies and error levels in different style properties are not consistently related to zoom level.

(Firefox Mac 33.1 and Safari Mac version 7.1 (9537.85.10.17.1) and IE 11 Win and emulated modes down to version 7 report correct values.

Opera Mac 25.0.1614.68, Safari Win 5.1.7 and the above reported Chrome report wrong values.)

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Timo Kähkönen
  • 11,962
  • 9
  • 71
  • 112
  • 1
    As far as the CSS definition goes, you do in fact want to get the computed value. That is, the value that is computed based on cascade resolution by processing the CSS. The problem is that `getComputedStyle()` does not follow the CSS definition, for whatever reason, and therefore the name is incredibly misleading. – BoltClock Dec 23 '14 at 05:17
  • @BoltClock: Yes, you right that I need the values after cascading resolution, but so that zoom level does not affect the values. – Timo Kähkönen Dec 23 '14 at 21:00
  • It works on Ubuntu Linux Chrome Version 40.0.2214.111 (64-bit). If you update Chrome on the Mac, is the problem corrected? – Robin like the bird Feb 19 '15 at 21:28
  • No. Chrome 40.0.2214.115 (64-bit) and 42.0.2302.2 canary (64-bit) both are stil affected in Mac. – Timo Kähkönen Feb 20 '15 at 06:40

2 Answers2

1

I've reproduced this with Chrome 49 and JQuery 1.11, not in FF and not in Internet Explorer.

However, I believe this to be an artifact of the code as well. The only divs that show this problem are div1 and overflow1, which both use the same system of setting the width to the computed width, repeatedly. What happens is that for some zooms the computed value is 201. You set the width to 201, so for some zooms the computed value becomes 202 and so on. I got 204, for example.

In the Chrome debugger, at zoom 67%, the reported width appears as 199.981, but the values available to Javascript are integers. scrollWidth is 199 while clientWidth and offsetWidth are 200. All of the jQuery width methods return 200 (width, innerWidth, outerWidth). At zoom 33%, scrollWidth and jQuery widths all return 201, althought the debugger reported width is still 199.981.

My assertion is that the problem is a bug in Chrome and probably related to rounding.

As described here: Getting the actual, floating-point width of an element you can get the actual floating point value reported by the debugger with .getBoundingClientRect(). If you want to be completely safe, try using that one.

Community
  • 1
  • 1
Siderite Zackwehdex
  • 6,293
  • 3
  • 30
  • 46
0

If I understand what you are trying to accomplish correctly (and if I don't please say so and I'll try to improve my answer), and assuming you have already managed to catch the zooming event some how (which is not a given), you could:

  1. Clone the div you are trying to get the CSS styles from;
  2. Append the clone to the dom in an unobtrusive way (ie, a way in which it will not cover any other elements on the document);
  3. Remove it's style attribute (just in case it was set by other scripts or functions);
  4. Get all the styles you need from it;
  5. Finally, remove the clone from the dom when you are done.

This demo works for me, regardless of page zoom.

jQuery(function($) {
    function getRawStyles(sel, styles) {
        sel = $(sel);
        var clone = sel.clone().removeAttr("style").attr("class", "cloneDiv").insertBefore(sel);
        $.each(styles, function(index, style) {
            console.log( style + ": " + $(clone[0]).css(style) );
        });
         $(".cloneDiv").remove();  
    }
    $(document).ready(function() {
        $("button", this).on("click", function() {
            getRawStyles("#myDiv", ["height", "width"]);
        });
    });
});
#myDiv {
    background: grey;
    height: 50px;
    width: 200px;
}
.cloneDiv {
    left: -10000;
    opacity: 0;
    top: -10000;
    position: absolute;
    z-index: -1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="myDiv" style="height:200px; width: 100px"></div>
<br/>
<button>Log Computed Styles</button>
Marventus
  • 864
  • 1
  • 7
  • 14
  • This removes the style attribute so it reports incorrect dimensions, that are based only to css classes. My purpose is to get the raw values that are run through css cascading process, but are not changed when zoomed. – Timo Kähkönen Dec 23 '14 at 20:57
  • 1
    I simplified your demo a bit: jsfiddle.net/Marventus/3qzodpn2, and in mine the divs are never off by more than one pixel (always on zoom > 100%), and only for the elements inside containers set to `overflow: hidden`. – Marventus Dec 23 '14 at 23:24