JavaScript exactly gets style attributes (top) _javascript tips

Source: Internet
Author: User
Tags css inherit
Jquery,mootools,ext such as the library in this part of the implementation of a very difficult, intertwined with a large number of methods, so want to make this part of the difficult to dig out. After in-depth study of their implementation, according to my accumulated CSS knowledge, finally make a very conciseness version out. It is equivalent to Jquery.csscur bar, but perhaps the function is also rich, according to the catering industry said "No increase in quantity", I may also be called "Increase in price" ... The version is still in beta, because only a single tool function is not a class.
Copy Code code as follows:

var getstyle = function (el, style) {
if (!+ "\v1") {
style = Style.replace (/\-(\w)/g, function (all, letter) {
return Letter.touppercase ();
});
return El.currentstyle[style];
}else{
Return Document.defaultView.getComputedStyle (EL, null). GetPropertyValue (Style)
}
}

This is the most original state of the function, because the used value is the people from the same side of the Document.defaultView.getComputedStyle, so the basic link does not move to solve the 99 problem. IE side of the complex, although Microsoft engaged in Style,currentstyle and Runtimestyle, but there is no one with getComputedStyle close to the implementation, the closest is Currentstyle, it can only take to the internal style, And we're going to have to convert the CSS properties into hump style when we take the value. For convenience, I will now separate it out.
Copy Code code as follows:

var camelize = function (attr) {
Return Attr.replace (/\-(\w)/g, function (all, letter) {
return Letter.touppercase ();
});
}

Then we alone to solve the problem of IE transparency, the basic types of libraries are doing so, it can be seen how difficult the problem, I really want to thank Microsoft for the talent:
Copy Code code as follows:

var getieopacity = function (EL) {
var filter;
if (!! Window. Xdomainrequest) {
Filter = El.style.filter.match (/progid:dximagetransform.microsoft.alpha\ (.?) Opacity= (. *). \)/i);
}else{
Filter = El.style.filter.match (/alpha\ (opacity= (. *) \)/i);
}
if (filter) {
var value = parsefloat (filter[1]);
if (!isnan (value)) {
return value? value/100:0;
}
}
return 1;
}

And then our function becomes like this:
Copy Code code as follows:

var getstyle = function (el, style) {
if (!+ "\v1") {
if (style = = "opacity") {
Return Getieopacity (EL)
}
return el.currentstyle[camelize (style)];
}else{
Return Document.defaultView.getComputedStyle (EL, null). GetPropertyValue (Style)
}
}

Then down float the property problem. IE this is stylefloat,w3c is cssfloat. Solve is not a problem, but each time to change too much trouble, I refer to the implementation of ext to cache them.
Copy Code code as follows:

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) {//meaning: Check out form cache
return Propcache[prop] | | (Propcache[prop] = prop = = ' float ' propfloat:camelize (prop));
}
var getieopacity = function (EL) {
Slightly **********************
}
var getstyle = function (el, style) {
if (!+ "\v1") {
if (style = = "opacity") {
Return Getieopacity (EL)
}
return el.currentstyle[memorize (style)];
}else{
if (style = = "float") {
style = Propfloat;
}
Return Document.defaultView.getComputedStyle (EL, null). GetPropertyValue (Style)
}
}

To the hardest part--Get the height and width exactly. If anyone who has ever used jquery knows, John Resig is dealing with these two attributes alone. In fact, more than jquery, other libraries have headaches. The cause of the problem is that if you do not explicitly set these two attributes without inline styles or internal styles, we cannot get their exact values under IE, or get a percentage, an empty string, a auto,inhert, and so on. Another, for the Chinese, PX status is much higher than EM. For the total reason, let's not give up these two attributes. In order to get the exact value of these two attributes, we need to study the CSS inheritance problem. I have also written related blog "CSS Inhert and auto" to explore this issue, did not see, please read back again, or, simply can not see the.
According to the classification of CSS, width and height are attributes to the Non-inherited property, so that if we do not set a value for it, the default is auto. This auto is a magical thing, if it is a block element, its width is equal to 100%, supporting the content area of the parent element, of course, this is without considering its padding,border and margin. If the inline element, because does not have the box model, you give it to set wide and high is meaningless, even in Firefox, the return of the correct conversion of the exact value and you see the situation completely does not match, if not set, directly return to auto. In order to obtain the exact value px, we need to convert the idea to block elements and inline elements, but the light is staring at the CSS properties. At this time, Microsoft did a good deed, developed the OFFSETXX,CLIENTXX and SCROLLXX three big family, now finally incorporates the standard of the consortium. But before that, browsers had come to the end.
In standard mode, the offsetwidth is comprised of padding,borderwidth and width, and if there is a scroll bar, its offsetwidth will not change, the width of the scroll bar in the browser is very consistent, 17px, At this time it will be the width minus 17px, the missing space by the scroll bar to fill. Offsetwidth if there is padding and padding, we will subtract padding and padding in the eccentricity mode, offsetwidth equals width, and width is padding and borderwidth. Offsetheight the same. The Clientxx family has a good understanding that it does not contain borderwidth and scroll bars. The SCROLLXX family does not say, in the five big browsers are inconsistent. Therefore, in standard mode, to achieve high and wide, the preferred Clientxx family, the eccentricity pattern, first offsetxx family.
At this time have to say the quirks mode, do not think to IE8, set the corresponding DOCTYPE can escape a robbery, as long as your Web page too many places do not follow the standard, IE also into a compatible mode of operation. Whether this compatibility mode is equal to the eccentricity mode is not necessary, because IE8 has up to five rendering modes, IE5 quirks mode, IE7 Standard mode, IE8 almost standard mode, IE7 compatibility mode and support HTML5 edge mode. So many patterns, do you think document.compatmode = = "Css1compat" can hold?! Can't hold on, fortunately IE8 added a new mode at the same time, added a Document.documentmode attribute, really do not know is happy or sad. So the code that determines whether to run in quirks mode is:
http://www.mangguo.org/x-ua-compatible-ie8-compatible-mode/
Copy Code code as follows:

var Isquirk = (document.documentmode)? (document.documentmode==5)? true:
False: ((document.compatmode== "Css1compat")? false:true);

So we have the following pseudo code:
Copy Code code as follows:

var getwidth = function (EL) {
if (Isquirk) {
Return El.offsetwidth
}else{
Return El.clientwidth-parsefloat (GetStyle (el, "Padding-left"))-parsefloat (GetStyle (el, "Padding-right"))
}
}

Compare the implementation of EXT (only the core part):
Copy Code code as follows:

Getwidth:function (contentwidth) {
var me = this,
Dom = Me.dom,
W = Math.max (dom.offsetwidth, dom.clientwidth) | | 0;
W =!contentwidth? W:w-Me.getborderwidth ("LR")-me.getpadding ("LR");
Return W < 0? 0:w;
},

A very dangerous approach, which is worse than the prototype implementation, so it must not be corrected in other parts, which is why its UI is so bulky that it also highlights the sophistication of jquery implementations from the side. However, the implementation of jquery is also quite complex, if this element can not get accurate value, starting from the superior element, this traversal consumption is very serious. Which also borrows a great hack from Dean Edwards:
Copy Code code as follows:

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;
}
This function is provided by Dean Edwards, the earliest source of which is shown in the link below
http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
Note that the second parameter must be a number with units, such as Em ', ' ex ', ' cm ', ' mm ', ' in ', ' pt ', ' PC '
Percent seems to be a problem
Also, do not attempt to use a browser other than IE
Usage: Convertpixelvalue ($ ("Drag4"), ' 10em ')
var convertpixelvalue = function (el, styleval) {
Save the original value to left and Rsleft
var style = El.style,left = Style.left,rsleft = El.runtimeStyle.left;
The next step is the key,
Turn El.currentStyle.left into el.runtimeStyle.left, activate hack
El.runtimeStyle.left = El.currentStyle.left;
Substituting the value of non px units into style.left, such as 10em
Style.left = Styleval | | 0;
Be sure to use Style.pixelleft to fetch, or the value is inaccurate
If we get 160 with style.pixelleft, we'll get 150px with Style.left.
If all has been converted well, Style.left is inaccurate.
var px = style.pixelleft;
Style.left = left;//Restore Data
El.runtimeStyle.left = rsleft;//Restore Data
return px;
}

This hack is used to convert EM, PC, PT, CM, in, and ex units to PX, excluding percentages, of course.
Come back to see my getwidth function, the main problem is to get the value of Padding-left and Padding-right. In standard browsers, we use getComputedStyle to easily get the exact value of the converted, PX. In IE, if you give it a value of 2EM, it will return 2EM, very lazy. In the "CSS Inherit and auto" article, I also pointed out that padding for the Non-inherited property, this does not have to deal with Inhert this nonsense value; in the auto list, padding is not listed, Reduce the risk of dealing with the fuzzy value of auto, plus a measurable unit, each browser is very kind to set the default value of 0px, in other words, we need to do is, the unit of duty is not px, we convert it to PX. We integrate Dean Edwards's hack into our main function GetStyle. If the padding-left is a percentage, we can multiply the width of its parent element by a percentage. All in all, the level of traversal and number of times are compressed to the minimum. In this regard, my handling of this aspect is much better than jquery (jquery even Border,margin is included in the calculation range, and border and margin have fuzzy values in IE, which forces jquery to compute the parent element at every turn, in other words, The attributes of its parent element need to be repeated five times; I'm up to three times, just once in weird mode. Sometimes the values obtained in IE are more accurate than those with getComputedStyle Firefox (though, as if they are too accurate to adjust their accuracy with tofixed).
Copy Code code as follows:

var getstyle = function (el, style) {
if (!+ "\v1") {
if (style = = "opacity") {
Return Getieopacity (EL)
}
var value = El.currentstyle[memorize (style)];
if (/^ (height|width) $/.test (style)) {
var values = (style = = ' width ')? [' Left ', ' right ']: [' top ', ' bottom '], size = 0;
if (Isquirk) {
Return El[camelize ("offset-" +style)]
}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";
}
}
if (!/^\d+px$/.test (value)) {
Convert measurable values
if (/(EM|PT|MM|CM|PC|IN|EX|REM|VW|VH|VM|CH|GR) $/.test (value)) {
Return Convertpixelvalue (El,value);
}
Conversion percent
if (/%/.test (value)) {
Return parsefloat (GetStyle (El.parentnode, "width")) * parsefloat (value)/100 + "px"
}
}
Return value;//such as 0px
}else{
if (style = = "float") {
style = Propfloat;
}
Return Document.defaultView.getComputedStyle (EL, null). GetPropertyValue (Style)
}
}

It's pointless to say, let's test it.
<div id = "text" style= "Width:3in;height:180px;background: #8080c0;p adding:2%;" > Parent Element
<div id= "Text2" style= "width:78%;height:4em;padding:1%;background:red;border:1px solid Red" > child elements </div>
</div>
Window.onload = function () {
Alert (GetStyle (_ ("text"), "width")
Alert (GetStyle (_ ("Text2"), ' width ')
Alert (GetStyle (_ ("Text2"), ' Padding-left ')
};
<!doctype html> <ptml dir= "ltr" lang= "ZH-CN" > <pead> <meta charset= "Utf-8"/> <meta http-e quiv= "x-ua-compatible" content= "ie=8" > <style type= "text/css" > </style> <script> var isquirk = (d Ocument.documentmode)? (document.documentmode==5)? True:false: ((document.compatmode== "Css1compat")? false:true); 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) {return Propcache[prop] | | (Propcache[prop] = prop = = ' float ' propfloat:camelize (prop)); var getieopacity = function (EL) {var filter; if (!! Window. Xdomainrequest) {filter = El.style.filter.match (/progid:dximagetransform.microsoft.alpha\ (.?) Opacity= (. *). \)/i); }else{filter = El.style.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;//Restore Data El.runtimeStyle.left = rsleft;//restore data return px; var getstyle = function (el, style) {if (!+ "\v1") {if (style = = "opacity") {return getieopacity (EL)} var value = El . Currentstyle[memorize (style)]; if (/^ (height|width) $/.test (style)) {var values = (style = = ' width ')? [' Left ', ' right ']: [' top ', ' bottom '], size = 0; if (Isquirk) {return el[camelize ("offset-" +style)]}else{var client = parsefloat (El[camelize ("client-" +style)]), Paddi NgA = parsefloat (GetStyle (el, "padding-" + values[0]), PADDINGB = parsefloat (GetStyle (el, "padding-" + values[1])); Return (CLIENT-PADDINGA-PADDINGB) + "px"; } var unit = Value.match (/^\d*\.? \d*\s* ([\w%]+) $/) [1]; if (/^ (em|pt|mm|cm|pc|in|EX|REM|VW|VH|VM|CH|GR) $/.test (unit)) {return convertpixelvalue (el,value); } if (/%/.test) {return parsefloat (GetStyle (el.parentnode, ' width ')) * parsefloat (value)/100 + "px"} return Valu e;//such as 0px}else{if (style = = "float") {style = Propfloat; Return Document.defaultView.getComputedStyle (EL, null). GetPropertyValue (Style)}} var _ = function (id) {return doc Ument.getelementbyid (ID); } window.onload = function () {Alert (GetStyle (_ ("text"), "width") Alert (GetStyle (_ ("Text2"), ' width ') alert (GetStyle ( _ ("Text2"), ' Padding-left ')}; </script> <title> exact value </title> </pead> <body> <div id = "text" > Parent element <div id= "Tex T2 "> Child elements </div> </div> </body> </ptml>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]

found that the value in IE is too accurate, more accurate than Firefox, but I do not intend to set the accuracy of the operation within the program, because I am not sure how many times in the real world to traverse up. The precision of the padding and width of a parent element is likely to seriously affect the accuracy of its final value. Basically, the width and height and the value of the padding is over, let's look at the two things in the box model: margin and border.
Margin auto is usually 0px, but under IE6, when we set the text-align of its parent element as center, it not only centers the text, but also the block-level element itself, which is the cornerstone of IE6 centered layout. It's hard to say that this is a bug, like IE5 's Quirk model box model, which fits people's usual thinking habits, but harder to achieve, and that the company is biased against Microsoft, and Netscape's box model becomes standard. IE6 huge user base can not be ignored, we can't give 0px. I also said that auto has a symmetry, so it's good to do, we find the width of its parent element and then subtract it from its offsetwidth and divide by 2. Because Offsetwidth is aimed at offsertparent, we temporarily set the position of its parent element to relative, let the child element come offsetwidth, and then restore the position of the parent element.
Copy Code code as follows:

Convert 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";
}

The default value for BorderWidth is medium, even if it is 0px, but if we explicitly set its width to medium?! It's not going to be 0px anymore. This is disgusting, and we need to determine whether the value is the default value we added or the browser. However, we found that if this is the default, its border-xx-style is none. Besides medium, there are two fuzzy values thin and thick. Their exact values in the browser are shown in the following table:
IE8, Firefox and other standard browsers ie4-7
Thin 1px 2px
Medium 3px 4px
Thick 5px 6px
Copy Code code as follows:

Convert 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];
}

Again see Top,left,right and bottom, unexpectedly firefox,safari will be lazy, will return to auto, only opera honestly return accurate value. The solution is also simple, because Microsoft is a useful function has been supported by all browsers.
Copy Code code as follows:

Convert Top|left|right|bottom Auto
if (/(Top|left|right|bottom)/.test (style) && value = = "Auto") {
return El.getboundingclientrect () [style]
}

Well, the article has been very long, the rest of the next time to speak.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.