精确获取样式属性(第2部分)

继续上一部分,我们要看一下颜色。火狐好像不管三七二十一都会转变为rgb格式,不过我们通常比较习惯的是hex格式。这就用到以下两函数。

1. var rgb2hex = function(rgb) {
2.   rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
3.   return "#"+tohex(rgb[1])+tohex(rgb[2])+tohex(rgb[3])
4. }
5. var tohex = function(x) {
6.   var hexDigits = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
7.   return isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
8. }

我们用正则表达式在检测其是否为rgb格式,是就用rgb2hex来转换它。但如果是red,green等值呢,火狐就一反常态,转换为hex格式,但IE依然如故。我们没有办法,自己做一个哈希,把常用的颜色都弄进去,然后一一匹对便是。

01. if(style.search(/background|color/) != -1) {
02.   var color = {
03.     aqua: '#0ff',
04.     black: '#000',
05.     blue: '#00f',
06.     gray: '#808080',
07.     purple: '#800080',
08.     fuchsia: '#f0f',
09.     green: '#008000',
10.     lime: '#0f0',
11.     maroon: '#800000',
12.     navy: '#000080',
13.     olive: '#808000',
14.     orange:'#ffa500',
15.     red: '#f00',
16.     silver: '#c0c0c0',
17.     teal: '#008080',
18.     transparent:'rgba(0,0,0,0)',
19.     white: '#fff',
20.     yellow: '#ff0'
21.   }
22.   if(!!color[value]){
23.     value = color[value]
24.   }
25.   if(value == "inherit"){
26.     return getStyle(el.parentNode,style);
27.   }
28.   if(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.test(value)){
29.     return rgb2hex(value)
30.   }else if(/^#/.test(value)){
31.     value = value.replace('#', '');
32.     return "#" +  (value.length == 3 ? value.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : value);
33.   }
34.   return value;
35. }

基本上是对于CSS的精确取值就是这样,显然它还存在许多不足之处,但对于布局用的和常用的样式都实现了。还提供了一个判断页面渲染模式的常数q,为了方便,方法名与JQuery同名(只能取值,不能赋值,以后有空慢慢与我的addSheet函数整合到一起)。

001. (function(){
002.   var isQuirk = (document.documentMode) ? (document.documentMode==5) ? true : false : ((document.compatMode=="CSS1Compat") ? false : true);
003.   var isElement = function(el) {
004.     return !!(el && el.nodeType == 1);
005.   }
006.   var propCache = [];
007.   var propFloat = !+"\v1" ? 'styleFloat' : 'cssFloat';
008.   var camelize = function(attr){
009.     return attr.replace(/\-(\w)/g, function(all, letter){
010.       return letter.toUpperCase();
011.     });
012.   }
013.   var memorize = function(prop) { //意思为:check out form cache
014.     return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : camelize(prop));
015.   }
016.   var getIEOpacity = function(el){
017.     var filter;
018.     if(!!window.XDomainRequest){
019.       filter = el.style.filter.match(/progid:DXImageTransform.Microsoft.Alpha\(.?opacity=(.*).?\)/i);
020.     }else{
021.       filter = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
022.     }
023.     if(filter){
024.       var value = parseFloat(filter[1]);
025.       if (!isNaN(value)) {
026.         return value ? value / 100 : 0;
027.       }
028.     }
029.     return 1;
030.   }
031.   var convertPixelValue = function(el, value){
032.     var style = el.style,left = style.left,rsLeft = el.runtimeStyle.left;
033.     el.runtimeStyle.left = el.currentStyle.left;
034.     style.left = value || 0;
035.     var px = style.pixelLeft;
036.     style.left = left;//还原数据
037.     el.runtimeStyle.left = rsLeft;//还原数据
038.     return px + "px"
039.   }
040.   var rgb2hex = function(rgb) {
041.     rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
042.     return "#"+tohex(rgb[1])+tohex(rgb[2])+tohex(rgb[3])
043.   }
044.   var tohex = function(x) {
045.     var hexDigits = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
046.     return isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
047.   }
048.   var getStyle = function (el, style){
049.     var value;
050.     if(!+"\v1"){
051.       //特殊处理IE的opacity
052.       if(style == "opacity"){
053.         return getIEOpacity(el)
054.       }
055.       value = el.currentStyle[memorize(style)];
056.       //特殊处理IE的height与width
057.       if (/^(height|width)$/.test(style)){
058.         var values = (style == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
059.         if(isQuirk){
060.           return el[camelize("offset-"+style)] + "px"
061.         }else{
062.           var client = parseFloat(el[camelize("client-"+style)]),
063.           paddingA = parseFloat(getStyle(el, "padding-"+ values[0])),
064.           paddingB = parseFloat(getStyle(el, "padding-"+ values[1]));
065.           return (client - paddingA - paddingB)+"px";
066.         }
067.       }
068.     }else{
069.       if(style == "float"){
070.         style = propFloat;
071.       }
072.       value = document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
073.     }
074.     //下面部分全部用来转换上面得出的非精确值
075.     if(!/^\d+px$/.test(value)){
076.       //转换可度量的值
077.       if(/(em|pt|mm|cm|pc|in|ex|rem|vw|vh|vm|ch|gr)$/.test(value)){
078.         return convertPixelValue(el,value);
079.       }
080.       //转换百分比,不包括字体
081.       if(/%$/.test(value) && style != "font-size"){
082.         return parseFloat(getStyle(el.parentNode,"width")) * parseFloat(value) /100 + "px"
083.       }
084.       //转换border的thin medium thick
085.       if(/^(border).+(width)$/.test(style)){
086.         var s = style.replace("width","style"),
087.         b  = {
088.           thin:["1px","2px"],
089.           medium:["3px","4px"],
090.           thick:["5px","6px"]
091.         };
092.         if(value == "medium" && getStyle(el,s) == "none"){
093.           return "0px";
094.         }
095.         return !!window.XDomainRequest ? b[value][0] : b[value][1];
096.       }
097.       //转换margin的auto
098.       if(/^(margin).+/.test(style) && value == "auto"){
099.         var father = el.parentNode;
100.         if(/MSIE 6/.test(navigator.userAgent) && getStyle(father,"text-align") == "center"){
101.           var fatherWidth = parseFloat(getStyle(father,"width")),
102.           _temp = getStyle(father,"position");
103.           father.runtimeStyle.postion = "relative";
104.           var offsetWidth = el.offsetWidth;
105.           father.runtimeStyle.postion = _temp;
106.           return (fatherWidth - offsetWidth)/2 + "px";
107.         }
108.         return "0px";
109.       }
110.       //转换top|left|right|bottom的auto
111.       if(/(top|left|right|bottom)/.test(style) && value == "auto"){
112.         return el.getBoundingClientRect()[style];
113.       }
114.       //转换颜色
115.       if(style.search(/background|color/) != -1) {
116.         var color = {
117.           aqua: '#0ff',
118.           black: '#000',
119.           blue: '#00f',
120.           gray: '#808080',
121.           purple: '#800080',
122.           fuchsia: '#f0f',
123.           green: '#008000',
124.           lime: '#0f0',
125.           maroon: '#800000',
126.           navy: '#000080',
127.           olive: '#808000',
128.           orange:'#ffa500',
129.           red: '#f00',
130.           silver: '#c0c0c0',
131.           teal: '#008080',
132.           transparent:'rgba(0,0,0,0)',
133.           white: '#fff',
134.           yellow: '#ff0'
135.         }
136.         if(!!color[value]){
137.           value = color[value]
138.         }
139.         if(value == "inherit"){
140.           return getStyle(el.parentNode,style);
141.         }
142.         if(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.test(value)){
143.           return rgb2hex(value)
144.         }else if(/^#/.test(value)){
145.           value = value.replace('#', '');
146.           return "#" +  (value.length == 3 ? value.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : value);
147.         }
148.         return value;
149.       }
150.     }
151.     return value;//如 0px
152.   }
153.   var css = function(){
154.     var a = arguments;
155.     if(a.length == 1){
156.       return getStyle(this,a[0])
157.     }
158.   }
159.   var _ = function(el){
160.     var el = isElement(el)? el :document.getElementById(el);
161.     var gene = !el.constructor ? el : el.constructor.prototype;
162.     gene.css = css;
163.     gene.width = function(){ 
164.       return getStyle(this,"width");
165.     };
166.     gene.height = function(){ 
167.       return getStyle(this,"height");
168.     };
169.     return el
170.   }
171.   if(!window._){ //为了避免与JQuery的$发生冲突,我用_作为类库唯一的全局变量
172.     window['_'] =_;
173.   }
174.   _.q = isQuirk;
175. })()

用法如下:

1. window.onload = function(){
2.   alert(_("ccc").css("background-color"))
3.   alert(_("aaa").css("width"))
4.   alert(_(document.body).width())
5. };

我们可以用这个东西研究一下document.body与document.documentElement。

01. function text(){
02.   var body = document.body,html = document.documentElement;
03.   _("w1").innerHTML = _(body).width();
04.   _("w2").innerHTML = _(html).width();
05.   _("h1").innerHTML = _(body).height();
06.   _("h2").innerHTML = _(html).height();
07.   _("ml1").innerHTML = _(body).css("margin-left");
08.   _("ml2").innerHTML = _(html).css("margin-left");
09.   _("mr1").innerHTML = _(body).css("margin-right");
10.   _("mr2").innerHTML = _(html).css("margin-right");
11.   _("mt1").innerHTML = _(body).css("margin-top");
12.   _("mt2").innerHTML = _(html).css("margin-top");
13.   _("mb1").innerHTML = _(body).css("margin-bottom");
14.   _("mb2").innerHTML = _(html).css("margin-bottom");
15.   _("pl1").innerHTML = _(body).css("padding-left");
16.   _("pl2").innerHTML = _(html).css("padding-left");
17.   _("pr1").innerHTML = _(body).css("padding-right");
18.   _("pr2").innerHTML = _(html).css("padding-right");
19.   _("bl1").innerHTML = _(body).css("border-left-width");
20.   _("bl2").innerHTML = _(html).css("border-left-width");
21.   _("br1").innerHTML = _(body).css("border-right-width");
22.   _("br2").innerHTML = _(html).css("border-right-width");
23.   _("qqq").innerHTML = !_.q ? "标准模式" : "怪癖模式";
24.   _("t1").innerHTML = _(body).css("top");
25.   _("t2").innerHTML = _(html).css("top");
26.   _("l1").innerHTML = _(body).css("left");
27.   _("l2").innerHTML = _(html).css("left");
28.   _("ot1").innerHTML = body.offsetTop;
29.   _("ot2").innerHTML = html.offsetTop;
30.   _("ol1").innerHTML = body.offsetLeft;
31.   _("ol2").innerHTML = html.offsetLeft;
32.   _("ct1").innerHTML = body.clientTop;
33.   _("ct2").innerHTML = html.clientTop;
34.   _("cl1").innerHTML = body.clientLeft;
35.   _("cl2").innerHTML = html.clientLeft;
36.   _("cw1").innerHTML = body.clientWidth;
37.   _("cw2").innerHTML = html.clientWidth;
38.   _("ow1").innerHTML = body.offsetWidth;
39.   _("ow2").innerHTML = html.offsetWidth;
40.   _("sw1").innerHTML = body.scrollWidth;
41.   _("sw2").innerHTML = html.scrollWidth;
42. }

在标准模式下,火狐等浏览器中我们看到offsetWidth等值最大为1007,因为火狐的offsetWidth不大于clientWidth,而clientWidth是不包含滚动条(滚动条的宽都固定为17px)。在IE中,offsetWidth是比clientWidth多了两个border,由此发现问题,1024-1003-17=4,4应该是两个auto生成,而这个auto应该为border的值,这两个border在IE中是固定死,不能通过以下手段修改。

1. <style type="text/css">
2.   html{
3.     border: 0;
4.   }
5. </style>

换言之,在标准模式下,IE的html是存在不可修改的宽为2px的border。也换言之,我的程序是有个BUG,没有正确显示出html的border为2px,囧。

再看怪癖模式,

测试属性 document.body document.documentElement
width 1024px 1024px
height 604px 604px
margin-left 0px undefined
margin-right 0px undefined
margin-top 0px undefined
margin-bottom 0px undefined
padding-left 0px 0px
padding-right 0px 0px
border-left-width 4px 0px
border-right-width 4px 0px
渲染模式 怪癖模式
top 0 0
left 0 0
offsetTop 0 0
offsetLeft 0 0
clientTop 2 0
clientLeft 2 0
offsetWidth 1024 1024
clientWidth 1003 0
scrollWidth 1003 1024

火狐等没有所谓的怪癖模式,直接看IE的。发现那神秘的2px又出现,这时出现在document.body的clientTop,clientLeft中。那么怪癖模式下的document.body的clientTop,clientLeft又相当于CSS的什么概念呢?我们来看微软给出的一幅老图,那时IE5独步天下,没有所谓标准模式与怪癖模式之分,因此这幅图的东西都是按怪癖模式表示的。

精确获取样式属性(第2部分)

不难看出,clientLeft相当于borderLeft,clientTop相当于borderTop。至于上面的border-left-width与border-right-width,就不要看了,是错误,因为我当初就没有考虑这两个元素在标准模式与怪癖模式下的问题。既然document.body的边框区就达1024px了,那么html元素的脸往哪里搁呢?!对不起,在微软早期的设想,body元素才是代表文档(一个强有力的证据是,在怪癖模式下,网页的滚动条是位于body元素中)。模准模式连同火狐那帮失败者宣扬的各种没有市场份额的“标准”,都是在微软极不情愿下支持的。你看,documentElement这样累赘傻气的名字像是微软起的吗?!如果是微软,它应该就叫html,和document.boy那样简洁。搞到在标准模式下,我们取scrollLeft,要用document.documentElement.scrollLeft,因为这时body不存在滚动条;在怪癖模式下,要用document.body,虽然微软以打补丁的方法添加上document.documentElement(真拗口,难怪网景会失败),但滚动条的位置不是说变就变。
来源:http://www.cnblogs.com/rubylouvre/archive/2009/09/08/1562212.html

你可能感兴趣的:(样式)