• 博客园logo
  • 会员
  • 周边
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Joanna Qian
Stay Hungry, Stay Foolish!
博客园    首页    新随笔    联系   管理    订阅  订阅
图像替换技术

1、Fahrner图像替换

为了表示对发明者Todd Fahrner的尊重,这个技巧随后也被叫做“Fahrner图像替换(Fahrner Image Replacement,FIR)”。该技巧的实现非常简单:用span将元素中的文本包围起来,然后通过应用CSS样式隐藏这个span中的文本,最后将背景图像应用到该元素之上即可。例如,对于下面的这一段HTMl标记:

<h1 id="pageHeader"><span>webjx.com</span></h1>

我们可以使用下面的这段CSS容易地实现图像替换:

#pageHeader {
background: url(lemonfresh.gif) top left no-repeat;
width: 400px;
height: 20px;
}
#pageHeader span {
display: none;
}

通过使用CSS的display: none或visibility: hidden; 所以在#pageHeader 元素中的span元素都被隐藏起来。Hellsing同时使用了上述两种CSS设定——但它们的效果却是一致的。图像替换技术非常强大且很快开始流行——若是没有了它,我们甚至无法建立禅意花园。该技术可以说是实现复杂、灵活CSS布局的一埠最为重要基石

2、Rundler的方案

设计师Mike Rundle提出了一种使用负text-indent属性值的方法,将文本推到屏幕的左边缘之外。虽然该方案的适用性并不广泛——IE 5.0会将背景图片随文本一起推出浏览者的视线范围——但却相当简洁优雅。

<h3 id="header">I like webjx.com.</h3>

css

#header {
text-indent: -5000px;
background: url(sample-image.gif) no-repeat;
height: 25px;
}

优点:屏幕阅读器可正常访问;没有多余的<span>;简洁优雅的CSS。
缺点:并没有解决浏览器禁用图像后空白页面的可访问性问题;有时在IE 5.0中无法使用。
浏览器支持:WindowsInternet Explorer 5.5+, Netscape 7, Opera 6+, Firefox. MacintoshInternet Explorer 5.2, Safari, Firefox.

3.Levin的方案

Levin Alexander想出了一个绝妙的主意:不再将文本置于span中,而是将其从span中移出来,将文本和span一起放在父元素中,然后使用这个空白的span覆盖住文本,并将背景图像应用到该span之上。如果一切顺利的话,屏幕阅读器即可正常访问这段文本,且也充分考虑并解决了浏览器禁用图像后空白页面的可访问性问题。但新的问题也随之出现,那就是图像不能是透明的,否则用户将会看到下面的文本。且这种方案所需要的CSS极为冗长,让人难以理解。

<h3 class="replace" id="myh1">And a dash of Thyme.<span></span></h1>

css

.replace {
position: relative;
margin: 0px; padding: 0px;
/* hide overflow:hidden from IE5/Mac \*/
overflow: hidden;
/* */
}
.replace span {
display: block;
position: absolute;
top: 0px;
left: 0px;
z-index: 1; /*for Opera 5 and 6*/
}
#myh1, #myh1 span {
height: 25px;
width: 300px;
background-image: url(thyme.png);
}

优点:屏幕阅读器可正常访问;解决浏览器禁用图像后空白页面的可访问性问题。
缺点:无法使用透明图像;CSS代码较为冗长。
浏览器支持:WindowsInternet Explorer 5+, Netscape 7, Opera 6+, Firefox. MacintoshInternet Explorer 5.2, Safari, Firefox.

4、状态域方法(The State Scope Method)

Dave Shea 在他的一篇文章对此做了详细的总结,参看Dave Shea’s excellent summary,Paul Young 在分析现存的所有方法的优缺点之后,提出了一种新的方法,并将其命名为“状态域方法”(The State Method)

该图像替换技术需要借助于js来实现,但很容易执行,只需要将一小段js引入到头部即可。一旦js执行,响应的规则前将附加“.image-on”,只要客户端的图片未被禁用,规则就会生效,下面是一条应用到h1“状态域方法”的声明:

h1 { 
width: 100px; 
height: 50px;
} 
@media screen { 
.images-on h1 { 
text-indent: -10000px;
background-image: url(image.png);
overflow: hidden; 
}
} 
  • 第一条规则总是生效,h1就是我们所说的要添加背景图片的区域,第二条只有在image未被禁用时生效。“text-indent”使文字偏移于屏幕之外,“overflow:hidden”主要用来在FF下放置锚点在被点击时其焦点偏移于屏幕之外。
  • 第二条规则包绕在@media screen中,主要用来保证图像替换只发生在屏幕阅读器中,而不是在打印状态下执行。如果不这样处理,页面打印时,多数用户将看到一个很大的空隙而不是有意义的文本。不过如果我们不打印,它就可有可无了,原作者Paul Young给出的示范页就没有@media screen块了。抛开@media screen不谈,我们发现里面是个 后代选择器(Descendant selectors),亦有人称之为包含选择符,于是这些背景显示信息是否执行处理,就关键在于它(h1)的祖先(.images-on)是否存在了!我们可以通过addClass与removeClass为html动态添加或删除.images-on类。

该项技术执行起来很快。因为文本偏移于屏幕之外,图像可以包含透明元素,透过图像本身,你看不到任何文本。Js执行很快,几乎是瞬时的,它充分利用浏览器本身的特性。

方法解析

“状态域方法”是在一种假定的状态下,快速使css规则生效的方法,其上下文背景为document,这样避免了浏览器遍历DOM树。应用“状态域方法”有两个理由:

  1. 针对用户的反应,页面部分内容再格式化;
  2. 基于客户端浏览器、设备、和其它状况而附加额外的样式。

“状态域方法”通过使用下面的script给html附加一个class。

document.enableStateScope = function(scope, on) 
   { 
     var de = document.documentElement; 
     if (on) 
     de.className += " " + scope; 
     else 
     de.className = de.className.replace( 
       new RegExp("\\b" + scope + "\\b"), ""); 
   };

这段js有一点小问题,在示例页中切换功能并不生效,我重新修改了一下,代码如下:

function hasClass(ele,cls) {
return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
if (!this.hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
ele.className=ele.className.replace(reg,' ');
}
}
document.enableStateScope = function(scope, on) {
var de = document.documentElement; 
On ?  addClass(de,scope) : removeClass(de,scope);  
};

上面的hasClass、addClass、removeClass方法借用的是《Pro JavaScript Techniques》提供的方法。如果你使用过jquery,方法将更简单。

“状态域”可以通过下面的方法来切换:

if (condition == true) {
document.enableStateScope("myScope", true); 
}

如果“状态域”为“on”,状态域的名字将附加到规则的选择器之前,下面这条规则在条件为真时会将锚点的颜色变成blue。

a { color: red; } 
.myScope a { color: blue; }

正如你所预想的那样,状态域图像替代技术是通过检查图像是否被禁用而工作的。如果未被禁用,将激活“image-on”状态域,这很直接了当。

检查图片是否禁用

该方法检查图片是否禁用,并不是请求服务器上的图片,因为那样会导致一次额外的http请求。作者创建了一个巧妙的方法。

在大多数浏览器中,Image对象可以实例化并追溯到一个无效的URL(http://0),这样很容易检测Image的状态。如果禁用,onerror事件将触发,在js文件的开头,j建立一个新的图像对象:

var img = new Image();

但是,有两个古怪的浏览器对此方法并不兼容。在Gecko浏览器中,不论Image是否被禁用。Onerror事件总是被触发。所幸的是,另外一种可行的方案可以解决此问题--给html元素附加一个无效的背景图片,然后通过getComputedStyle方法获得style属性。如果Image禁用,其属性为none或url( invalid-url:):

if (img.style.MozBinding != null) { /*判断是否为火狐*/
/************略************/
}else { 
    img.style.cssText = "-webkit-opacity:0"; 
    if (img.style.webkitOpacity == 0) { /*判断是否为safari*/
        img.onload = function(){ 
             /*如果图片的宽大于零,证明图片可用,我们把on设置为true,否则为false*/
            document.enableStateScope("images-on", img.width > 0);         
        } 
       /*动态生成gif图片,预防因为图片不存在,一直报错!*/
        img.src =   "data:image/gif;base64,"
               +  "R0lGODlhAQABAIAAAP///wAAACH5BAE"
               +  "AAAAALAAAAAABAAEAAAICRAEAOw=="; 
    } 
} 

最后,对于其它浏览器,在开始初始化Image对象时,仅需检测onerror事件是否发生。

if (img.style.MozBinding != null) {
/************略************/
}else {
    if (img.style.webkitOpacity == 0){
    /************略************/
    }else{
        img.onerror = function(e) {
            document.enableStateScope("images-on", true); 
        } 
        /*取消onerror事件  */
        img.src = "about:blank";
    }      
}

下面给出完整方法,利用闭包保持enableStateScope方法一直存在下去!

(function(){
    d=document;e=d.documentElement;c="images-on";i=new Image();t=i.style;s=d.enableStateScope=function(s,o){
        if(o)e.className+=" "+s;else e.className=e.className.replace(new RegExp("\\b"+s+"\\b"),"");
    };if(t.MozBinding!=null){
        t.backgroundImage="url("+d.location.protocol+"//0)";b=window.getComputedStyle(i,'').backgroundImage;if(b!="none"&&b!="url(invalid-url:)"||d.URL.substr(0,2)=="fi")s(c,true);
    }else{
        t.cssText="-webkit-opacity:0";if(t.webkitOpacity==0){
            i.onload=function(){
                s(c,i.width>0);
            };i.src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
        }else{
            i.onerror=function(){
                s(c,true);
            };i.src="about:blank";
        }
    }
})();

此方法的一些优点

  • 当客户端的电脑不支持javascript与禁止图片显示时,它都能优雅地降级而不致于页面效果有太多的差异
  • 支持半透明或透明的图片
  • 实现非常简单,只要导入我们的脚本以及设置需要图片替换的区域
  • 由于是用非常基础的技术,即使是过气的游览器中也畅通无阻
  • 符合标准,对屏幕阅读器与搜索引擎友好
  • 不需要添加额外的标签
  • 不消耗内存(因为基本不遍历DOM树)
  • 即使是页面加载完毕对DOM进行操作也不会影响它的效果
  • 在加载过程基本不会引发或只有轻微的闪烁现象
  • 文本与图片可以在容器元素设置居中或居左对齐
  • 不要求在服务器端存在一张1*1的gif图片来防止出错
  • 在显示器与打印页上都显示良好
  • 由于是使用CSS background-image属性来设置图片,便于我们使用image sprites技术来减少请求数

附上原作者Paul Young的文章:http://www.sitepoint.com/article/image-replacement-state-scope/

完整代码:

<!doctype html>
<html dir="ltr" lang="zh-CN">
    <head>
        <meta charset="utf-8"/>
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
        <style type="text/css">
        </style>
        <script type="text/javascript">/*<![CDATA[*/
            var hasClass = function(ele,cls) {
                return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
            }
            var addClass = function(ele,cls) {
                if (!this.hasClass(ele,cls)) ele.className += " "+cls;
            }
            var removeClass = function(ele,cls) {
                if (hasClass(ele,cls)) {
                    var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
                    ele.className=ele.className.replace(reg,' ');
                }
            }
            // Don't copy and paste this code, use the minified script
            document.enableStateScope = function(scope, on) {
                var de = document.documentElement;
                on ? addClass(de,scope) : removeClass(de,scope);
            };
            (function(){
                var de = document.documentElement;
                var img = new Image();
                // 针对于 Gecko内核游览器的处理
                if (img.style.MozBinding != null){
                    img.style.backgroundImage = "url(" + document.location.protocol + "//0)";
                    var bg = window.getComputedStyle(img, '').backgroundImage;
                    //如果images为off,则在FF2以及其旧版本中,bg的值为 "none"
                    //在FF3中,bg的值为"url(invalid-url:)"
                    if (bg != "none" && bg != "url(invalid-url:)" || document.URL.substr(0, 2) == "fi"){
                        document.enableStateScope("images-on", true);
                    }
                }else{
                    //针对于Safari游览器(包括 iPhone)的处理
                    img.style.cssText = "-webkit-opacity:0";
                    if (img.style.webkitOpacity == 0){
                        img.onload = function(){                         
                            document.enableStateScope("images-on", img.width > 0);
                        }
                        // Source the image to a 43-byte 1x1 pixel GIF image encoded as a data URI.
                        img.src =
                            "data:image/gif;base64," +
                            "R0lGODlhAQABAIAAAP///wAAACH5BAE" +
                            "AAAAALAAAAAABAAEAAAICRAEAOw==";
                    }else{// Handling for everything else
                        img.onerror = function(e){
                            document.enableStateScope("images-on", true);
                        }
                        img.src = "about:blank";
                    }
                }
            } )();
            //]]>
        </script>
        <script type="text/javascript">//<![CDATA
           window.onload = function(){
               document.enableStateScope("images-on", false);
           }
            // Toggles the images-on state scope on and off,
            // and displays the appropriate message
            function toggle(on){
                document.enableStateScope("images-on", on);
                document.getElementById(on ? "stateScopeOn" : "stateScopeOff").style.display = "block";
                document.getElementById(on ? "stateScopeOff" : "stateScopeOn").style.display = "none";
            }
            //]]>
        </script>
        <style type="text/css">
            .width{
                width: 800px;
                margin: auto;
                text-align: left;
            }
            .header H1{
                margin-top: 10px;
                margin-bottom: 25px;
                color: white;
                line-height: 1;
                top: -35px;
                font-size: 9pt;
                text-transform: uppercase;
            }
            .header H1 .statescope{
                color: #ABDDA9;
                letter-spacing: -2px;
                text-transform: none;
                font-size: 35pt;
                top: 0.52em;
            }

            .images-on .header H1{ /*利用images-on来监视H1的样式*/
                text-indent: -12345px;
                overflow: hidden;
                background:url(http://images.cnblogs.com/cnblogs_com/rubylouvre/199042/o_aggregated.png) no-repeat;
                width: 297px;
                height: 66px;
                top: 0;
            }

            /*Toggle Switch*/
            #stateScopeOff, #stateScopeOn{
                position: absolute;
                top: -1px;
                right: 25px;
                background-color: white;
                padding: 9px 15px;
                border: 1px solid #79B17C; /*[e]1px solid @00*/
                font-size: 10pt;
                z-index: 1;
            }
            #stateScopeOn{
                display: none;
            }

        </style>
    </head>
    <body>
        <div class="width">
            <div class="header">
                <h1>The <span class="statescope">State Scope</span></h1>
            </div>
        </div>
        <div id="stateScopeOff">现在images-on这个类 <strong>是不存在的。</strong><a href="javascript:toggle(true)">是否添加它?</a></div>
        <div id="stateScopeOn">现在images-on这个类 <strong>已经存在。</strong><a href="javascript:toggle(false)">是否删掉它?</a></div>
    </body>
</html>

 

posted on 2013-06-20 04:00  Joanna Qian  阅读(946)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3