`
yiminghe
  • 浏览: 1431130 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

IE 取得css属性的绝对像素值

阅读更多

问题:

由于 css 属性单位可以设置为 em ,以及 % 来达到流体布局以及弹性布局的效果,但是当 javascript 操作这些元素进行运算时,一般要转换为绝对数值进行运算,比如 offsetWidth ,offsetHeight ,但是不是所有的css属性(padding,margin)都对应上述可以得到直接数值的属性,w3c 规范说明可以使用

 

document.defaultView.getComputedStyle(element,null).getPropertyValue(property);

 来获得相应 css property 的像素绝对值(也不是完美的,存在缩写属性读取问题 ),而 ie 则完全没有办法 ,

 

element.currentStyle.property

 只能获得用户指定的原始css 属性,比如 4em 或 20%,没有设置则为 auto


解决:


Dean Edwards 提出了针对 ie 的处理方式,利用了生僻的ie特有元素属性  runtimeStyle (运行时样式,比style优先级更高, 设置runtimestyle后再修改style对应属性,UI不会有对应变化) ,以及 style 某些属性相应的 pixel 属性,获取到了任意css 属性有效单元的运行时绝对像素数值。

 

From Secrets of the javacript ninja :

 

.runtimeStyle is analogous to .style with one exception: Any style properties set using
.runtimeStyle.prop will override .style.prop (which still leaving the value contained in
.style.prop intact).

.pixelLeft (and Top, Bottom, Right, Height, and Width) are properties for directly accessing the pixel
value of the respective CSS properties. (Note: These could be used as alternatives to even using Dean
Edwards' technique in the first place for these properties - Dean's technique is more useful for things like
font-size, line-height, etc.).

The technique works by setting the current computed left to the runtime left ('left' is chosen arbitrarily
- it could also work with top, right, etc.) - this will keep the positioning of the element intact while we
compute the pixel value. The pixel value is computed by setting the .style.left and then reading the
resulting pixel value out using .style.pixelLeft.

Dean's technique isn't perfect - especially when attempting to handle percentages on elements that are
a child of the body element (they end up expanding to consume a large portion of the document - 10%
becomes 200px, for example) but it ends up working well enough to handle most of the common use cases.

 


演示@google code



核心代码

 

var PIXEL = /^\d+(px)?$/i;
			function getPixelValue(element, value) {
				if (PIXEL.test(value)) return parseInt(value);
				var style = element.style.left;
				var runtimeStyle = element.runtimeStyle.left;
				element.runtimeStyle.left = element.currentStyle.left;
				element.style.left = value || 0;
				value = element.style.pixelLeft;
				element.style.left = style;
				element.runtimeStyle.left = runtimeStyle;
				return value;
			};

 

 

YUI3 解决:

 

dom-style-debug.js


相当于模拟实现了标准浏览器原生的GET_COMPUTED_STYLE:

 

if (!Y.config.win[GET_COMPUTED_STYLE]) {
    Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get; 
}
 

对于 width,height的数值获取采用 offsetWidth 减去 padding和边框的数值 ,而边框,padding,margin以及其他属性的数值则用上述的pixel方法获取。

 

IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;

IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
        IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
        ComputedStyle.getBorderWidth;

IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
        IEComputed.marginLeft = ComputedStyle.getMargin;
 

 

注意: width,height 不能统一用 getPixelValue 来获取数值,width,height似乎有问题(为什么啊??pixelleft不能代表?),所以 yui3 区别判断用了offsetXX ,jquery也存在这个问题:(kissy 和 yui3 保持一致

 

<style>
	#t {
		width:80%;
		position:relative;
		left:80%;
	}
	</style>
<div id="t">
</div>
<script src="http://kissy.googlecode.com/svn/trunk/build/packages/ks-core.js"></script>
<script src="http://kissy.googlecode.com/svn/trunk/build/node/node-pkg-min.js"></script>
	
	
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script type="text/javascript" charset="utf-8"
        src="http://yui.yahooapis.com/3.1.1/build/yui/yui-min.js">
</script>
<script src="http://www.sencha.com/products/core/manual/js/ext-base.js"></script> 
<script src="http://www.sencha.com/products/core/manual/js/extjs.js"></script> 
<script>
	YUI().use("node",function(Y){
	
	var s=KISSY;
		
		alert(s.one("#t").css("width"));
		alert(s.one("#t")[0].offsetWidth);
		alert(Y.one("#t").getStyle("width"));
		alert(Ext.get("t").getStyle("width"));
		alert("jquery : "+$("#t").css("width"));
});
</script>
 

 

 

 

ps:IE color问题

 

同样的,如果color设置为red,black等字符数值,则标准兼容浏览器可以使用getComputedStyle得到16进制数值,而ie则会取得字符串值,dean同样给出了ie专用的方法,利用IE专有的queryCommandValue ?

 

function toHex(color) {
  var body  = createPopup().document.body,
      range = body.createTextRange();
  body.style.color = color;
  var value = range.queryCommandValue("ForeColor");
  value = ((value & 0x0000ff) << 16) | (value & 0x00ff00) | ((value & 0xff0000) >>> 16);
  value = value.toString(16);
  return "#000000".slice(0, 7 - value.length) + value;
};
 

PS: IE 绝对定位 left(top) 问题

 

当元素为绝对定位且不设置left(top)时,ie 使用 currentStyle 取得为 auto,而我们如果使用上述的 pixelLeft可以得到为0,但是实际上由于left是和其相对定位的祖先有关,即使不设置也不为0的,在标准浏览器中可用 getComputedStyle 计算取得,或许有些库使用 offsetLeft 来代替 left ,实际上这是不对的,详见:Ext.Element.setXY 使用注意 bug in IE ? 。KISSY 中对这个问题特殊处理,使用 offsetLeft - margin-left

 

// getComputedStyle for IE
var RE_SPECIAL = /^auto$/i,
    RE_WH = /^width|height$/i,
    RE_LEFT = /^left$/i,
    POSITION = "position";
if (! (doc.defaultView || {}).getComputedStyle && docElem[CURRENT_STYLE]) {
    DOM._getComputedStyle = function (elem, name) {
        var style = elem.style,
            ret = elem[CURRENT_STYLE][name];
        if (RE_SPECIAL.test(ret) && RE_LEFT.test(name)) {
            var position = DOM.css(elem, POSITION);
            //absolute: auto == offsetLeft - margin-left
            if (position == "absolute") ret = elem.offsetLeft - parseInt(DOM.css(elem, "margin-left"));
            //relative: auto ==0
            else ret = 0;
        }....
    }
}
 

 

分享到:
评论
3 楼 sp42 2014-02-23  
for ie8 可以通过 offsetHeight 获取,
for ie7,要使元素大小发生变化,才能获取,如下例,要获取 父级 td 元素 的 高度,怎么获取绝对像素值?
//导入iframe时获取高度并适应
function iFrameHeight(ifm) {  
	if(window.navigator.isFF || window.navigator.isIE8)
		ifm.height  = document.getElementById('tdtd').offsetHeight;
	
	if(window.navigator.isIE7){
		// ie6, ie7 不能通过 offsetHeight 来直接获取绝对的高度,getComputed() 也是返回 ifm.style.height ="auto",于是……
		document.getElementById('tdtd').height = "100%";
		ifm.height  = document.getElementById('tdtd').offsetHeight - 30;
		document.getElementById('tdtd').height = "";
	}
}


只是一个思路。
2 楼 yiminghe 2012-10-12  
hunter3721 写道
@yiminghe:
您认为设置runtimeStyle的目的在于“设置runtimestyle后再修改style对应属性,UI不会有对应变化”
结合您给出的DE的原始代码来看,这个解释可以说得通
但Jquery1.5之后,代码里这里有一点细节变动
导致这个解释有一个无法自圆其说的地方
详见我的一篇blog: http://hunter3721.iteye.com/blog/1697054

我还注意到kissy的源码里,此处的代码是和最新的JQ保持一致的
所以希望yiminghe能帮忙解释一下我的疑惑~


有意思,我都忘了,有空看看答复你
1 楼 hunter3721 2012-10-12  
@yiminghe:
您认为设置runtimeStyle的目的在于“设置runtimestyle后再修改style对应属性,UI不会有对应变化”
结合您给出的DE的原始代码来看,这个解释可以说得通
但Jquery1.5之后,代码里这里有一点细节变动
导致这个解释有一个无法自圆其说的地方
详见我的一篇blog: http://hunter3721.iteye.com/blog/1697054

我还注意到kissy的源码里,此处的代码是和最新的JQ保持一致的
所以希望yiminghe能帮忙解释一下我的疑惑~

相关推荐

Global site tag (gtag.js) - Google Analytics