How can I get the computed width of an element in Opera? In other browsers I can do this:
// getComputedStyle wrapper
function getStyle(element, styleProp) {
return element.currentStyle ? element.currentStyle[styleProp] :
getComputedStyle(element, null).getPropertyValue(styleProp);
}
...but this only sort of works on Opera. It returns "auto" for a lot of things instead of a useful pixel value.
Here's a live demo that expands some text to fit in a box. It doesn't work on Opera, because the computed width is auto instead of a px value as in other browsers.
How can I get more useful computed styles, such as the pixel width of an element, in Opera?
I realize that I can, in this case, use offsetWidth instead of getting the computed style. I appreciate the advice, but the real point of this question is that I want to know how to get computed styles in Opera where the style is actually computed in units. I don't care about offsetWidth for the purposes of this question.
What CSS calls "computed value" isn't always what you expect. I guess Opera follows the spec to the T here while the other browsers do something they consider more useful.
I'd suggest using element.offsetWidth instead of getComputedStyle() for this purpose.
It also fails in IE <= 8
The reason is because currentStyle and getComputedStyle work differently in this case. If you were testing for getComputedStyle first it would work in both Opera and IE 9-10. Opera tries to mimic IE in a lot of cases (see innerText vs textContent), so it has currentStyle too.
BUT please note that you lose your "expected" behavior if the element in question has display:inline in it's style (FF, Chrome, IE), because they will report "auto" for you... except... you guessed it, in Opera which will then show you the "correct" px width of the element.
If you want a general purpose function you better off including a general purpose library (which as you will find are filled with edge cases you will never need). If you have a specific purpose to solve you can use a compatible replacement.
Computed style isn't really useful for you in this case. What you need is probably clientWidth, offsetWidth or scrollWidth depending on your needs. They differ mainly in whether you want to include padding, border, margin and/or clipped areas (in case of horizontally overflowing content).
They are supported even on ancient browsers like IE 6, in fact these properties were first introduced by MS back in the first browser war (just like innerHTML).
You can read more about them by googling with MSDN or MDN.
There shouldn't be any reason this has to be difficult if you keep your code well structured, never put script elements as children to the body element even if it validates as it will lead to very poor coding practices. On the other hand I commend you for using appendChild instead of the unreliable innerHTML so at least you're making an effort to not take the lazy route.
Use an anonymous function for the onload event so you can execute more than one function obviously. I'm not familiar with glyphs (SVG?) so I was not able to get any browser to render the glyph at anything other than 7px.
Here is the reworked code...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>get computed width in pixels in Opera</title>
<script type="application/javascript">
//<![CDATA[
// getComputedStyle wrapper
function getStyle(element, styleProp)
{
return element.currentStyle ? element.currentStyle[styleProp] : getComputedStyle(element, null).getPropertyValue(styleProp);
}
// cheesy convenience function
function textDiv(textContent, className)
{
var tmp = document.createElement('div');
if (className) tmp.className = className;
tmp.appendChild(document.createTextNode(textContent));
return tmp;
}
window.onload = function()
{
var box = document.getElementById('box'),glyph = box.appendChild(textDiv('g', 'glyph')),size=500;
glyph.style.position = 'absolute';
/*
document.getElementById('status').appendChild(textDiv('Initial computed width: ' + getStyle(glyph, 'width')));
while (parseInt(getStyle(glyph, 'width'), 10) < 100)
{
glyph.style.fontSize = size++ + '%';
}
*/
document.getElementById('status').appendChild(document.createTextNode(document.getElementById('box').firstChild.scrollWidth+'px'));
}
//]]>
</script>
</head>
<body>
<div id="status"></div>
<div id="box"></div>
</body>
</html>
You can use this code to get the property in Opera:
document.defaultView.getComputedStyle(element,null).getPropertyValue(styleProp);
Related
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>
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
I have no idea why, but clientWidth and clientHeight are always returning zero when I run this from IE in IE9 compat View, or IE7. It works for everything else.
Very simple code snippet with problem (so that you can try it too):
http://jsfiddle.net/nz2DA/
The code snippet found above is as follows...
I have a page containing the following HTML snippet:
<div id='aaa'>aaaaaa</div>
And my javascript to test the clientWidth and clientHeight functions are as follows:
var el = $('#aaa')[0];
alert('Client width and height: '+ el.clientWidth + ' X ' + el.clientHeight);
This always pops up an alert with "0 X 0" when I run in IE7 or IE9 Compatibility mode.
Any help or explanation would really be appreciated. Thanks!
This is happening because of the "hasLayout" property in IE, and your div on its own does not "have layout". For more information, see http://www.satzansatz.de/cssd/onhavinglayout.html
Luckily you can trigger an element to have layout, which is why adding the "float:left" style works in the answer above. There are other triggers you can use too though that don't change the page. This one gives me proper values for clientWidth and clientHeight:
<div id="aaa" style="zoom: 1">aaaaaa</div>
The article says that setting "min-width: 0" should also work but it didn't for me. Setting "display: inline-block" worked OK but that might change your page. You can set these triggers in CSS so that the HTML doesn't need to change at all.
I tested your code and following are the observations.
in IE(sucks!), if you didn't apply any styles for the "aaa" element IE won't calculate any width and height. So JS simply give you 0. But if you look at the box model from the IE dev tool bar you will see some value. So if you use float:left to that element JS will return a value, which is correct and all browsers will give you the same output.
Since you are using jQuery why don't you use width() or outerWidth() or innerWidth(). These methods are generelaized for the every browsers. Simply if you use width() you will see a very large width since you didn't apply any styles. In IE if element doesn't have an float value it gets it's parent width.In your case it's window width.
So if I modify your code to get correct width and height would be:
HTML:
<div id="aaa" style="float:left;">aaaaaa</div>
JS:
var el = $('#aaa')[0];
alert('Client width and height: '+ el.clientWidth + ' X ' + el.clientHeight);
Please let me know if you need more clarifications...
cheers!
Try offsetHeight property of internet explorer.
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
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.