4 * style 値の変更は、enterFrame 後にまとめて適用
5 * width(), height(), x(), y() 1em の取得時にも適用
6 * css3 の ie用 fix は X.UI レベルで行う
11 /* font-size -> fontSize */
12 function X_Node_CSS_camelize( cssProp ){
13 var parts, l, i, parts0, camelized;
15 if( camelized = X_Node_CSS__DICTIONARY_CAMELIZE[ cssProp ] ) return camelized;
16 parts = cssProp.split( ' ' ).join( '' ).split( '-' );
19 if( l === 1 ) return parts0;
21 camelized = cssProp.charAt(0) === '-'
22 ? parts0.charAt( 0 ).toUpperCase() + parts0.substring( 1 )
25 for( i = 1; i < l; ++i ){
26 camelized += parts[ i ].charAt( 0 ).toUpperCase() + parts[ i ].substring( 1 );
28 return X_Node_CSS__DICTIONARY_CAMELIZE[ cssProp ] = camelized;
31 // TODO use X_HTMLParser_CHARS
32 /* fontSize -> font-size */
33 function X_Node_CSS_uncamelize( str ){
34 var A = X_Node_CSS_CHAR_CODE_A,
36 uncamelized, l, chr, code, i;
37 str = str.split( ' ' ).join( '' );
38 if( uncamelized = X_Node_CSS__DICTIONARY_UNCAMELIZE[ str ] ) return uncamelized;
40 for( i = 0, l = str.length; i < l; ++i ){
41 chr = str.charAt( i );
42 code = chr.charCodeAt( 0 );
43 uncamelized += ( A <= code && code <= Z ) ? '-' + chr : chr;
45 return X_Node_CSS__DICTIONARY_UNCAMELIZE[ str ] = uncamelized.toLowerCase();
50 X_Node_CSS_getComputedStyle = window.getComputedStyle || document.defaultView && document.defaultView.getComputedStyle,
52 /* font-size -> fontSize */
53 X_Node_CSS__DICTIONARY_CAMELIZE = {},
55 /* fontSize -> font-size */
56 X_Node_CSS_CHAR_CODE_A = 'A'.charCodeAt( 0 ),
58 X_Node_CSS__DICTIONARY_UNCAMELIZE = {},
61 * CSS における display, position, float プロパティの相互関係
62 * http://d.hatena.ne.jp/elm200/20080201/1201874740
64 * CSS21:9.7 Relationships between ’display’, ’position’, and ’float’
65 * http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo
67 * display:none? -yes-> 非表示
69 * position:absolute? -yes-> float:none,display:block;
71 * float:none? -no-> display:block;
76 display position float
77 block static|relative none
78 block static|relative right|left
80 inline static|relative none
87 X_Node_CSS_VENDER_PREFIX = {},
89 X_Node_CSS__CLIP_SEPARATOR = X_UA[ 'IE' ] < 8 ? ' ' : ',',
91 X_Node_CSS__UNIT_RATIO = {},
92 X_Node_CSS__FONT_SIZE_RATIO = {},
94 // https://developer.mozilla.org/en-US/docs/Web/CSS/transform
95 // Firefox 3.5, ie9, Opera 10.5, Safari 3.1, Chrome
96 // 3D support Firefox 10, ie10, Safari 4.0, Chrome 12.0
97 // transform : void 0,
99 // https://developer.mozilla.org/ja/docs/Web/Guide/CSS/Using_CSS_transitions
100 // Chrome 1.0, Firefox 4.0, ie10, Opera 10.5, Safari 3.2
101 // Android 2.1, Firefox Android 4.0, Opera Mobile 10, Safari Mobile 3.2
102 // transition : void 0
104 // ブラウザ毎の getComputedStyle の戻り値 http://d.hatena.ne.jp/uupaa/20080928/1222543331
114 'MAGENTA' : 0xFF00FF,
115 'FUCHSIA' : 0xFF00FF,
125 'DIMGRAY' : 0x696969,
126 'SLATEGRAY' : 0x708090,
127 'DARKGRAY' : 0xA9A9A9,
128 'GAINSBORO' : 0xDCDCDC,
129 'MIDNIGHTBLUE' : 0x191970,
130 'SLATEBLUE' : 0x6A5ACD,
131 'MEDIUMBLUE' : 0x0000CD,
132 'ROYALBLUE' : 0x4169E1,
133 'DODGERBLUE' : 0x1E90FF,
134 'SKYBLUE' : 0x87CEEB,
135 'STEELBLUE' : 0x4682B4,
136 'LIGHTBLUE' : 0xADD8E6,
137 'PALETURQUOISE' : 0xAFEEEE,
138 'TURQUOISE' : 0x40E0D0,
139 'LIGHTCYAN' : 0xE0FFFF,
140 'AQUAMARINE' : 0x7FFFD4,
141 'DARKGREEN' : 0x006400,
142 'SEAGREEN' : 0x2E8B57,
143 'LIGHTGREEN' : 0x90EE90,
144 'CHARTREUSE' : 0x7FFF00,
145 'GREENYELLOW' : 0xADFF2F,
146 'LIMEGREEN' : 0x32CD32,
147 'YELLOWGREEN' : 0x9ACD32,
148 'OLIVEDRAB' : 0x6B8E23,
149 'DARKKHAKI' : 0xBCB76B,
150 'PALEGOLDENROD' : 0xEEE8AA,
151 'LIGHTYELLOW' : 0xFFFFE0,
153 'GOLDENROD' : 0xDAA520,
154 'DARKGOLDENROD' : 0xB8860B,
155 'ROSYBROWN' : 0xBC8F8F,
156 'INDIANRED' : 0xCD5C5C,
157 'SADDLEBROWN' : 0x8B4513,
160 'BURLYWOOD' : 0xDEB887,
163 'SANDYBROWN' : 0xF4A460,
165 'CHOCOLATE' : 0xD2691E,
166 'FIREBRICK' : 0xB22222,
172 'HOTPINK' : 0xFF69B4,
174 'DEEPPINK' : 0xFF1493,
175 'PALEVIOLETRED' : 0xDB7093,
178 'ORCHILD' : 0xDA70D6,
179 'DARKVIOLET' : 0x9400D3,
180 'BLUEVIOLET' : 0x8A2BE2,
181 'MEDIUMPURPLE' : 0x9370DB,
182 'THISTLE' : 0xD8BFD8,
183 'LAVENDER' : 0xE6E6FA,
184 'MISTYROSE' : 0xFFE4E1,
186 'LEMONCHIFFON' : 0xFFFACD
189 function X_Node_CSS_parseColor( x ){
192 if( X_Type_isNumber( x ) ){
193 return ( 0x0 <= x && x <= 0xFFFFFF ) ? x : NaN;
195 if( !X_Type_isString( x ) ) return;
197 if( X_Type_isNumber( rgb = X_Node_CSS_COLOR[ x.toUpperCase() ] ) && 0x0 <= rgb && rgb <= 0xFFFFFF ){
200 if( x.charAt( 0 ) === '#' ){
203 r = parseInt( x.substr( 1, 2 ), 16 );
204 g = parseInt( x.substr( 3, 2 ), 16 );
205 b = parseInt( x.substr( 5, 2 ), 16 );
208 r = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 );
209 g = parseInt( x.charAt( 2 ) + x.charAt( 2 ), 16 );
210 b = parseInt( x.charAt( 3 ) + x.charAt( 3 ), 16 );
213 r = g = b = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 );
219 if( x.indexOf( 'rgb(' ) === 0 ){
220 rgb = x.substr( 4 ).split( ',' );
221 r = parseFloat( rgb[ 0 ] );
222 g = parseFloat( rgb[ 1 ] );
223 b = parseFloat( rgb[ 2 ] );
224 if( x.indexOf( '%' ) !== -1 ){
230 if( x.indexOf( 'rgba(' ) === 0 ){
231 rgb = x.substr( 5 ).split( ',' );
232 r = parseFloat( rgb[ 0 ] );
233 g = parseFloat( rgb[ 1 ] );
234 b = parseFloat( rgb[ 2 ] );
235 //a = parseFloat( rgb[ 3 ] );
236 if( x.indexOf( '%' ) !== -1 ){
244 return X_Type_isFinite( r + b + g ) ? ( r << 16 ) + ( g << 8 ) + b : NaN;
247 function X_Node_CSS_objToCssText( that, skipFilter ){
248 var obj = that[ '_css' ],
249 //plain = X_EMPTY_OBJECT,
252 p, v, specialFix, filterFix;
254 that[ '_flags' ] &= ~X_NodeFlags_OLD_CSSTEXT;
256 if( !obj ){ // Opera7.5 未満?
257 delete that[ '_cssText' ];
262 // object の拡張に備えて plain なオブジェクトを用意し、そのメンバーと一致するものは処理の対象外。
263 //if( plain[ p ] ) continue;
267 p = X_Node_CSS_uncamelize( X_Node_CSS_VENDER_PREFIX[ p ] || p );
269 if( specialFix = X_Node_CSS_SPECIAL_FIX_PROP[ p ] ){
270 css[ ++n ] = p + ':' + specialFix( v );
272 if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ p ] ){
273 ( filterFix || ( filterFix = {} ) )[ p ] = v;
275 css[ ++n ] = p + ':' + v;
280 v = X_Node_CSS_objToIEFilterText( that, filterFix, css );
281 n = css.length; /* css が変更されている場合あり */
283 css[ ++n ] = 'filter:' + v;
285 skipFilter = skipFilter && v;
291 // cssText には完全なものを控えるが、戻すのは filter を抜いたもの
292 that[ '_cssText' ] = css.join( ';' );
293 //console.log( that[ '_cssText' ] );
296 return css.join( ';' );
298 return that[ '_cssText' ];
300 delete that[ '_cssText' ];
305 X_Node_CSS_FILTER_FIX_PROPS =
306 X_UA[ 'ActiveX' ] && X_UA[ 'IE' ] < 9 ?
312 'dxtransform' : 7 // X.NodeAnime で使用
314 X_UA[ 'ActiveX' ] && X_UA[ 'IE9' ] ? // == 9
320 function X_Node_CSS_objToIEFilterText( that, opt_css, opt_cssList ){
321 var obj = opt_css || that[ '_css' ],
322 test = X_Node_CSS_FILTER_FIX_PROPS,
325 p, id, v, num, vu, u, _v, ary, params, i, l, dir,
326 afterUpdate, impossible, color;
329 //if( X_EMPTY_OBJECT[ p ] ) continue;
331 if( !( id = test[ p ] ) ) continue;
335 case 1 : //'filter' :
338 case 2 : //'opacity' :
340 console.log( '@opacity:0 ' + !!opt_cssList );
341 opt_cssList && ( opt_cssList[ opt_cssList.length ] = 'visibility:hidden' );
343 if( v < 1 ) filters[ ++n ] = 'alpha(opacity=' + ( v * 100 | 0 ) +')';
345 case 3 : //'boxShadow' :
347 // box-shadow: 10px 10px 10px 10px rgba(0,0,0,0.4) inset;
348 // スペース区切りで、水平方向の距離 垂直方向の距離 ぼかし距離 広がり距離 影の色 insetキーワードを指定する。 ぼかし距離 広がり距離 影の色 insetキーワードは省略可
349 // https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow
350 // <length> に絶対値は不可? <color> 省略した場合は、文字の色が使われる(webkit以外)
351 // shadow(color=#cccccc, strength=10, direction=135);
352 ary = v.split( ' ' );
353 params = [ 0, 0, 0, 0 ]; // offset-x, offset-y, blur-radius, spread-radius
354 for( i = 0, l = ary.length; i < l; ++i ){
356 num = i < 4 && parsetFloat( v );
359 vu = X_Node_CSS__splitValueAndUnit( v );
363 if( _v = X_Node_CSS__UNIT_RATIO[ u ] ){
364 params[ i ] = v / _v;
371 if( X_Node_updateTimerID ){
374 params[ i ] = X_Node_CSS_getCharSize( that ) * v;
385 if( v.charAt( 0 ) === '#' || v.indexOf( 'rgb' ) === 0 || X_Node_CSS_COLOR[ v.toUpperCase() ] ){
386 v = X_Node_CSS_parseColor( v );
387 if( 0 <= v && v < 0x100000 ){
388 color = '00000' + v.toString( 16 );
389 color = '#' + color.substr( color.length - 6 );
392 color = '#' + v.toString( 16 );
401 if( impossible || !color ){
405 // AFTER_UPDATE 時に 再計算
406 X_ViewPort[ 'listenOnce' ]( X_EVENT_AFTER_UPDATE, that, X_Node_CSS_onAfterUpdateForIEFilterFix );
409 dir = X_Node_CSS_ieMathRangeFix( Math.atan2( params[ 1 ] + params[ 3 ], params[ 0 ] + params[ 3 ] ) * 180 / Math.PI + 90 );
410 filters[ ++n ] = 'shadow(color=' + color + ',strength=' + params[ 3 ] + ',direction=' + ( dir | 0 ) + ')';
412 case 4 : //'textShadow' :
413 //text-shadow: 5px 5px 2px blue; 水平方向の距離 垂直方向の距離 影のぼかし半径 影の色 none
414 //glow(Color=yellow,Strength=10);
415 //どうやらCSSのbackgroundプロパティと同時に使えないようです。
417 case 6 : //'backgroundImage' :
421 case 5 : // transform scale, matrix
423 case 7 : // dxtransform
424 that[ '_flags' ] |= X_NodeFlags_IE_FILTER_FIX_AFTER;
428 return filters.join( ' ' );//n !== -1 ? filters.join( ' ' ) : '';
433 function X_Node_CSS_ieMathRangeFix( a ){
435 return a < 0 ? 360 + a : a;
439 * http://p2b.jp/200912-CSS3-Transform-for-IE8
440 * http://rtilabs.rti-giken.jp/files/2011_09_16/rotate.html
442 function X_Node_CSS_IETransform( elm, params ){
443 var PI_180 = Math.PI / 180,
445 rotate = X_Node_CSS_ieMathRangeFix( params[ 2 ] ),//回転
446 radian = rotate * PI_180,
447 cosX = Math.cos( radian ),
448 sinY = Math.sin( radian ),
450 skewX = X_Node_CSS_ieMathRangeFix( params[ 3 ] ), //skew
451 skewY = X_Node_CSS_ieMathRangeFix( params[ 4 ] ),
453 _skX = Math.tan( skewX * PI_180 ),
454 _skY = Math.tan( skewY * PI_180 ),
456 scaleX = params[ 5 ], //拡大
457 scaleY = params[ 6 ],
460 m12 = ( -sinY + _skX ) * scaleX,
461 m21 = ( sinY + _skY ) * scaleY,
464 //absolute時には軸を補正してあげないとだめだ。
466 //計算式元ネタ http://p2b.jp/200912-CSS3-Transform-for-IE8
468 //offset*系のサイズは回転によって生じたゆがみも考慮されるらしい。
471 //this.get(0).style.width や height には拡縮の影響を受けない元の数字が入っている
472 ow = elm.offsetWidth,
473 oh = elm.offsetHeight,
475 absCosX = Math.abs( cosX ),
476 absSinY = Math.abs( sinY ),
479 dx = ( ow - ( ow * absCosX + oh * absSinY ) ) / 2
480 //skewの補正(rotate しながらskew すると補正がおかしくなります。 これがわからない)
483 - ( ( ow * scaleX - ow ) / 2 | 0 )
486 dy = ( oh - ( ow * absSinY + oh * absCosX ) ) / 2
490 - ( ( oh * scaleY - oh ) / 2 | 0 )
494 //console.log( ow + ' ' + oh )
495 elm.style[ params[ 7 ] ] = dx + 'px'; // left or right
496 elm.style[ params[ 8 ] ] = dy + 'px'; // top or bottom
498 //フィルターで回転と拡大縮小を加えます。
499 return 'progid:DXImageTransform.Microsoft.Matrix(' +
506 ',FilterType="bilinear",sizingMethod="auto expand")';
509 function X_Node_CSS_onAfterUpdateIEFilterFix( that ){
510 var PI_180 = Math.PI / 180,
511 test = X_Node_CSS_FILTER_FIX_PROPS,
512 css = that[ '_css' ],
513 elm = that[ '_rawObject' ],
514 filter = elm.style.filter || '',
519 if( !( id = test[ p ] ) ) continue;
522 case 7 : // dxtransform
523 plus = X_Node_CSS_IETransform( elm, css[ p ] );
528 if( plus ) filter += ( filter ? ' ' : '' ) + plus;
530 if( filter !== origin ) elm.style.filter = filter;
534 function X_Node_CSS_onAfterUpdateForIEFilterFix(){
535 if( this[ '_flags' ] & X_NodeFlags_IN_TREE ){ // 要素があり、要素がツリーに属している
536 this[ '_flags' ] |= X_NodeFlags_DIRTY_IE_FILTER;
537 X_Node_reserveUpdate();
543 * http://css-eblog.com/ie-css-problems/rgba-pe.html
544 * ie67 では rgb() は background-color で反応しない、、、
551 // ex, rem, vh, vw, vmin, vmax
569 function X_Node_CSS__splitValueAndUnit( v ){
571 if( X_Type_isNumber( v ) ) return [ v || 0, '' ];
572 num = parseFloat( v );
573 if( num !== num ) return [ 0, '' ];
575 if( 0 < num && num < 1 && v.charAt( 0 ) === '.' ) _num = _num.slice( 1 );
576 if( -1 < num && num < 0 && v.charAt( 1 ) === '.' ) _num = '-.' + _num.substr( 2 );
577 u = v.substr( v.indexOf( _num ) + _num.length );
578 return [ num, X_Node_CSS_UNIT[ u ] ? u : 'px' ];
582 var test = X_Node_CSS_SPECIAL_FIX_PROP,
583 ret = [], p, id, v, bgpX, bgpY, clipT, clipB, clipL, clipR;
585 if( !( id = test[ p ] ) ) continue;
588 case 1 : //'backgroundPositionX' :
591 case 2 : //'backgroundPositionY' :
594 case 3 : //'clipTop' :
597 case 4 : //'clipBottom' :
600 case 5 : //'clipLeft' :
603 case 6 : //'clipRight' :
608 if( bgpX || bgpY ) ret[ ret.length ] = 'background-position:';
609 if( clipT || clipB || clipL || clipR ){
610 ret[ ret.length ] = 'clip:rect(';
612 return ret.join( ';' );
620 // unitID, name 単位指定のプロパティ取得 geter
622 // name, value setter
624 * style の getter と setter。
625 * @alias Node.prototype.css
626 * @param {string|object} [nameOrObj] style 名、または追加する style のハッシュ
627 * @param {string|number} [value=] style の値
628 * @return {Node|string|number} getter の場合は値を、setter の場合は自身を返す。(メソッドチェーン)
630 * node.css( 'color' );
632 * node.css( { width : w + 'px', height : h + 'px' } );
634 * node.css( 'color', 0x666666 );
636 function X_Node_css( nameOrObj /* value */ ){
637 var args = arguments,
638 css = this[ '_css' ],
639 p, name, v, plain, camelize, flags;
641 if( !this[ '_tag' ] || X_Dom_DTD_MOVE_TO_HEAD[ this[ '_tag' ] ] || this[ '_tag' ] === 'SCRIPT' ) return this;
643 if( X_Type_isObject( nameOrObj ) ){
644 if( !css ) css = this[ '_css' ] = {};
645 //plain = X_EMPTY_OBJECT;
646 camelize = X_Node_CSS_camelize;
647 flags = this[ '_flags' ];
648 for( p in nameOrObj ){
649 //if( plain[ p ] ) continue;
650 name = camelize( p );
652 if( css[ name ] === v ) continue;
653 flags = X_Node_CSS_setStyle( css, flags, name, v );
655 flags |= X_NodeFlags_DIRTY_CSS | X_NodeFlags_OLD_CSSTEXT;
656 this[ '_flags' ] = flags;
657 flags & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();
658 delete this[ '_cssText' ];
661 if( 1 < args.length ){
662 // setter name, value
663 if( !css ) css = this[ '_css' ] = {};
664 name = X_Node_CSS_camelize( nameOrObj );
666 if( css[ name ] === v ) return this;
667 this[ '_flags' ] = X_Node_CSS_setStyle( css, this[ '_flags' ], name, v ) | X_NodeFlags_DIRTY_CSS | X_NodeFlags_OLD_CSSTEXT;
668 this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();
669 delete this[ '_cssText' ];
674 // TODO 集計 border, padding, margin, backgroundPosition, clip
675 // TODO border で正確なデータを返せない時は、null を返す
676 return css[ X_Node_CSS_camelize( nameOrObj ) ];
679 function X_Node_CSS_setStyle( css, flags, name, newValue ){
681 if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ name ] ){
682 flags |= X_NodeFlags_DIRTY_IE_FILTER;
684 if( !newValue && newValue !== 0 ){
687 css[ name ] = newValue;
692 console.log( newValue );
693 newValue === 'none' ? ( flags |= X_NodeFlags_STYLE_IS_DISPLAY_NONE ) : ( flags &= ~X_NodeFlags_STYLE_IS_DISPLAY_NONE );
697 // すでに opacity:0 で invisible
698 if( flags & X_NodeFlags_STYLE_IS_INVISIBLE && css[ 'opacity' ] == 0 ) return flags;
699 newValue === 'hidden' ? ( flags |= X_NodeFlags_STYLE_IS_INVISIBLE ) : ( flags &= ~X_NodeFlags_STYLE_IS_INVISIBLE );
703 flags |= X_NodeFlags_IE8_OPACITY_FIX;
704 // すでに visibility:hidden で invisible
705 if( flags & X_NodeFlags_STYLE_IS_INVISIBLE && css[ 'visibility' ] === 'hidden' ) return flags;
706 newValue == 0 ? // 0 or "0"
707 ( flags |= X_NodeFlags_STYLE_IS_INVISIBLE ) : ( flags &= ~X_NodeFlags_STYLE_IS_INVISIBLE );
711 newValue === 'hidden' ? ( flags |= X_NodeFlags_STYLE_IS_NO_OVERFLOW ) : ( flags &= ~X_NodeFlags_STYLE_IS_NO_OVERFLOW );
715 newValue === 'absolute' ? ( flags |= X_NodeFlags_STYLE_IS_POS_ABSOLUTE ) : ( flags &= ~X_NodeFlags_STYLE_IS_POS_ABSOLUTE );
719 newValue = X_Node_CSS__splitValueAndUnit( newValue );
720 if( newValue[ 1 ] !== '%' ){
721 flags |= X_NodeFlags_STYLE_IS_WIDTH_LENGTH;
722 flags &= ~X_NodeFlags_STYLE_IS_WIDTH_PCT;
724 flags &= ~X_NodeFlags_STYLE_IS_WIDTH_LENGTH;
725 flags |= X_NodeFlags_STYLE_IS_WIDTH_PCT;
730 newValue = X_Node_CSS__splitValueAndUnit( newValue );
731 if( newValue[ 1 ] !== '%' ){
732 flags |= X_NodeFlags_STYLE_IS_HEIGHT_LENGTH;
733 flags &= ~X_NodeFlags_STYLE_IS_HEIGHT_PCT;
735 flags &= ~X_NodeFlags_STYLE_IS_HEIGHT_LENGTH;
736 flags |= X_NodeFlags_STYLE_IS_HEIGHT_PCT;
747 * cssText の getter と setter。setter の場合 css と異なり全ての style が書き変わる。
748 * @alias Node.prototype.cssText
749 * @param {string=} v cssText 文字列名
750 * @return {Node|string} getter の場合は cssText 文字列を、setter の場合は自身を返す。(メソッドチェーン)
754 * node.cssText('color:red;width:20px');
756 function X_Node_cssText( v ){
757 var obj, i, l, attr, name;
759 if( v === this[ '_cssText' ] && ( ( this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT ) === 0 ) ){
764 delete this[ '_css' ];
765 delete this[ '_cssText' ];
766 this[ '_flags' ] |= X_NodeFlags_DIRTY_CSS | X_NodeFlags_DIRTY_IE_FILTER;
767 this[ '_flags' ] &= ~X_NodeFlags_OLD_CSSTEXT;
768 this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();
771 if( X_Type_isString( v ) ){
772 delete this[ '_css' ];
774 v = v.split( ';' ); // TODO content ";" などにも対応 <- 不要 :before :after 疑似要素には触らない
775 for( i = 0, l = v.length; i < l; ++i ){
776 attr = v[ i ].split( ':' );
777 ( name = attr[ 0 ] ) && ( obj[ name ] = attr[ 1 ] || true );
779 return this[ 'css' ]( obj );
782 this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT && X_Node_CSS_objToCssText( this );
783 return this[ '_cssText' ];
787 * ここでは HTMLElement のチ1ェックは行わない! <- 行う!
789 * body に css attr がセットされた場合には X_ViewPort_baseFontSize をクリア
790 * class, id, attr(<font size><basefont>) の変更があった場合は、変更の適用の後、charSize を取得
791 * css の場合は、計算で求めることが可能、content は影響しない
792 * :hover, #target, が絡む場合、正しく扱えない
795 X_Node_CSS_getCharSize =
796 X_Node_CSS_getComputedStyle ?
798 X_Node_updateTimerID && X_Node_startUpdate();
799 if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
800 if( that[ '_fontSize' ] ) return that[ '_fontSize' ];
801 return that[ '_fontSize' ] = that[ '_rawObject' ] ? parseFloat( X_Node_CSS_getComputedStyle( that[ '_rawObject' ], null ).fontSize ) : 0;
806 var font, vu, v, u, _v;
808 X_Node_updateTimerID && X_Node_startUpdate();
809 if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
810 if( that[ '_fontSize' ] ) return that[ '_fontSize' ];
812 font = that[ '_rawObject' ].currentStyle.fontSize;
813 //font = that[ '_css' ] && that[ '_css' ].fontSize || '1em';
814 vu = X_Node_CSS__splitValueAndUnit( font );
819 if( v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that[ '_fontSize' ] = v;
821 if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that[ '_fontSize' ] = v / _v;
825 return that[ '_fontSize' ] = v;
827 // body まで辿ってしまった場合は?
828 if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v;
831 // body まで辿ってしまった場合は?
832 if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v / 100;
839 X_Node_updateTimerID && X_Node_startUpdate();
840 if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
841 if( that[ '_fontSize' ] ) return that[ '_fontSize' ];
843 that[ '_rawObject' ].appendChild( elm = document.createElement( 'span' ) );
844 elm.style.cssText = 'display:block;position:absolute;top:0;left:0;visivility:hidden;line-height:1;height:1em;';
846 v = elm.offsetHeight;
847 that[ '_rawObject' ].removeChild( elm );
848 return that[ '_fontSize' ] = v;
852 var font, vu, v, u, _v, elm;
854 X_Node_updateTimerID && X_Node_startUpdate();
855 if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
856 if( that[ '_fontSize' ] ) return that[ '_fontSize' ];
858 if( that[ '_css' ] && ( font = that[ '_css' ].fontSize ) ){
859 vu = X_Node_CSS__splitValueAndUnit( font );
864 if( _v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that[ '_fontSize' ] = _v;
866 if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that[ '_fontSize' ] = v / _v;
869 // TODO 要素を生成して測定! ではなくて elm.style.fontSize が使えそう
870 ( that[ '_rawObject' ] || X_Node__ie4getRawNode( that ) ).insertAdjacentHTML( 'BeforeEnd', '<div id="ie4charsize" style="position:absolute;top:0;left:0;visivility:hidden;line-height:1;height:1em;">X</div>' );
871 elm = document.all[ 'ie4charsize' ];
872 v = elm.offsetHeight;
873 elm.removeAttribute( 'id' ); // ?
875 return that[ '_fontSize' ] = v;
880 return that[ '_fontSize' ] = v;
882 // body まで辿ってしまった場合は?
883 if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v;
886 // body まで辿ってしまった場合は?
887 if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v / 100;
893 var X_Node_CSS_Support = {},
895 X_Node_CSS_SPECIAL_FIX_PROP = {
897 'transitionDuration' : X_UA[ 'Android' ] && !X_UA[ 'Chrome' ] && function( v ){ // bad Android
898 return parseFloat( v ) === 0 ? '0.001s' : v;
901 //webkit boxShadow <color> が省略された場合。transparent になるのを color に
902 //webkit boxShadow が border-radius をはみ出す, background-image に グラデーションのないグラデーション指定
903 // http://melty.koume.in/android-bug-boxshadow-radius/
912 * @alias X.CSS.VENDER_PREFIX
914 'VENDER_PREFIX' : X_Node_CSS_VENDER_PREFIX,
917 * @alias X.CSS.Support
919 'Support' : X_Node_CSS_Support
923 * backgroundPositionX : testStyle.backgroundPositionX === undefined ? 3 : 0,
924 backgroundPosiitonY : testStyle.backgroundPositionX === undefined ? 3 : 0,
925 clipTop : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 3 : 0,
926 clipBottom : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 4 : 0,
927 clipLeft : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 5 : 0,
928 clipRight : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 6 : 0
932 var testStyle = X_UA[ 'IE4' ] ? {} : ( /*document.documentElement ||*/ document.createElement( 'div' ) ).style,
933 temp = testStyle.cssText,
934 vendors = 'webkit,Webkit,Moz,moz,Ms,ms,O,o,khtml,Khtml'.split( ',' ),
936 'opacity,boxSizing,boxShadow,' +
937 'transform,transformOrigin,perspective,' +
938 'transisiton,transitionDelay,transitionProperty,transitionDuration,transitionTimingFunction,backfaceVisibility,willChange,filter,' +
939 'userSelect,touchSelect,touchAction,touchCallout,contentZooming,userDrag,tapHighlightColor' ).split( ',' ),
940 vendor, i, search, prop, j, v;
942 for( i = searches.length; i; ){
943 search = prop = searches[ --i ];
945 if( testStyle[ prop ] === undefined ){
946 prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 );
947 for( j = vendors.length; j; ){
949 if( testStyle[ v + prop ] !== undefined ){
950 if( v === 'ms'/* && !( 10 <= X_UA[ 'IEHost' ] )*/ ) v = 'Ms';// for ie9, 但し ie11 のieには不要
951 if( v === 'o' ) v = 'O';//for opera12
952 X_Node_CSS_VENDER_PREFIX[ search ] = v + prop;
957 X_Node_CSS_VENDER_PREFIX[ search ] = prop;
961 testStyle.cssText = 'background:rgba(0,0,0,0.5);border-color:transparent';
963 * 色指定に rgba() が使用できるか?
964 * @alias X.CSS.Support.rgba
967 X_Node_CSS_Support[ 'rgba' ] = !!testStyle[ 'background' ];
970 * 色指定に transparent が使用できるか?
971 * @alias X.CSS.Support.transparent
974 X_Node_CSS_Support[ 'transparent' ] = !!testStyle[ 'borderColor' ];
975 // TODO border による三角形の可否
976 // 2:完全、 1:透過に非対応(IE7-) 0:borderの描画が非標準で三角形が作れない
978 if( prop = X_Node_CSS_VENDER_PREFIX[ 'boxShadow' ] ){
980 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0';
984 * chrome 1+, ff3.5(1.9.1), ie9+, opera10.5+, Safari3+(522)
985 * @alias X.CSS.Support.boxShadow
988 X_Node_CSS_Support[ 'boxShadow' ] = !!testStyle[ prop ];
990 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0, 0 0';
993 * boxShadow の複数指定が使用できるか?<br>
994 * chrome 4+, ff3.5(1.9.1), ie9+, opera10.5+, Safari5+(533)
995 * @alias X.CSS.Support.boxShadowMulti
998 X_Node_CSS_Support[ 'boxShadowMulti' ] = !!testStyle[ prop ];
1000 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0 inset';
1003 * https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow<br>
1004 * この値を用いる場合には、spread-radius を省略出来ません。box-shadow が効かないケースに遭遇した時はこの事を思い出して下さい。<br>
1005 * chrome 4+, ff3.5(1.9.1), ie9+, opera10.5+, Safari5+(533)<br>
1007 * http://unformedbuilding.com/articles/considerations-when-using-the-box-shadow/<br>
1008 * box-shadow:inset と border-radius を指定しているときの Google Chrome の表示<br>
1009 * このバグは Windows と Linux で発生するようです。<br>
1010 * Windows 版 Chrome 10.0.648.127 で修正されているのを確認しました。<br>
1011 * @alias X.CSS.Support.boxShadowInset
1014 X_Node_CSS_Support[ 'boxShadowInset' ] = testStyle[ prop ] && testStyle[ prop ].indexOf( 'inset' ) !== -1;
1018 testStyle.cssText = temp;
1022 X_ViewPort[ 'listenOnce' ]( X_EVENT_INIT, function(){
1023 var xnode = X_Node_systemNode,
1024 output = X_Node_CSS__UNIT_RATIO,
1025 list = 'cm,mm,in,pt,pc'.split( ',' ),
1026 unit, size, base, i;
1028 for( i = list.length; i; ){
1030 output[ unit ] = xnode[ 'css' ]( 'width', 10 + unit )[ 'width' ]() / 10;
1033 output = X_Node_CSS__FONT_SIZE_RATIO,
1034 list = 'xx-large,x-large,large,larger,medium,small,smaller,x-small,xx-small'.split( ',' );
1035 xnode[ 'css' ]( { lineHeight : '100%', height : '1em' } )[ 'text' ]( 'X' );
1037 for( i = list.length; i; ){
1039 output[ size ] = xnode[ 'css' ]( 'fontSize', size )[ 'height' ]();// / base;
1042 xnode[ 'cssText' ]( '' )[ 'empty' ]();