你也許沒聽過jQuery.cssHooks,但只要寫過.css("opacity", "0.5"),你就已經享用過它的好處了! cssHooks是jQuery用來實現跨瀏覽器CSS特效的手法,大家有沒有想過,IE是從IE9才開始支援CSS opacity屬性,為什麼設定.css("opacity", "0.5")後,連IE7, IE8甚至已經不該繼續出現在地球上的某種瀏覽器都能正常呈現半透明的效果??

追進jquery.js(以jquery-1.6.js為例),看到以下程式碼才恍然大悟: 原來jQuery在底層偷偷為IE8之前的版本加上Alpha濾鏡設定實現相等的半透明效果! 我們才得以靠css(“opacity”, “0.5”)走遍天下。

if ( !jQuery.support.opacity ) {
    jQuery.cssHooks.opacity = {
        get: function( elem, computed ) {
            // IE uses filters for opacity
            return ropacity.test( (computed && elem.currentStyle ? 
                   elem.currentStyle.filter : elem.style.filter) || "" ) ?
                ( parseFloat( RegExp.$1 ) / 100 ) + "" :
                computed ? "1" : "";
        },
 
        set: function( elem, value ) {
            var style = elem.style,
                currentStyle = elem.currentStyle;
 
            // IE has trouble with opacity if it does not have layout
            // Force it by setting the zoom level
            style.zoom = 1;
 
            // Set the alpha filter to set the opacity
            var opacity = jQuery.isNaN( value ) ?
                "" :
                "alpha(opacity=" + value * 100 + ")",
                filter = currentStyle && currentStyle.filter || style.filter || "";
 
            style.filter = ralpha.test( filter ) ?
                filter.replace( ralpha, opacity ) :
                filter + " " + opacity;
        }
    };
}

見識到cssHooks的妙用,一時手癢也試著體驗一下自行打造cssHook的感覺。就以ericsk上回介紹的CSS3圖片漸層跨瀏覽器寫法為例,打算享受用$(...).css("lineGradBackground", "#FF9933,#666666");就能跨瀏覽器產生漸層背景特效的快感!

<!DOCTYPE html>
<html>
<head>
    <title>CSS Hooks API</title>
    <script type="text/javascript" 
        src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.js"></script>
    <script type="text/javascript">
        //cssHooks的效果在於 -- 假設有人不辭辛勞種出大樹
        (function ($) {
            var _patterns = {
                "msie": "progid:DXImageTransform.Microsoft.Gradient(" +
                         "StartColorStr='{0}', EndColorStr='{1}', GradientType=0)",
                "msie10": "-ms-linear-gradient(top, {0} 0%, {1} 100%)",
                "mozilla": "-moz-linear-gradient(top, {0} 0%, {1} 100%)",
                "opera": "-o-linear-gradient(top, {0} 0%, {1} 100%)",
 "webkit": "-webkit-gradient(linear, left top, left bottom, from({0}), to({1}))"
            };
            var _browserName = function () {
                var ua = $.browser;
                if (ua.msie)
                    if (ua.version.split('.')[0] > 9) return "msie10";
                    else return "msie";
                else if (ua.mozilla) return "mozilla";
                else if (ua.opera) return "opera";
                else if (ua.webkit) return "webkit";
                else return "unknown";
            }
            var _genCssString = function (s, b) {
                var reStr = _patterns[b];
                if (!reStr) return null;
                var p = s.split(',');
                if (p.length < 2) return;
                return reStr.replace(/\{0\}/, p[0])
                            .replace(/\{1\}/, p[1]);
            };
            $.cssHooks["lineGradBackground"] = {
                get: function (elem, computed, extra) {
                    return "not implemented!";
                },
                set: function (elem, value) {
                    var b = _browserName();
                    elem.style[b == "msie" ? "filter" : "background"] =
                        _genCssString(value, b);
                }
            };
        })(jQuery);
    </script>
    <script type="text/javascript">
        //後人就可以在樹下納涼,用一行css()搞定可跨瀏覽器的奇炫CSS特效
        $(function () {
            $("#x").css("lineGradBackground", "#3399FF,#66FFFF");
            $("#y").css("lineGradBackground", "#FF9933,#666666");
        });
    </script>
</head>
<body>
<div style="width: 300px; height: 60px;" id="x"></div>
<div style="width: 300px; height: 60px;" id="y"></div>
</body>
</html>

如程式所示,由於不同瀏覽器的CSS語法頗為分歧,cssHooks邏輯寫起來囉索非常,要不是偷懶沒寫撰寫讀取現有CSS漸層設定的get邏輯,程式應該還要更長的。

經此番嘗試,我的心得是: cssHooks是一種典型的宋丟力甘扣丟哇(註1)前人種樹後人乘涼的機制,如果有選擇的話,還是乘涼就好… orz

NPNT,所以就來個IE7, IE8, IE9, IE10, Chrome, Firefox, Safari, Opera測試結果大拼盤吧! 少了一種? 基於我是夠意思的好朋友,要協助大家早日遠離那種"很可怕,不要問"的老瀏覽器,即日起跨瀏覽器時將繼續秉持"有所跨有所不跨"的原則,請大家跟我一起忘了它吧!


IE7


IE8


IE9


IE10


Chrome


FireFox


Safari


Opera

註1: 台語,意指"爽到你艱苦到我"


Comments

# by D

如果只是要達到靜態 cross-browser CSS 的話,用 jQuery 可能會額外浪費效能,不妨改用像 Sass 等有 mixin 的 CSS extensions

# by Apparition2018

嘿嘿,見鬼啦!!!

Post a comment