这里实际包含两个文件,在IE9中,它完全支持W3C那种精确获取样式的API,因此无需使用currentStyle与runtimeStyle,因此对于旧式IE的兼容单独放到一个JS文件中。
css.js
//========================================= // 样式操作模块 by 司徒正美 2011.8.23 //========================================= (function(global,DOC){ var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')], deps = global.getComputedStyle ? "node" : "node,css_ie" ; dom.define("css", deps, function(){ dom.log("已加载css模块") var cssFloat = dom.support.cssFloat ? 'cssFloat': 'styleFloat',rcap = /-([a-z])/g,capfn = function($0,$1){ return $1.toUpperCase(); }, adapter = dom.cssAdapter = dom.cssAdapter || {}; function cssCache(name){ return cssCache[name] || (cssCache[name] = name == 'float' ? cssFloat : name.replace(rcap, capfn)); } dom.mix(dom, { //http://www.cnblogs.com/rubylouvre/archive/2011/03/28/1998223.html cssName : function (name){ var prefixes = ['', '-ms-','-moz-', '-webkit-', '-khtml-', '-o-','ms-'] dom.cssName = function(name, target, test){ target = target || document.documentElement.style; for (var i=0, l=prefixes.length; i < l; i++) { test = (prefixes[i] + name).replace(rcap,capfn); if(test in target){ return test; } } return null; } return dom.cssName(name); }, cssCache: cssCache, cssNumber : dom.oneObject("fontSizeAdjust,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom"), css: function(nodes, name, value){ var props = {}, fn if(nodes.nodeType == 1){ nodes = [nodes] } if ( value === void 0 ) {//获取样式 try{ return (adapter[name+":get"] || adapter["_default:get"])( nodes[0], cssCache(name) ); }catch(e){ dom.log(e) } }else {//设置样式 if(typeof name == "string"){ props[name] = value; }else{ props = name; } for(name in props){ value = props[name]; name = cssCache(name); fn = adapter[name+":set"] || adapter["_default:set"]; if ( isFinite( value ) && !dom.cssNumber[ name ] ) { value += "px"; } for(var i = 0, node; node = nodes[i++];){ if(node && node.nodeType === 1){ fn(node, name, value ); } } } } return nodes; } }); dom.fn.css = function(name,value){ return dom.css(this, name,value); } //========================= 处理 width height ========================= var cssShow = { position: "absolute", visibility: "hidden", display: "block" } var cssPair = { width:['Left', 'Right'], height:['Top', 'Bottom'] } function swap( node, options, callback ) { var old = {}; for ( var name in options ) { old[ name ] = node.style[ name ]; node.style[ name ] = options[ name ]; } callback.call( node ); for ( name in options ) { node.style[ name ] = old[ name ]; } } // clientWidth = node.style.width + padding // https://developer.mozilla.org/en/DOM/element.clientWidth // offsetWidth = node.style.width + padding + border // https://developer.mozilla.org/en/DOM/element.offsetWidth // getBoundingClientRect = node.style.width + padding + border // https://developer.mozilla.org/en/DOM/element.getBoundingClientRect // [CSS2.1 盒子模型] http://www.w3.org/TR/CSS2/box.html // B-------border----------+ -> border // | | // | P----padding----+ | -> padding // | | | | // | | C-content-+ | | -> content // | | | | | | // | | | | | | // | | +---------+ | | // | | | | // | +---------------+ | // | | // +-----------------------+ // B = event.offsetX/Y in WebKit // event.layerX/Y in Gecko // P = event.offsetX/Y in IE6 ~ IE8 // C = event.offsetX/Y in Opera function getWH( node, name ) { var which = cssPair[name], getter = dom.cssAdapter["_default:get"], val = name === "width" ? node.offsetWidth : node.offsetHeight; which.forEach(function(direction){ val -= parseFloat(getter(node, 'padding' + direction)) || 0; val -= parseFloat(getter(node, 'border' + direction + 'Width')) || 0; }); return val; } "width,height".replace(dom.rword,function(name){ dom.cssAdapter[ name+":get" ] = function(node, name, value){ if ( node.offsetWidth !== 0 ) { value = getWH( node, name ) ; } else { swap( node, cssShow, function() { value = getWH( node, name ); }); } return value + "px" } }); //IE9 FF等支持getComputedStyle dom.mix(adapter, { "_default:get" :function( node, name){ return node.style[ name ]; }, "_default:set" :function( node, name, value){ return node.style[ name ] = value; } },false); if ( DOC.defaultView && DOC.defaultView.getComputedStyle ) { adapter[ "_default:get" ] = function( node, name ) { var ret, defaultView, computedStyle; if ( !(defaultView = node.ownerDocument.defaultView) ) { return undefined; } var underscored = name == "cssFloat" ? "float" : name.replace( /([A-Z]|^ms)/g, "-$1" ).toLowerCase(); if ( (computedStyle = defaultView.getComputedStyle( node, null )) ) { ret = computedStyle.getPropertyValue( underscored ) ret = ret.replace(/\d*(?:\.\d+px)/,function(a){ return parseFloat(a).toFixed()+"px" }); if ( ret === "" && !dom.contains( node.ownerDocument, node ) ) { ret = node.style[name];//如果还没有加入DOM树,则取内联样式 } } return ret; }; } //========================= 处理 user-select ========================= //https://developer.mozilla.org/en/CSS/-moz-user-select //http://www.w3.org/TR/2000/WD-css3-userint-20000216#user-select //具体支持情况可见下面网址 //http://help.dottoro.com/lcrlukea.php adapter[ "userSelect:set" ] = function( node, name, value ) { name = dom.cssName(name); if(typeof name === "string"){ return node.style[name] = value } var allow = /none/.test(value||"all"); node.unselectable = allow ? "" : "on"; node.onselectstart = allow ? "" : function(){ return false; }; }; //http://msdn.microsoft.com/en-us/library/cc304082(v=vs.85).aspx var test = dom('<div style="background-position: 3px 5px">'); dom.support.backgroundPosition = test.css('backgroundPosition') === "3px 5px" ? true : false; dom.support.backgroundPositionXY = test.css('backgroundPositionX') === "3px" ? true : false; test = null; //如果像IE67那样,只支持backgroundPositionXY,不支持backgroundPosition var XY = ["X","Y"],prefix = "backgroundPosition"; if (!dom.support.backgroundPosition && dom.support.backgroundPositionXY) { adapter[prefix+":get"] = function( node, name) { return XY.map(function(which){ return adapter[ "_default:get" ](node,prefix+which) }).join(" "); } adapter[prefix+":set"] =function(node, name, value){ XY.forEach(function(which,i){ node.style[ prefix +which ] = value.split(/\s/)[i] }) } } function parseBgPos(bgPos) { var parts = bgPos.split(/\s/), values = { "X": parts[0], "Y": parts[1] }; return values; } if (dom.support.backgroundPosition && !dom.support.backgroundPositionXY) { XY.forEach(function(which){ adapter[prefix+which+":get"] = function(node,name){ var values = parseBgPos( adapter[ "_default:get" ](node,prefix) ); return values[ which]; } adapter[prefix+which+":set"] = function(node,name,value){ var values = parseBgPos( adapter[ "_default:get" ](node,prefix) ), isX = which === "X"; node.style.backgroundPosition = (isX ? value : values[ "X" ]) + " " + (isX ? values[ "Y" ] : value); } }) } }); })(this,this.document);
css_ie.js
(function(global,DOC){ var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')]; dom.define("css_ie", function(){ dom.log("已加载css_ie模块") var adapter = dom.cssAdapter = {}; //========================= 处理 opacity ========================= var ropacity = /opacity=([^)]*)/i, ralpha = /alpha\([^)]*\)/i, rnumpx = /^-?\d+(?:px)?$/i, rnum = /^-?\d/; adapter["opacity:get"] = function(node,op){ //这是最快的获取IE透明值的方式,不需要动用正则了! if(node.filters.alpha){ op = node.filters.alpha.opacity; }else if(node.filters["DXImageTransform.Microsoft.Alpha"]){ op = node.filters["DXImageTransform.Microsoft.Alpha"].opacity }else{ op = (node.currentStyle.filter ||"opacity=100").match(ropacity)[1]; } return (~~op)/100; } adapter["opacity:set"] = function(node, name, value){ var currentStyle = node.currentStyle, style = node.style; if(!currentStyle.hasLayout) style.zoom = 1;//让元素获得hasLayout value = (value > 0.999) ? 1: (value < 0.001) ? 0 : value; if(node.filters.alpha){ //必须已经定义过透明滤镜才能使用以下便捷方式 node.filters.alpha.opacity = value * 100; }else{ style.filter = "alpha(opacity="+((value * 100) | 0)+")"; } //IE7的透明滤镜当其值为100时会让文本模糊不清 if(value === 1){ style.filter = currentStyle.filter.replace(ralpha,''); } style.visibility = value ? "visible" : "hidden"; if(node.tagName === "TR"){//IE bug,TD与TH不会继承TR的透明度 var self = arguments.callee; dom.slice(node.cells).forEach(function(cell){ self(cell,name, value); }); } } var ie8 = !!global.XDomainRequest, border = { thin: ie8 ? '1px' : '2px', medium: ie8 ? '3px' : '4px', thick: ie8 ? '5px' : '6px' }; adapter[ "_default:get" ] = function(node, name){ var ret = node.currentStyle && node.currentStyle[name]; if ((!rnumpx.test(ret) && rnum.test(ret))) { // Remember the original values var style = node.style, left = style.left, rsLeft = node.runtimeStyle && node.runtimeStyle.left ; if (rsLeft) { node.runtimeStyle.left = node.currentStyle.left; } style.left = name === 'fontSize' ? '1em' : (ret || 0); ret = style.pixelLeft + "px"; // Revert the changed values style.left = left; if (rsLeft) { node.runtimeStyle.left = rsLeft; } } if(ret == "medium"){ name = name.replace("Width","Style"); //border width 默认值为medium,即使其为0" if(arguments.callee(node,name) == "none"){ ret = "0px"; } } return ret === "" ? "auto" : border[ret] || ret; } }); })(this,this.document); //2011.9.5 //将cssName改为隋性函数,修正msTransform Bug
相关测试:
dom.define("test/css","spec,css",function(){ dom.addTestModule("样式操作模块-css",{ "dom.fn.css":function(){ var el = dom('<div id="test-div" ' + 'style="padding-left: 2pt; ' + 'background: transparent; ' + 'font-size:16px;' + 'float: left; ' + 'border: 5px solid rgb(0,0,0);">css test</div>').appendTo("body"); el = dom("#test-div") expect(el.css( 'float')).eq('left');//1 expect(el.css( 'position')).eq('static');//2 expect(el.css( 'backgroundColor')).match(function(val){ return val == "rgba(0, 0, 0, 0)" || val == "transparent" });//3 expect(el.css( 'backgroundPosition')).eq("0% 0%");//4 expect(el.css( 'backgroundPositionX')).eq('0%');//5 expect(el.css( 'fontSize')).eq('16px');//6 expect(el.css( 'border-right-width')).eq('5px');//7 var matchFn = function(val){ val = parseFloat(val) return val >= 2 && val <= 3 } expect(el.css( 'paddingLeft')).match(matchFn);//8 expect(el.css( 'padding-left')).match(matchFn);//9 expect(el.css( 'padding-right')).eq('0px');//10 expect(el.css( 'opacity')).eq('1');//11 // 不加入 dom 节点,ie9,firefox 返回 auto by computedStyle // ie7,8 返回负数,offsetHeight 返回0 //alert(elem.currentStyle.height);== auto expect(parseInt(el.css( 'height'))).match(function(val){ val = parseFloat(val) return val >= 18 && val <= 20 });//12 el.css( 'float', 'right'); expect(el.css( 'float')).eq('right');//13 el.css( 'font-size', '100%'); expect(el.css( 'font-size')).eq("16px");//14 el.css( 'opacity', '0.2'); expect(el.css( 'opacity')).match(function(val){ val = parseFloat(val); return val >= 0.2 && val < 0.21; }); el.css( 'border', '2px dashed red'); expect(el.css( 'borderLeftWidth')).eq('2px');//16 el.remove(); } }); });
使用方法与jQuery保持一致,读写器合而为一,set all get first。
dom.require("css",function(){ var a = dom('<div style="width:100px;opacity:0.7;filter:alpha(opacity=50),blur(add=ture,direction=135,strength=200)">'); dom.log( a.css("opacity"))//IE9,FF为0.7;IE6-8为0.5 });