.css()
は渡されたjQueryオブジェクトの、引数に指定されたCSSプロパティの値を取得する関数です。
前編では、引数として渡された値を評価して、必要に応じて値を整形するところまでを見てきました。
またその過程で、それぞれのブラウザの挙動の差を吸収する クロスブラウザ 処理が施されている事も分かりました。
後編では、実際に要素に適用されている style
の値を取得する curCSS()
の中身を見ていきます。
jQuery.css() – 後編
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/*===== jquery-1.11.1.js-L6700 =====*/ css: function( elem, name, extra, styles ) { var num, val, hooks, origName = jQuery.camelCase( name ); // Make sure that we're working with the right name name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); // gets hook for the prefixed version // followed by the unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // If a hook was provided get the computed value from there if ( hooks && "get" in hooks ) { val = hooks.get( elem, true, extra ); } // Otherwise, if a way to get the computed value exists, use that if ( val === undefined ) { val = curCSS( elem, name, styles ); } //convert "normal" to computed value if ( val === "normal" && name in cssNormalTransform ) { val = cssNormalTransform[ name ]; } // Return, converting to number if forced or a qualifier was provided and val looks numeric if ( extra === "" || extra ) { num = parseFloat( val ); return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; } return val; } |
前編で触れた float
と opacity
の例外に当てはまらなかった場合、処理は curCSS()
に引き継がれます。
1 2 3 4 5 |
/*===== jquery-1.11.1.js-L6716 =====*/ // Otherwise, if a way to get the computed value exists, use that if ( val === undefined ) { val = curCSS( elem, name, styles ); } |
curCSS()
は下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
/*===== jquery-1.11.1.js-L6116 =====*/ if ( window.getComputedStyle ) { getStyles = function( elem ) { return elem.ownerDocument.defaultView.getComputedStyle( elem, null ); }; curCSS = function( elem, name, computed ) { var width, minWidth, maxWidth, ret, style = elem.style; computed = computed || getStyles( elem ); // getPropertyValue is only needed for .css('filter') in IE9, see #12537 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined; if ( computed ) { if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { ret = jQuery.style( elem, name ); } // A tribute to the "awesome hack by Dean Edwards" // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { // Remember the original values width = style.width; minWidth = style.minWidth; maxWidth = style.maxWidth; // Put in the new values to get a computed value out style.minWidth = style.maxWidth = style.width = ret; ret = computed.width; // Revert the changed values style.width = width; style.minWidth = minWidth; style.maxWidth = maxWidth; } } // Support: IE // IE returns zIndex value as an integer. return ret === undefined ? ret : ret + ""; }; } else if ( document.documentElement.currentStyle ) { getStyles = function( elem ) { return elem.currentStyle; }; curCSS = function( elem, name, computed ) { var left, rs, rsLeft, ret, style = elem.style; computed = computed || getStyles( elem ); ret = computed ? computed[ name ] : undefined; // Avoid setting ret to empty string here // so we don't default to auto if ( ret == null && style && style[ name ] ) { ret = style[ name ]; } // From the awesome hack by Dean Edwards // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 // If we're not dealing with a regular pixel number // but a number that has a weird ending, we need to convert it to pixels // but not position css attributes, as those are proportional to the parent element instead // and we can't measure the parent instead because it might trigger a "stacking dolls" problem if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { // Remember the original values left = style.left; rs = elem.runtimeStyle; rsLeft = rs && rs.left; // Put in the new values to get a computed value out if ( rsLeft ) { rs.left = elem.currentStyle.left; } style.left = name === "fontSize" ? "1em" : ret; ret = style.pixelLeft + "px"; // Revert the changed values style.left = left; if ( rsLeft ) { rs.left = rsLeft; } } // Support: IE // IE returns zIndex value as an integer. return ret === undefined ? ret : ret + "" || "auto"; }; } |
やたらと大掛かりな処理に見えますが、それもそのはずで、ブラウザによって curCSS()
は異なる2つの関数を使い分けています。
その切り替えの起点となるのが、下の箇所です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
if ( window.getComputedStyle ) { getStyles = function( elem ) { return elem.ownerDocument.defaultView.getComputedStyle( elem, null ); }; curCSS = function( elem, name, computed ) { ... }; } else if ( document.documentElement.currentStyle ) { getStyles = function( elem ) { return elem.currentStyle; }; curCSS = function( elem, name, computed ) { ... }; } |
要素に適用されている style
を取得するには、 window.getComputedStyle
を使用しますが、 InternetExplorer8とそれ以前のバージョンではこのメソッドが実装されていません。
その代わりにIEの独自拡張メソッドである document.documentElement.currentStyle
が使用できるので、 window.getComputedStyle
をサポートしていないブラウザではこちらが使われます。
また、 window.getComputedStyle
をサポートするブラウザでも、 Safari では、このメソッドを windowオブジェクト から使用する事が出来ません。
そのため elem.ownerDocument.defaultView.getComputedStyle()
として、各ブラウザごとの差を吸収しています。
さらに、 CSS2.1
をサポートしているブラウザと、 CSS 2.0
までのサポートのブラウザでは、 window.getComputedStyle
で取得できる値が違うため、6140行からの処理でこの差を補正しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/*===== jquery-1.11.1.js-L6136 =====*/ // A tribute to the "awesome hack by Dean Edwards" // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { // Remember the original values width = style.width; minWidth = style.minWidth; maxWidth = style.maxWidth; // Put in the new values to get a computed value out style.minWidth = style.maxWidth = style.width = ret; ret = computed.width; // Revert the changed values style.width = width; style.minWidth = minWidth; style.maxWidth = maxWidth; } |
jQueryは「重い」と言われる事の多いライブラリです。
サポートブラウザを減らす事で処理を軽くした、 zepto.js や、そもそもネイティブのJavaScriptを使う事を推奨している vanilla.js という考え方も注目されています。
しかし、サポートするブラウザが様々な場合(特にIE8以前のブラウザをサポートする必要がある場合)、jQueryのこうした強力なクロスブラウザ性はとても頼もしいですね。