The source code

    /**
     * @ignore
     *  dom/style
     * @author yiminghe@gmail.com, lifesinger@gmail.com
     */
    KISSY.add('dom/base/style', function (S, DOM, undefined) {
        var WINDOW = S.Env.host,
            UA = S.UA,
            getNodeName = DOM.nodeName,
            doc = WINDOW.document,
            STYLE = 'style',
            FLOAT = 'float',
            RE_MARGIN = /^margin/,
            WIDTH = 'width',
            HEIGHT = 'height',
            AUTO = 'auto',
            DISPLAY = 'display',
            OLD_DISPLAY = DISPLAY + S.now(),
            NONE = 'none',
            myParseInt = parseInt,
            cssNumber = {
                'fillOpacity': 1,
                'fontWeight': 1,
                'lineHeight': 1,
                'opacity': 1,
                'orphans': 1,
                'widows': 1,
                'zIndex': 1,
                'zoom': 1
            },
            rmsPrefix = /^-ms-/,
            RE_DASH = /-([a-z])/ig,
            CAMEL_CASE_FN = function (all, letter) {
                return letter.toUpperCase();
            },
        // 考虑 ie9 ...
            R_UPPER = /([A-Z]|^ms)/g,
            EMPTY = '',
            DEFAULT_UNIT = 'px',
            CUSTOM_STYLES = {},
            cssProps = {},
            defaultDisplay = {};

        cssProps[FLOAT] = 'cssFloat';

        function camelCase(name) {
            // fix #92, ms!
            return name.replace(rmsPrefix, 'ms-').replace(RE_DASH, CAMEL_CASE_FN);
        }

        function getDefaultDisplay(tagName) {
            var body,
                oldDisplay = defaultDisplay[ tagName ],
                elem;
            if (!defaultDisplay[ tagName ]) {
                body = doc.body || doc.documentElement;
                elem = doc.createElement(tagName);
                // note: do not change default tag display!
                DOM.prepend(elem, body);
                oldDisplay = DOM.css(elem, 'display');
                body.removeChild(elem);
                // Store the correct default display
                defaultDisplay[ tagName ] = oldDisplay;
            }
            return oldDisplay;
        }

        S.mix(DOM,
            /**
             * @override KISSY.DOM
             * @class
             * @singleton
             */
            {
                _camelCase: camelCase,

                _CUSTOM_STYLES: CUSTOM_STYLES,

                _cssProps: cssProps,

                _getComputedStyle: function (elem, name) {
                    var val = '',
                        computedStyle,
                        width,
                        minWidth,
                        maxWidth,
                        style,
                        d = elem.ownerDocument;

                    name = name.replace(R_UPPER, '-$1').toLowerCase();

                    // https://github.com/kissyteam/kissy/issues/61
                    if (computedStyle = d.defaultView.getComputedStyle(elem, null)) {
                        val = computedStyle.getPropertyValue(name) || computedStyle[name];
                    }

                    // 还没有加入到 document，就取行内
                    if (val === '' && !DOM.contains(d, elem)) {
                        name = cssProps[name] || name;
                        val = elem[STYLE][name];
                    }

                    // Safari 5.1 returns percentage for margin
                    if (DOM._RE_NUM_NO_PX.test(val) && RE_MARGIN.test(name)) {
                        style = elem.style;
                        width = style.width;
                        minWidth = style.minWidth;
                        maxWidth = style.maxWidth;

                        style.minWidth = style.maxWidth = style.width = val;
                        val = computedStyle.width;

                        style.width = width;
                        style.minWidth = minWidth;
                        style.maxWidth = maxWidth;
                    }

                    return val;
                },

                /**
                 *  Get inline style property from the first element of matched elements
                 *  or
                 *  Set one or more CSS properties for the set of matched elements.
                 *  @param {HTMLElement[]|String|HTMLElement} selector Matched elements
                 *  @param {String|Object} name A CSS property. or A map of property-value pairs to set.
                 *  @param [val] A value to set for the property.
                 *  @return {undefined|String}
                 */
                style: function (selector, name, val) {
                    var els = DOM.query(selector),
                        k,
                        ret,
                        elem = els[0], i;
                    // supports hash
                    if (S.isPlainObject(name)) {
                        for (k in name) {
                            for (i = els.length - 1; i >= 0; i--) {
                                style(els[i], k, name[k]);
                            }
                        }
                        return undefined;
                    }
                    if (val === undefined) {
                        ret = '';
                        if (elem) {
                            ret = style(elem, name, val);
                        }
                        return ret;
                    } else {
                        for (i = els.length - 1; i >= 0; i--) {
                            style(els[i], name, val);
                        }
                    }
                    return undefined;
                },

                /**
                 * Get the computed value of a style property for the first element in the set of matched elements.
                 * or
                 * Set one or more CSS properties for the set of matched elements.
                 * @param {HTMLElement[]|String|HTMLElement} selector 选择器或节点或节点数组
                 * @param {String|Object} name A CSS property. or A map of property-value pairs to set.
                 * @param [val] A value to set for the property.
                 * @return {undefined|String}
                 */
                css: function (selector, name, val) {
                    var els = DOM.query(selector),
                        elem = els[0],
                        k,
                        hook,
                        ret,
                        i;
                    // supports hash
                    if (S.isPlainObject(name)) {
                        for (k in name) {
                            for (i = els.length - 1; i >= 0; i--) {
                                style(els[i], k, name[k]);
                            }
                        }
                        return undefined;
                    }

                    name = camelCase(name);
                    hook = CUSTOM_STYLES[name];
                    // getter
                    if (val === undefined) {
                        // supports css selector/Node/NodeList
                        ret = '';
                        if (elem) {
                            // If a hook was provided get the computed value from there
                            if (hook && 'get' in hook && (ret = hook.get(elem, true)) !== undefined) {
                            } else {
                                ret = DOM._getComputedStyle(elem, name);
                            }
                        }
                        return ret === /**@type String
                         @ignore*/undefined ? '' : ret;
                    }
                    // setter
                    else {
                        for (i = els.length - 1; i >= 0; i--) {
                            style(els[i], name, val);
                        }
                    }
                    return undefined;
                },

                /**
                 * Display the matched elements.
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements.
                 */
                show: function (selector) {
                    var els = DOM.query(selector),
                        tagName,
                        old,
                        elem, i;
                    for (i = els.length - 1; i >= 0; i--) {
                        elem = els[i];
                        elem[STYLE][DISPLAY] = DOM.data(elem, OLD_DISPLAY) || EMPTY;
                        // 可能元素还处于隐藏状态，比如 css 里设置了 display: none
                        if (DOM.css(elem, DISPLAY) === NONE) {
                            tagName = elem.tagName.toLowerCase();
                            old = getDefaultDisplay(tagName);
                            DOM.data(elem, OLD_DISPLAY, old);
                            elem[STYLE][DISPLAY] = old;
                        }
                    }
                },

                /**
                 * Hide the matched elements.
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements.
                 */
                hide: function (selector) {
                    var els = DOM.query(selector),
                        elem, i;
                    for (i = els.length - 1; i >= 0; i--) {
                        elem = els[i];
                        var style = elem[STYLE],
                            old = style[DISPLAY];
                        if (old !== NONE) {
                            if (old) {
                                DOM.data(elem, OLD_DISPLAY, old);
                            }
                            style[DISPLAY] = NONE;
                        }
                    }
                },

                /**
                 * Display or hide the matched elements.
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements.
                 */
                toggle: function (selector) {
                    var els = DOM.query(selector),
                        elem, i;
                    for (i = els.length - 1; i >= 0; i--) {
                        elem = els[i];
                        if (DOM.css(elem, DISPLAY) === NONE) {
                            DOM.show(elem);
                        } else {
                            DOM.hide(elem);
                        }
                    }
                },

                /**
                 * Creates a stylesheet from a text blob of rules.
                 * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
                 * @param {window} [refWin=window] Window which will accept this stylesheet
                 * @param {String} [cssText] The text containing the css rules
                 * @param {String} [id] An id to add to the stylesheet for later removal
                 */
                addStyleSheet: function (refWin, cssText, id) {
                    refWin = refWin || WINDOW;

                    if (typeof refWin == 'string') {
                        id = cssText;
                        cssText = /**@type String
                         @ignore*/refWin;
                        refWin = WINDOW;
                    }

                    refWin = DOM.get(refWin);

                    var win = DOM.getWindow(refWin),
                        doc = win.document,
                        elem;

                    if (id && (id = id.replace('#', EMPTY))) {
                        elem = DOM.get('#' + id, doc);
                    }

                    // 仅添加一次，不重复添加
                    if (elem) {
                        return;
                    }

                    elem = DOM.create('<style>', { id: id }, doc);

                    // 先添加到 DOM 树中，再给 cssText 赋值，否则 css hack 会失效
                    DOM.get('head', doc).appendChild(elem);

                    if (elem.styleSheet) { // IE
                        elem.styleSheet.cssText = cssText;
                    } else { // W3C
                        elem.appendChild(doc.createTextNode(cssText));
                    }
                },

                /**
                 * Make matched elements unselectable
                 * @param {HTMLElement[]|String|HTMLElement} selector  Matched elements.
                 */
                unselectable: function (selector) {
                    var _els = DOM.query(selector), elem, j,
                        e,
                        i = 0,
                        excludes,
                        els;
                    for (j = _els.length - 1; j >= 0; j--) {
                        elem = _els[j];
                        if (UA['gecko']) {
                            elem[STYLE]['MozUserSelect'] = 'none';
                        } else if (UA['webkit']) {
                            elem[STYLE]['KhtmlUserSelect'] = 'none';
                        } else if (UA['ie'] || UA['opera']) {
                            els = elem.getElementsByTagName('*');
                            elem.setAttribute('unselectable', 'on');
                            excludes = ['iframe', 'textarea', 'input', 'select'];
                            while (e = els[i++]) {
                                if (!S.inArray(getNodeName(e), excludes)) {
                                    e.setAttribute('unselectable', 'on');
                                }
                            }
                        }

                    }
                },

                /**
                 * Get the current computed width for the first element in the set of matched elements, including padding but not border.
                 * @method
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements
                 * @return {Number}
                 */
                innerWidth: 0,
                /**
                 * Get the current computed height for the first element in the set of matched elements, including padding but not border.
                 * @method
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements
                 * @return {Number}
                 */
                innerHeight: 0,
                /**
                 *  Get the current computed width for the first element in the set of matched elements, including padding and border, and optionally margin.
                 * @method
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements
                 * @param {Boolean} [includeMargin] A Boolean indicating whether to include the element's margin in the calculation.
                 * @return {Number}
                 */
                outerWidth: 0,
                /**
                 * Get the current computed height for the first element in the set of matched elements, including padding, border, and optionally margin.
                 * @method
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements
                 * @param {Boolean} [includeMargin] A Boolean indicating whether to include the element's margin in the calculation.
                 * @return {Number}
                 */
                outerHeight: 0,
                /**
                 * Get the current computed width for the first element in the set of matched elements.
                 * or
                 * Set the CSS width of each element in the set of matched elements.
                 * @method
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements
                 * @param {String|Number} [value]
                 * An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string).
                 * @return {Number|undefined}
                 */
                width: 0,
                /**
                 * Get the current computed height for the first element in the set of matched elements.
                 * or
                 * Set the CSS height of each element in the set of matched elements.
                 * @method
                 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements
                 * @param {String|Number} [value]
                 * An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string).
                 * @return {Number|undefined}
                 */
                height: 0
            });

        S.each([WIDTH, HEIGHT], function (name) {
            DOM['inner' + S.ucfirst(name)] = function (selector) {
                var el = DOM.get(selector);
                return el && getWHIgnoreDisplay(el, name, 'padding');
            };

            DOM['outer' + S.ucfirst(name)] = function (selector, includeMargin) {
                var el = DOM.get(selector);
                return el && getWHIgnoreDisplay(el, name, includeMargin ? 'margin' : 'border');
            };

            DOM[name] = function (selector, val) {
                var ret = DOM.css(selector, name, val);
                if (ret) {
                    ret = parseFloat(ret);
                }
                return ret;
            };
        });

        var cssShow = { position: 'absolute', visibility: 'hidden', display: 'block' };

        /*
         css height,width 永远都是计算值
         */
        S.each(['height', 'width'], function (name) {
            /**
             * @ignore
             */
            CUSTOM_STYLES[ name ] = {
                /**
                 * @ignore
                 */
                get: function (elem, computed) {
                    if (computed) {
                        return getWHIgnoreDisplay(elem, name) + 'px';
                    }
                    return undefined;
                }
            };
        });

        S.each(['left', 'top'], function (name) {

            CUSTOM_STYLES[ name ] = {
                get: function (elem, computed) {
                    var val, offset;
                    if (computed) {
                        val = DOM._getComputedStyle(elem, name);

                        // 1. 当没有设置 style.left 时，getComputedStyle 在不同浏览器下，返回值不同
                        //    比如：firefox 返回 0, webkit/ie 返回 auto
                        // 2. style.left 设置为百分比时，返回值为百分比
                        // 对于第一种情况，如果是 relative 元素，值为 0. 如果是 absolute 元素，值为 offsetLeft - marginLeft
                        // 对于第二种情况，大部分类库都未做处理，属于“明之而不 fix”的保留 bug
                        if (val === AUTO) {
                            val = 0;
                            if (S.inArray(DOM.css(elem, 'position'), ['absolute', 'fixed'])) {
                                offset = elem[name === 'left' ? 'offsetLeft' : 'offsetTop'];

                                // old-ie 下，elem.offsetLeft 包含 offsetParent 的 border 宽度，需要减掉
                                if (UA.ie && (doc['documentMode'] || 0) < 9 || UA['opera']) {
                                    // 类似 offset ie 下的边框处理
                                    // 如果 offsetParent 为 html ，需要减去默认 2 px == documentElement.clientTop
                                    // 否则减去 borderTop 其实也是 clientTop
                                    // http://msdn.microsoft.com/en-us/library/aa752288%28v=vs.85%29.aspx
                                    // ie<9 注意有时候 elem.offsetParent 为 null ...
                                    // 比如 DOM.append(DOM.create('<div class='position:absolute'></div>'),document.body)
                                    offset -= elem.offsetParent && elem.offsetParent['client' + (name == 'left' ? 'Left' : 'Top')]
                                        || 0;
                                }
                                val = offset - (myParseInt(DOM.css(elem, 'margin-' + name)) || 0);
                            }
                            val += 'px';
                        }
                    }
                    return val;
                }
            };
        });

        function swap(elem, options, callback) {
            var old = {}, name;

            // Remember the old values, and insert the new ones
            for (name in options) {
                old[ name ] = elem[STYLE][ name ];
                elem[STYLE][ name ] = options[ name ];
            }

            callback.call(elem);

            // Revert the old values
            for (name in options) {
                elem[STYLE][ name ] = old[ name ];
            }
        }

        function style(elem, name, val) {
            var style,
                ret,
                hook;
            if (elem.nodeType === 3 || elem.nodeType === 8 || !(style = elem[STYLE])) {
                return undefined;
            }
            name = camelCase(name);
            hook = CUSTOM_STYLES[name];
            name = cssProps[name] || name;
            // setter
            if (val !== undefined) {
                // normalize unset
                if (val === null || val === EMPTY) {
                    val = EMPTY;
                }
                // number values may need a unit
                else if (!isNaN(Number(val)) && !cssNumber[name]) {
                    val += DEFAULT_UNIT;
                }
                if (hook && hook.set) {
                    val = hook.set(elem, val);
                }
                if (val !== undefined) {
                    // ie 无效值报错
                    try {
                        // EMPTY will unset style!
                        style[name] = val;
                    } catch (e) {
                        S.log('css set error :' + e);
                    }
                    // #80 fix,font-family
                    if (val === EMPTY && style.removeAttribute) {
                        style.removeAttribute(name);
                    }
                }
                if (!style.cssText) {
                    // weird for chrome, safari is ok?
                    // https://github.com/kissyteam/kissy/issues/231
                    UA.webkit && (style = elem.outerHTML);
                    elem.removeAttribute('style');
                }
                return undefined;
            }
            //getter
            else {
                // If a hook was provided get the non-computed value from there
                if (hook && 'get' in hook && (ret = hook.get(elem, false)) !== undefined) {

                } else {
                    // Otherwise just get the value from the style object
                    ret = style[ name ];
                }
                return ret === undefined ? '' : ret;
            }
        }

        // fix #119 : https://github.com/kissyteam/kissy/issues/119
        function getWHIgnoreDisplay(elem) {
            var val, args = arguments;
            // in case elem is window
            // elem.offsetWidth === undefined
            if (elem.offsetWidth !== 0) {
                val = getWH.apply(undefined, args);
            } else {
                swap(elem, cssShow, function () {
                    val = getWH.apply(undefined, args);
                });
            }
            return val;
        }

        /*
         得到元素的大小信息
         @param elem
         @param name
         @param {String} [extra]  'padding' : (css width) + padding
         'border' : (css width) + padding + border
         'margin' : (css width) + padding + border + margin
         */
        function getWH(elem, name, extra) {
            if (S.isWindow(elem)) {
                return name == WIDTH ? DOM.viewportWidth(elem) : DOM.viewportHeight(elem);
            } else if (elem.nodeType == 9) {
                return name == WIDTH ? DOM.docWidth(elem) : DOM.docHeight(elem);
            }
            var which = name === WIDTH ? ['Left', 'Right'] : ['Top', 'Bottom'],
                val = name === WIDTH ? elem.offsetWidth : elem.offsetHeight;

            if (val > 0) {
                if (extra !== 'border') {
                    S.each(which, function (w) {
                        if (!extra) {
                            val -= parseFloat(DOM.css(elem, 'padding' + w)) || 0;
                        }
                        if (extra === 'margin') {
                            val += parseFloat(DOM.css(elem, extra + w)) || 0;
                        } else {
                            val -= parseFloat(DOM.css(elem, 'border' + w + 'Width')) || 0;
                        }
                    });
                }

                return val;
            }

            // Fall back to computed then un computed css if necessary
            val = DOM._getComputedStyle(elem, name);
            if (val == null || (Number(val)) < 0) {
                val = elem.style[ name ] || 0;
            }
            // Normalize '', auto, and prepare for extra
            val = parseFloat(val) || 0;

            // Add padding, border, margin
            if (extra) {
                S.each(which, function (w) {
                    val += parseFloat(DOM.css(elem, 'padding' + w)) || 0;
                    if (extra !== 'padding') {
                        val += parseFloat(DOM.css(elem, 'border' + w + 'Width')) || 0;
                    }
                    if (extra === 'margin') {
                        val += parseFloat(DOM.css(elem, extra + w)) || 0;
                    }
                });
            }

            return val;
        }

        return DOM;
    }, {
        requires: ['./api']
    });

    /*
     2011-12-21
     - backgroundPositionX, backgroundPositionY firefox/w3c 不支持
     - w3c 为准，这里不 fix 了

     2011-08-19
     - 调整结构，减少耦合
     - fix css('height') == auto

     NOTES:
     - Opera 下，color 默认返回 #XXYYZZ, 非 rgb(). 目前 jQuery 等类库均忽略此差异，KISSY 也忽略。
     - Safari 低版本，transparent 会返回为 rgba(0, 0, 0, 0), 考虑低版本才有此 bug, 亦忽略。

     - getComputedStyle 在 webkit 下，会舍弃小数部分，ie 下会四舍五入，gecko 下直接输出 float 值。

     - color: blue 继承值，getComputedStyle, 在 ie 下返回 blue, opera 返回 #0000ff, 其它浏览器
     返回 rgb(0, 0, 255)

     - 总之：要使得返回值完全一致是不大可能的，jQuery/ExtJS/KISSY 未“追求完美”。YUI3 做了部分完美处理，但
     依旧存在浏览器差异。
     */