熟悉css的開發者一定知道圖像替換技術,也深知它的意義,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;
}
}
第一條規則總是生效,第二條只有在image未被禁用時生效。“text-indent”使文字偏移于屏幕之外,“overflow:hidden”主要用來在ff下放置錨點在被點擊時其焦點偏移于屏幕之外。
第二條規則包繞在@media screen中,主要用來保證圖像替換只發生在屏幕閱讀器中,而不是在打印狀態下執行。如果不這樣處理,頁面打印時,多數用戶將看到一個很大的空隙而不是有意義的文本。
該項技術執行起來很快。因為文本偏移于屏幕之外,圖像可以包含透明元素,透過圖像本身,你看不到任何文本。js執行很快,幾乎是瞬時的,它充分利用瀏覽器本身的特性。
方法解析
“狀態域方法”是在一種假定的狀態下,快速使css規則生效的方法,其上下文背景為document,這樣避免了瀏覽器遍歷dom樹。應用“狀態域方法”有兩個理由:
“狀態域方法”通過使用下面的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)
{
img.style.backgroundimage = "url(" + document.location.protocol + "//0)";
var bg = window.getcomputedstyle(img, '').backgroundimage;
if (bg != "none" && bg != "url(invalid-url:)" || document.url.substr(0, 2) == "fi")
{
document.enablestatescope("images-on", true);
}
}
另外一個富有挑戰性的瀏覽器是safari,如果請求是一個無效的url,safari的狀態欄將出現錯誤提示,但頁面布局不受任何影響。如果用戶的狀態欄處于開啟狀態,報錯將一直持續,這很不專業,同樣,作者研究了另外一種可行的方案。如果image來自于1*1的gif圖像,且被數據編碼。如果image禁用,其寬度將為0,以下為在safari中測試的情況:
else
{
img.style.csstext = "-webkit-opacity:0";
if (img.style.webkitopacity == 0)
{
img.onload = function()
{
document.enablestatescope("images-on", img.width > 0);
}
img.src =
"data:image/gif;base64," +
"r0lgodlhaqabaiaaap///waaach5bae" +
"aaaaalaaaaaabaaeaaaicraeaow==";
}
}
最后,對于其它瀏覽器,在開始初始化image對象時,僅僅需要測試onerror觸發事件。
else
{
img.onerror = function(e)
{
document.enablestatescope("images-on", true);
}
img.src = "about:blank";
}
狀態域是可以切換的
可以創建一個系統讓用戶在文本和替代圖像之間切換。
查看示例(示例文件由paul young提供)
class屬性添加到html之上而不是body或其它子元素之上,主要原因在于在圖像替換之前,body需要全面加載。如果“image-on”不添加到html之上。當狀態域啟用時,將會出現閃動。
圖像替換技術是css中相當重要的一部分。鑒于現存圖像替換技術的缺點,作者花大量時間另辟蹊徑,方法獨到,值得借鑒。
示例下載:tate-scope-image-replacement.zip
翻譯原文:http://www.denisdeng.com/?p=235
英文原文:http://www.sitepoint.com/article/image-replacement-state-scope/
新聞熱點
疑難解答