jquery css() 方法的分析 于bug .
bug 描述 当 element 的 css font-size:100% 此类百分比值的时候 我们将得到的是个错误的值
而这个值是什么呢? 也许大家猜到了。 是的 就是父容器的 clientWidth*这个百分比
之所以会这样的原因是 因为 他的代码如下:
if(elem.currentStyle){//
r=elem.currentStyle [ styleString];//取到相应css属性的最终渲染值
if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
var left = style.left, rsLeft = elem.runtimeStyle.left;
elem.runtimeStyle.left = elem.currentStyle.left;
style.left = ret || 0;
ret = style.pixelLeft + "px";
style.left = left;
elem.runtimeStyle.left = rsLeft;
}
return ret;
解释下上面的代码 这里判断 如果 取到的r 的内容是数字开头 且不是 px结尾的 就要做 转换了 比如 100% 20em 30pt ex in之类的
如何转换呢? 本来是有转换公式的 比如 n em==n*16 px , n pt==Math.floor(n*3/4) px 等等 但是jquery的方法就巧妙的很. 因为一旦值是 百分比
那么 对于 padding left top bottom right line-height margin 等等 所有的 % 都是和当前元素的父元素的 clientWidth 乘法运算得出的值....
这个原因 请去w3c手册自行查看 .现在 我们只要 去取父元素的 clientWidth 乘就是了 但是缺点是我们要为可能出现的 各种单位 去做 switch 还要正则匹配 取出 单位 然后要对不同单位应用不同的换算公式。 麻烦无比...
那么 jquery的做法 就是 如上面的代码 他 暂时把 当前元素的style.left 给一个变量保存 然后把 r 的值 (不管他是 em % pt 还是什么)赋给 style.left 那么
当前元素的left位置自然会发生变化 这个时候 再通过 element.pixelLeft 自动换算出这个值对应的 px值 . 这样我们就取到了 正确的 px值了 这样行为就和
defaultView 的结果是一致的 都自动转换成了px . 然后再把 原来的 style.left的值 覆盖回去 恢复元素的style.left位置.
其中要提的是 element.runtimeStyle 为什么这里也把他临时覆盖了呢? 可能是出于 保险。比如 其他代码中可能更改了此值 因为 runtimeStyle的优先级 要高越style... 所以为了pixelLeft取出正确的值 所以 也覆盖了element.runtimeStyle.
那么bug来了 ie 中 字体的 % 百分比 是相对默认字体大小的 . 而这里他却 去和父容器的 clientWidth 去换算了 显然得出的值是错误的。
所以 应该如此判断 :(下面的代码是伪代码 jquery里跑不了 但思路是可以用的)
var b = false;
if (/^\d+/.test(r = node.currentStyle[styleString = ns.String.camelize(styleString)])) {
if (!(b = /^font/.test(styleString)) || (b && r.match(/\D+$/)[0] != '%')) {
var left = node.style.left, rsLeft = node.runtimeStyle.left;
node.runtimeStyle.left = node.currentStyle.left;
node.style.left = r || 0;
r = node.style.pixelLeft;
node.style.left = left;
node.runtimeStyle.left = rsLeft;
return parseInt(r);
}
else if (node != document.body) return Math.floor(parseInt(r) * (parseInt(getCurrentStyle(document.body, 'font-size')) || 16) / 100);
else return Math.floor(parseInt(r) * 16 / 100);
那么接着说一说其他小bug.
这个bug本质来说和jquery无关 。是ie本身的问题 也就是 currentStyle的另外的问题
当 styleString为 float的时候 用currentStyle.cssFloat 这个大家都知道。
但问题是 ie 中 当前节点为 absolute 或relative fixed的时候 很显然float是会失去作用的 那么其他浏览器 会最终返回none 无论你float里是不是 left 或right 他都返回none 因为浏览器最终渲染 是none 所以很明显ie这里 返回 left或right是不对的.那么我们就判断下好了
f (styleString == 'float') return ns.String.isInList(node.currentStyle.position, ['absolute', 'relative','fixed']) ? 'none' : node.currentStyle.styleFloat;
当然 这里认真的话还要判断ie6 fixed无效 所以渲染是有效的 问题. 不过 既然ie6 fixed无效 一般来说会给 ie 用absolute css hack 来模拟fixed 所以 判断不判断 无所谓了.
还有功能上的疑问。 我不明白为什么jquery 不把 非ie浏览器 defaultView取出 的颜色值 如 rgb(255,255,255) 转换成 #ffffff 再返回 这样做不是更方便外面使用么? 可能是 因为他的set方法允许 此类参数吧. 但是我还是觉得转换一下的好
if (r.indexOf('rgb(', 0) >= 0) {
var color = r;
r = '';
color.replace(/\d{1,3}/g, function(m) {
m = parseInt(m).toString(16);
r += m.length == 2 ? m : m = 0 + m;
});
return '#' + r;
}
暂时就这些 至于其他的 如 left top 等值 不同浏览器不同 定位 等情况返回值差异问题 我觉得就没必要修复或统一...1是很麻烦. 再就是 我们可以用 element.offset来代替 可以直接的统一 ...