精确获取样式属性(第2部分)
继续上一部分,我们要看一下颜色。火狐好像不管三七二十一都会转变为rgb格式,不过我们通常比较习惯的是hex格式。这就用到以下两函数。
var rgb2hex = function (rgb) { rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); return "#" +tohex(rgb[1])+tohex(rgb[2])+tohex(rgb[3]) } var tohex = function (x) { var hexDigits = [ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' ]; return isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16]; } |
我们用正则表达式在检测其是否为rgb格式,是就用rgb2hex来转换它。但如果是red,green等值呢,火狐就一反常态,转换为hex格式,但IE依然如故。我们没有办法,自己做一个哈希,把常用的颜色都弄进去,然后一一匹对便是。
if (style.search(/background|color/) != -1) { var color = { aqua: '#0ff' , black: '#000' , blue: '#00f' , gray: '#808080' , purple: '#800080' , fuchsia: '#f0f' , green: '#008000' , lime: '#0f0' , maroon: '#800000' , navy: '#000080' , olive: '#808000' , orange: '#ffa500' , red: '#f00' , silver: '#c0c0c0' , teal: '#008080' , transparent: 'rgba(0,0,0,0)' , white: '#fff' , yellow: '#ff0' } if (!!color[value]){ value = color[value] } if (value == "inherit" ){ return getStyle(el.parentNode,style); } if (/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.test(value)){ return rgb2hex(value) } else if (/^ #/.test(value)){ value = value.replace( '#' , '' ); return "#" + (value.length == 3 ? value.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3' ) : value); } return value; } |
基本上是对于CSS的精确取值就是这样,显然它还存在许多不足之处,但对于布局用的和常用的样式都实现了。还提供了一个判断页面渲染模式的常数q,为了方便,方法名与JQuery同名(只能取值,不能赋值,以后有空慢慢与我的addSheet函数整合到一起)。
( function (){ var isQuirk = (document.documentMode) ? (document.documentMode==5) ? true : false : ((document.compatMode== "CSS1Compat" ) ? false : true ); var isElement = function (el) { return !!(el && el.nodeType == 1); } var propCache = []; var propFloat = !+ "\v1" ? 'styleFloat' : 'cssFloat' ; var camelize = function (attr){ return attr.replace(/\-(\w)/g, function (all, letter){ return letter.toUpperCase(); }); } var memorize = function (prop) { //意思为:check out form cache return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : camelize(prop)); } var getIEOpacity = function (el){ var filter; if (!!window.XDomainRequest){ filter = el.currentStyle.filter.match(/progid:DXImageTransform.Microsoft.Alpha\(.?opacity=(.*).?\)/i); } else { filter = el.currentStyle.filter.match(/alpha\(opacity=(.*)\)/i); } if (filter){ var value = parseFloat(filter[1]); if (!isNaN(value)) { return value ? value / 100 : 0; } } return 1; } var convertPixelValue = function (el, value){ var style = el.style,left = style.left,rsLeft = el.runtimeStyle.left; el.runtimeStyle.left = el.currentStyle.left; style.left = value || 0; var px = style.pixelLeft; style.left = left; //还原数据 el.runtimeStyle.left = rsLeft; //还原数据 return px + "px" } var rgb2hex = function (rgb) { rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); return "#" +tohex(rgb[1])+tohex(rgb[2])+tohex(rgb[3]) } var tohex = function (x) { var hexDigits = [ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' ]; return isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16]; } var getStyle = function (el, style){ var value; if (!+ "\v1" ){ //特殊处理IE的opacity if (style == "opacity" ){ return getIEOpacity(el) } value = el.currentStyle[memorize(style)]; //特殊处理IE的height与width if (/^(height|width)$/.test(style)){ var values = (style == 'width' ) ? [ 'left' , 'right' ] : [ 'top' , 'bottom' ], size = 0; if (isQuirk){ return el[camelize( "offset-" +style)] + "px" } else { var client = parseFloat(el[camelize( "client-" +style)]), paddingA = parseFloat(getStyle(el, "padding-" + values[0])), paddingB = parseFloat(getStyle(el, "padding-" + values[1])); return (client - paddingA - paddingB)+ "px" ; } } } else { if (style == "float" ){ style = propFloat; } value = document.defaultView.getComputedStyle(el, null ).getPropertyValue(style) } //下面部分全部用来转换上面得出的非精确值 if (!/^\d+px$/.test(value)){ //转换可度量的值 if (/(em|pt|mm|cm|pc| in |ex|rem|vw|vh|vm|ch|gr)$/.test(value)){ return convertPixelValue(el,value); } //转换百分比,不包括字体 if (/%$/.test(value) && style != "font-size" ){ return parseFloat(getStyle(el.parentNode, "width" )) * parseFloat(value) /100 + "px" } //转换border的thin medium thick if (/^(border).+(width)$/.test(style)){ var s = style.replace( "width" , "style" ), b = { thin:[ "1px" , "2px" ], medium:[ "3px" , "4px" ], thick:[ "5px" , "6px" ] }; if (value == "medium" && getStyle(el,s) == "none" ){ return "0px" ; } return !!window.XDomainRequest ? b[value][0] : b[value][1]; } //转换margin的auto if (/^(margin).+/.test(style) && value == "auto" ){ var father = el.parentNode; if (/MSIE 6/.test(navigator.userAgent) && getStyle(father, "text-align" ) == "center" ){ var fatherWidth = parseFloat(getStyle(father, "width" )), _temp = getStyle(father, "position" ); father.runtimeStyle.postion = "relative" ; var offsetWidth = el.offsetWidth; father.runtimeStyle.postion = _temp; return (fatherWidth - offsetWidth)/2 + "px" ; } return "0px" ; } //转换top|left|right|bottom的auto if (/(top|left|right|bottom)/.test(style) && value == "auto" ){ return el.getBoundingClientRect()[style]; } //转换颜色 if (style.search(/background|color/) != -1) { var color = { aqua: '#0ff' , black: '#000' , blue: '#00f' , gray: '#808080' , purple: '#800080' , fuchsia: '#f0f' , green: '#008000' , lime: '#0f0' , maroon: '#800000' , navy: '#000080' , olive: '#808000' , orange: '#ffa500' , red: '#f00' , silver: '#c0c0c0' , teal: '#008080' , transparent: 'rgba(0,0,0,0)' , white: '#fff' , yellow: '#ff0' } if (!!color[value]){ value = color[value] } if (value == "inherit" ){ return getStyle(el.parentNode,style); } if (/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.test(value)){ return rgb2hex(value) } else if (/^ #/.test(value)){ value = value.replace( '#' , '' ); return "#" + (value.length == 3 ? value.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3' ) : value); } return value; } } return value; //如 0px } var css = function (){ var a = arguments; if (a.length == 1){ return getStyle( this ,a[0]) } } var _ = function (el){ var el = isElement(el)? el :document.getElementById(el); var gene = !el.constructor ? el : el.constructor.prototype; gene.css = css; gene.width = function (){ return getStyle( this , "width" ); }; gene.height = function (){ return getStyle( this , "height" ); }; return el } if (!window._){ //为了避免与JQuery的$发生冲突,我用_作为类库唯一的全局变量 window[ '_' ] =_; } _.q = isQuirk; })() |
用法如下:
window.onload = function (){ alert(_( "ccc" ).css( "background-color" )) alert(_( "aaa" ).css( "width" )) alert(_(document.body).width()) }; |
我们可以用这个东西研究一下document.body与document.documentElement。
function text(){ var body = document.body,html = document.documentElement; _( "w1" ).innerHTML = _(body).width(); _( "w2" ).innerHTML = _(html).width(); _( "h1" ).innerHTML = _(body).height(); _( "h2" ).innerHTML = _(html).height(); _( "ml1" ).innerHTML = _(body).css( "margin-left" ); _( "ml2" ).innerHTML = _(html).css( "margin-left" ); _( "mr1" ).innerHTML = _(body).css( "margin-right" ); _( "mr2" ).innerHTML = _(html).css( "margin-right" ); _( "mt1" ).innerHTML = _(body).css( "margin-top" ); _( "mt2" ).innerHTML = _(html).css( "margin-top" ); _( "mb1" ).innerHTML = _(body).css( "margin-bottom" ); _( "mb2" ).innerHTML = _(html).css( "margin-bottom" ); _( "pl1" ).innerHTML = _(body).css( "padding-left" ); _( "pl2" ).innerHTML = _(html).css( "padding-left" ); _( "pr1" ).innerHTML = _(body).css( "padding-right" ); _( "pr2" ).innerHTML = _(html).css( "padding-right" ); _( "bl1" ).innerHTML = _(body).css( "border-left-width" ); _( "bl2" ).innerHTML = _(html).css( "border-left-width" ); _( "br1" ).innerHTML = _(body).css( "border-right-width" ); _( "br2" ).innerHTML = _(html).css( "border-right-width" ); _( "qqq" ).innerHTML = !_.q ? "标准模式" : "怪癖模式" ; _( "t1" ).innerHTML = _(body).css( "top" ); _( "t2" ).innerHTML = _(html).css( "top" ); _( "l1" ).innerHTML = _(body).css( "left" ); _( "l2" ).innerHTML = _(html).css( "left" ); _( "ot1" ).innerHTML = body.offsetTop; _( "ot2" ).innerHTML = html.offsetTop; _( "ol1" ).innerHTML = body.offsetLeft; _( "ol2" ).innerHTML = html.offsetLeft; _( "ct1" ).innerHTML = body.clientTop; _( "ct2" ).innerHTML = html.clientTop; _( "cl1" ).innerHTML = body.clientLeft; _( "cl2" ).innerHTML = html.clientLeft; _( "cw1" ).innerHTML = body.clientWidth; _( "cw2" ).innerHTML = html.clientWidth; _( "ow1" ).innerHTML = body.offsetWidth; _( "ow2" ).innerHTML = html.offsetWidth; _( "sw1" ).innerHTML = body.scrollWidth; _( "sw2" ).innerHTML = html.scrollWidth; } |
在标准模式下,火狐等浏览器中我们看到offsetWidth等值最大为1007,因为火狐的offsetWidth不大于clientWidth,而clientWidth是不包含滚动条(滚动条的宽都固定为17px)。在IE中,offsetWidth是比clientWidth多了两个border,由此发现问题,1024-1003-17=4,4应该是两个auto生成,而这个auto应该为border的值,这两个border在IE中是固定死,不能通过以下手段修改。
< style type="text/css"> html{ border: 0; } </ style > |
换言之,在标准模式下,IE的html是存在不可修改的宽为2px的border。也换言之,我的程序是有个BUG,没有正确显示出html的border为2px,囧。
再看怪癖模式,
测试属性 | document.body | document.documentElement |
---|---|---|
width | ||
height | ||
margin-left | ||
margin-right | ||
margin-top | ||
margin-bottom | ||
padding-left | ||
padding-right | ||
border-left-width | ||
border-right-width | ||
渲染模式 | ||
top | ||
left | ||
offsetTop | ||
offsetLeft | ||
clientTop | ||
clientLeft | ||
offsetWidth | ||
clientWidth | ||
scrollWidth |
火狐等没有所谓的怪癖模式,直接看IE的。发现那神秘的2px又出现,这时出现在document.body的clientTop,clientLeft中。那么怪癖模式下的document.body的clientTop,clientLeft又相当于CSS的什么概念呢?我们来看微软给出的一幅老图,那时IE5独步天下,没有所谓标准模式与怪癖模式之分,因此这幅图的东西都是按怪癖模式表示的。

不难看出,clientLeft相当于borderLeft,clientTop相当于borderTop。至于上面的border-left-width与border-right-width,就不要看了,是错误,因为我当初就没有考虑这两个元素在标准模式与怪癖模式下的问题。既然document.body的边框区就达1024px了,那么html元素的脸往哪里搁呢?!对不起,在微软早期的设想,body元素才是代表文档(一个强有力的证据是,在怪癖模式下,网页的滚动条是位于body元素中)。模准模式连同火狐那帮失败者宣扬的各种没有市场份额的“标准”,都是在微软极不情愿下支持的。你看,documentElement这样累赘傻气的名字像是微软起的吗?!如果是微软,它应该就叫html,和document.boy那样简洁。搞到在标准模式下,我们取scrollLeft,要用document.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义