"getUnComputedStyle" of element - javascript

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:
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.)

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.

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:
Clone the div you are trying to get the CSS styles from;
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);
Remove it's style attribute (just in case it was set by other scripts or functions);
Get all the styles you need from it;
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>

Related

jQuery: how to make css('line-height') work cross-browser

I'm supporting IE8 and up.
$(something).css('line-height');
In Chrome this returns 32px but in IE8 it returns normal
How do I get around this? Maybe a native javascript variation?
Seems like this is a webkit vs. IE issue. Not sure about FF, but there are a couple options for how to fix it. Overtly specifying a pixel value will work. But I don't like doing that because it's harder to keep things in proportion if you scale the text, etc with media queries. I was able to get it working by overtly specifying the line-height in ems (rather then letting it inherit). It's also relevant that it was previously set to rems which IE8 doesn't recognize.
function lineHeight(element){
var tmp=$("<div>test</div>");
element.append(tmp);
tmp.css({"padding":"0","margin":"0","border":"0"});
var height = tmp[0].clientHeight;
tmp.remove();
return height;
}
jsfiddle in FF and Chrome return 20px but on IE8 18px

Retrieving percentage CSS values (in firefox)

I have a problem retrieving the exact css property value (in '%') on firefox.
Suppose we have this extremely simple markup:
<div id="box">box</div>
and this css:
#box{
width:200px;
height:200px;
left:10%;
position:absolute;
background:red;
}
and I'd like to retrieve the left position (in '%') by js
It's obv very easy with mootools (demo -> http://jsfiddle.net/steweb/AWdzB/):
var left = $('box').getStyle('left');
or jQuery (demo -> http://jsfiddle.net/steweb/RaVyU/):
var left = $('#box').css('left');
or by plain js (demo -> http://jsfiddle.net/steweb/tUAKA/):
function getStyle(el,styleProp){ //from ppk's quirksmode
var x = document.getElementById(el);
if (x.currentStyle)
var y = x.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
return y;
}
var left = getStyle('box','left');
But if you try it on firefox (8.0.1) you'll see that the result is not correct (should be 10%, but it's 91px). The questions are: is there a bug on this newer version of firefox? Does anyone knows if it's a known bug? Am I doing something wrong?
Thanks :)
Update: I tried it also on older firefox releases, and it's not correct (it always returns px value).. for completeness, it works correctly on IE
This is documented:
The used value of any CSS property is the final value of that property after all calculations have been performed. Used values can be retrieved by calling window.getComputedStyle. Dimensions (e.g. width, line-height) are all in pixels... etc
There seems to be no way to access "specified" css values for a given element, unless you know exactly which css rule applies and parse out this rule using document.stylesheets or similar interface.
The correct answer is a comment on the bug I filed on bugzilla
https://bugzilla.mozilla.org/show_bug.cgi?id=707691#c7
To get the correct % value (on firefox too) the element's (or one of its parents) display should be set to none
Test : http://jsfiddle.net/4RKsM/
The unclear thing is: why on the same browser/version (see, firefox 7 on XP/win7 or Opera 11.5 on mac osx / ubuntu) but on different os, the behav is different?
Btw, the spec #thg435 posted (and reported on mdn) is still in flux.
As I know , it has never shown the percentage (I use ff, opera and chrome). So I think it's not only a firefox problem.
However, you can calculate it manually , but it is just close to the definied value , if the browser window is small.
parseInt($('#box').css('left'))/ $(window).width()*100;
on chrome it depends on the the position value fixed and absolute always give a px whilst other values output what was put in for example if you gave it 10% value then it would output 10% and if you put in 100px then it would output 100px

How to make jQuery to not round value returned by .width()?

I've searched around and couldn't find this. I'm trying to get the width of a div, but if it has a decimal point it rounds the number.
Example:
#container{
background: blue;
width: 543.5px;
height: 20px;
margin: 0;
padding: 0;
}
If I do $('#container').width(); it will return 543 instead of 543.5. How do I get it to not round the number and return the full 543.5 (or whatever number it is).
Use the native Element.getBoundingClientRect rather than the style of the element. It was introduced in IE4 and is supported by all browsers:
$("#container")[0].getBoundingClientRect().width
Note: For IE8 and below, see the "Browser Compatibility" notes in the MDN docs.
$("#log").html(
$("#container")[0].getBoundingClientRect().width
);
#container {
background: blue;
width: 543.5px;
height: 20px;
margin: 0;
padding: 0;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container"></div>
<p id="log"></p>
Ross Allen's answer is a good starting point but using getBoundingClientRect().width will also include the padding and the border width which ain't the case the the jquery's width function:
The returned TextRectangle object includes the padding, scrollbar, and
the border, but excludes the margin. In Internet Explorer, the
coordinates of the bounding rectangle include the top and left borders
of the client area.
If your intent is to get the width value with the precision, you'll have to remove the padding and the border like this:
var a = $("#container");
var width = a[0].getBoundingClientRect().width;
//Remove the padding width (assumming padding are px values)
width -= (parseInt(a.css("padding-left")) + parseInt(a.css("padding-right")));
//Remove the border width
width -= (a.outerWidth(false) - a.innerWidth());
Just wanted to add my experience here, though the question's old: The consensus above seems to be that jQuery's rounding is effectively just as good as an unrounded calculation -- but that doesn't seem to be the case in something I've been doing.
My element has a fluid width, generally, but content that changes dynamically via AJAX. Before switching the content, I temporarily lock the dimensions of the element so my layout doesn't bounce around during the transition. I've found that using jQuery like this:
$element.width($element.width());
is causing some funniness, like there are sub-pixel differences between the actual width and the calculated width. (Specifically, I will see a word jump from one line of text to another, indicating the the width has been changed, not just locked.) From another question -- Getting the actual, floating-point width of an element -- I found out that window.getComputedStyle(element).width will return an unrounded calculation. So I changed the above code to something like
var e = document.getElementById('element');
$('#element').width(window.getComputedStyle(e).width);
And with THAT code -- no funny bouncing! That experience seems to suggest that the unrounded value actually does matter to the browser, right? (In my case, Chrome Version 26.0.1410.65.)
You can use getComputedStyle for it:
parseFloat(window.getComputedStyle($('#container').get(0)).width)
Use the following to get an accurate width:
var htmlElement=$('class or id');
var temp=htmlElement[0].style.width;

jQuery offset() not working in some browsers, on some computers

I have a problem positioning an element in certain browsers. I'm using the jQuery autocomplete found here. The div containing autocomplete values should be directly under the text box, and line up perfectly. The code sets the css left property of the div by using the left property generated by $(textbox).offset();
After un-packing the code to try and fix my problem, I get this:
var a = $(textbox).offset();
element.css({
width: typeof e.width == "string" || e.width > 0 ? e.width : $(textbox).width(),
top: a.top + textbox.offsetHeight,
left: a.left
}).show();
This seems like it should work, and it does work in Firefox. It doesn't work in IE8, Chrome. The top position is always correct, but the sometimes the div is too far to the left, or too far to the right.
On different computers (all with Windows XP), it works in IE8... how can this be? I've also tested it on my Mac, OS 10.5. It works in Firefox, but not Safari.
I've disabled plug-ins, changed screen resolutions, re-sized windows... It just inconsistently works in some places sometimes.
Can anyone think of something I'm missing?
UPDATE:
I have re-worked my code to use the autocomplete supplied with jQuery 1.4.2 and jQuery UI 1.8rc3. It is still broken, same problem. Please help!
UPDATE 2:
See this related question. jQuery UI autocomplete breaks because it uses offset. Does anyone have a work around?
Here is the javascript from the UI autocomplete function that trips up:
.css({ top: (offset.top + this.element.height) + 'px', left: offset.left + 'px' })
If it is changed to top: '0px', left: '0px' it works fine, but is obviously positioned in the wrong spot.
I finally figured out what was happening. I had a css rule defining the width of the body:
body {
width: 900px;
}
Once I changed this to width: 100%; and enclosed the entire page in a div of width 900px, it worked as expected.
It looks like IE uses the body element to measure top and left values for offset(), but uses the window edge when to measure top and left distances when positioning an item absolutely.
I hope this answer will save someone else all the time I've wasted on this...
I met a similar question,finally discovered the float property affects relative,making the relative div not stable in Internet Explorer 8 but performs well in firefox.

Firefox and Chrome give different values for offsetTop

I am trying to position an span element (let us call it "the tooltip span") relative to a input field. To do this, I am wrapping the tooltip span and the input field in another span element (let's call it "the wrapper span") that has position: relative. Then I set position: absolute on tooltip span. This makes the tooltip span position itself relative to the wrapper span but not being part of the page flow - not taking up any space. This is exactly what I want.
Then, using javascript, I set the position of the tooltip relative to the position of the input element. Since the input element can be shaped differently on different pages (script should be globablly applicable), I am using its offsetTop and offsetLeft properties to calculate its position relative to the wrapper span.
However, I am noticing inconsistencies between browsers here. In Firefox, IE6, 7, 8, it works as expected. But in Chrome and Safari the reported offsetTop seems, well, incorrect.
To prove this, I created the test page below:
<html>
<head>
<style type="text/css">
span { font-size: 8px; position: relative; top: 0; left: 0; border: 1px solid red }
</style>
</head>
<body>
<span id="wrapper">
<input id="foo" name="foo" type="text">
</span>
<script type="text/javascript">
document.write("<br>Offset parent: " + document.getElementById("foo").offsetParent.id);
document.write("<br>Offset top: " + document.getElementById("foo").offsetTop);
</script>
</body>
</html>
and loaded it in Firefox and Chrome. Both browser report the wrapper span as its offsetParent, but for Firefox the offsetTop is -8 and for Chrome it is 2. Visually the page renders the same in both browsers.
This gives me a headache, because I cannot just hack in a different offset that I always apply when someone is using Chrome, because if I change the font size, the offsetTop will not change, and my script will break.
Is this a bug? Can I solve this differently?
You Can try using
$(window).load
instead of
$(document).ready
because Explorer and Chrome sets proper offsets only after images have been fully loaded.
I've been having the same problem as you and I realized that (in my case) the thing that was messing up the offset().top value in chrome, was having one or more images without the "height" attribute above the element.
Before
<img src="/images/foo.jpg" />
offset.top() was 100 in Chrome
offset.top() was 150 in Firefox and IE7 (beleive or not, it worked just fine in IE!)
After
<img src="/images/foo.jpg" height="50" width="50" />
offset.top() is 150 in both Firefox, IE7, AND CHROME.
Notice the the difference was 50px, which is actually the same as the image height.
Since I was developing a JQuery plugin, i tryed to collect all the images that had their width and height attributes undefined, and manually setting their size with .width() and .height(), but it didn't work, because Chrome returned 0 for both functions. So, i guess the problem with offset.top() actually relies on that. If JQuery is triying to get te offset.top() value by accumulating the "above" element's height, and one of those elements it's an image with no specified height, "0" will be added to that sum, and therefore the top value will be missing those "ignored" heights.
PS: Sorry for my english, it's been a long time since i wrote such a long text in this language!
Use jQuery. DOM differences between browsers is one of the things it excels at.
Put you code into a window.onload function. I recall having issues when attempting to work with the dom directly from a <script> during page load in firefox, and webkit tends to be slightly more willing to give a sane DOM at such points.
This is just based on prior issues i've encountered, i'm not sure if it's applicable to your case.
I ran into the same problem, and jQuery's position() function was reporting the same as the offset() function. Ultimately it turns out that even waiting for the document to be ready didn't work for me. I had to check offset() later in the flow (in my case, in my handler that is fired on a window.scroll event).
When I try this test code below, on page load, I get different figures for Firefox + Chrome. Once it loads, however, I can press 'd' and I get the same figure for both browsers.
// this produced different results on Chrome + Firefox (Chrome was wrong!)
$(document).ready(function () {
var x = $('#some-div-on-your-page').position().top;
alert("On load, offset is "+x); // Chrome + Firefox report diff figures
$(window).keydown(function(e, r) {
k = e ? e.keyCode : event.keyCode;
if(k == 68) { // press 'd'
var x = $('#some-div-on-your-page').position().top;
alert("Now the offset is "+x); // ...but this is consistent
}
});
}
Hope this helps.
I was experiencing the same problem, and tried adding to my function
$(document).ready(function(){});
and it worked in both Chrome and Firefox
If you get "0" in chrome, see if you are targeting an empty element like "a". It needs to wrap something in order to return the correct offset.
It could be related to the different border/margin values for the HTML and body elements that browsers set by default.

Categories