< img> 標(biāo)簽是頁(yè)面上最為重要的元素之一。很難想象一個(gè)頁(yè)面上沒(méi)有圖片的樣子,這樣的頁(yè)面效果將會(huì)大打折扣。
任何一個(gè)前端工程師想必對(duì)< img>標(biāo)簽都非常熟悉了,畢竟經(jīng)常和它打交道嘛。但你真的對(duì)它完全了解嗎?如果你能準(zhǔn)確無(wú)誤地回答出以下幾個(gè)關(guān)于< img>的問(wèn)題,那么恭喜你,本文你可以不再往下看了,或者說(shuō)你可以用省視的目光來(lái)核對(duì)本文。
- 問(wèn)題1:如果在一個(gè)頁(yè)面上插入< img>標(biāo)簽,有哪些屬性是必需的?
- 問(wèn)題2:< img>標(biāo)簽在HTML和XHTML中有什么區(qū)別?
- 問(wèn)題3:在一個(gè)頁(yè)面上插入< img>標(biāo)簽,為什么說(shuō)最好要使用height和width屬性?
- 問(wèn)題4:< img>標(biāo)簽的onload/onerror/onabort事件,在什么情況下會(huì)被觸發(fā)?
- 問(wèn)題5:我們一般知道,當(dāng)一個(gè)圖片請(qǐng)求返回404時(shí),會(huì)觸發(fā)onerror事件,那當(dāng)圖片請(qǐng)求返回302時(shí),會(huì)觸發(fā)onerror事件嗎?304呢?403呢?500呢?請(qǐng)求超時(shí)呢?甚至說(shuō)當(dāng)返回200,但內(nèi)容并非是圖片時(shí),也會(huì)觸發(fā)onerror么?
- 問(wèn)題6:圖片觸發(fā)onerror事件時(shí),能使用javascript獲取到圖片請(qǐng)求的響應(yīng)代碼么?
- 問(wèn)題7:我們一般知道,< img>標(biāo)簽可以用來(lái)發(fā)起跨域請(qǐng)求,你能手寫出一段正確使用< img>發(fā)起跨域請(qǐng)求的javascript代碼么?
- 問(wèn)題8:用戶是可以設(shè)置瀏覽器不顯示圖片的,尤其是在移動(dòng)設(shè)備上,用戶為了節(jié)省流量,往往會(huì)進(jìn)行那么,如何獲知用戶是否禁止瀏覽圖片呢?
問(wèn)題1:如果在一個(gè)頁(yè)面上插入< img>標(biāo)簽,有哪些屬性是必需的?
答案是src和alt。
實(shí)例:(本實(shí)例摘自W3school: http://www.w3school.com.cn )
< img src=" http://www.w3school.com.cn/i/eg_tulip.jpg" alt="上海鮮花港 - 郁金香" />
src屬性規(guī)定了顯示圖像的URL,瀏覽器會(huì)對(duì)該URL發(fā)起Http Get請(qǐng)求。
alt屬性則規(guī)定了圖像的替代文本,在圖像無(wú)法顯示或者用戶禁用圖像顯示時(shí),代替圖像顯示在瀏覽器中的內(nèi)容。如下圖:

與src屬性相比較,alt屬性更容易被設(shè)計(jì)人員和開發(fā)人員所忽視,事實(shí)上,在筆者撰寫本文時(shí),即使在國(guó)內(nèi)一些大型門戶網(wǎng)站首頁(yè)上(例如新浪、搜狐),我們也可以找到許多沒(méi)有alt屬性的< img>標(biāo)簽。但筆者強(qiáng)烈推薦在文檔的每個(gè)圖像中都使用這個(gè)屬性,這樣即使圖像無(wú)法顯示,用戶還是可以看到的一些相關(guān)信息,從而大大提高了頁(yè)面的用戶友好性。
問(wèn)題2:< img>標(biāo)簽在HTML和XHTML中有什么區(qū)別?
(答案摘自W3school: http://www.w3school.com.cn)
在 HTML 中,< img> 標(biāo)簽沒(méi)有結(jié)束標(biāo)簽。例如:
< img src=" http://www.w3school.com.cn/i/eg_tulip.jpg" alt="上海鮮花港 - 郁金香" >
在 XHTML 中,< img> 標(biāo)簽必須被正確地關(guān)閉。
< img src=" http://www.w3school.com.cn/i/eg_tulip.jpg" alt="上海鮮花港 - 郁金香" />
在 HTML 4.01 中,不推薦使用 image 元素的 "align"、"border"、"hspace" 以及 "vspace" 屬性。在 XHTML 1.0 Strict DTD 中,不支持 image 元素的 "align"、"border"、"hspace" 以及 "vspace" 屬性。
問(wèn)題3:在一個(gè)頁(yè)面上插入< img>標(biāo)簽,為什么說(shuō)最好要使用height和width屬性?
您在瀏覽網(wǎng)頁(yè)的時(shí)候,可能會(huì)遇到這種情況:隨著頁(yè)面中的圖像加載并成功顯示,頁(yè)面上的內(nèi)容會(huì)隨之發(fā)生不規(guī)律的移動(dòng),影響您的閱讀。這種情況就是因?yàn)轫?yè)面上的圖像沒(méi)有定義height和width屬性而導(dǎo)致的。
如果沒(méi)有定義圖片的height和width屬性,那么瀏覽器為了能夠顯示每一個(gè)加載的圖像,它需要先下載圖像,然后解析出圖像的高度和寬度,并在顯示窗口留出相應(yīng)的屏幕空間,這樣就會(huì)導(dǎo)致瀏覽器不斷地重新計(jì)算/調(diào)整頁(yè)面的布局,這可能會(huì)延遲文檔的顯示,并導(dǎo)致頁(yè)面重繪。
因此,筆者建議使用< img>的 height 和 width 屬性來(lái)指定圖像的尺寸。這樣的話,瀏覽器在下載圖像之前就為其預(yù)留出了空間,從而可以加速文檔的顯示,還可以避免文檔內(nèi)容的移動(dòng)而引起頁(yè)面重繪。
但是,需要注意的是:不要通過(guò) height 和 width 屬性來(lái)縮放圖像。如果通過(guò) height 和 width 屬性來(lái)縮小圖像,那么用戶就必須下載大容量的圖像(即使圖像在頁(yè)面上看上去很?。U_的做法是,在網(wǎng)頁(yè)上使用圖像之前,應(yīng)該通過(guò)軟件把圖像處理為合適的尺寸。當(dāng)然,這個(gè)準(zhǔn)則在實(shí)際應(yīng)用中也有例外,例如筆者就認(rèn)為,小比例的圖像縮放應(yīng)該是允許的,此外,如果頁(yè)面上需要加載同一張圖像的不同尺寸的顯示,因?yàn)闉g覽器對(duì)同一個(gè)圖像只會(huì)請(qǐng)求一次,因此此時(shí)就建議使用height 和 width 屬性來(lái)縮放圖像。
問(wèn)題4:< img>標(biāo)簽的onload/onerror/onabort事件,在什么情況下會(huì)被觸發(fā)?
onload: 事件會(huì)在圖像加載完成后立即發(fā)生。
onerror: 事件會(huì)在文檔或圖像加載過(guò)程中發(fā)生錯(cuò)誤時(shí)被觸發(fā)。
onabort: 事件會(huì)在圖像加載被中斷時(shí)發(fā)生。例如用戶單擊了瀏覽器的Stop按鈕,或者在圖像下載的過(guò)程中。
上面的三句話雖然看起來(lái)很簡(jiǎn)單,但實(shí)際上有許多細(xì)節(jié)需要進(jìn)一步的研究,尤其是onload和onerror事件。這些細(xì)節(jié)的問(wèn)題,將在問(wèn)題5中提出。
問(wèn)題5:我們一般知道,當(dāng)一個(gè)圖片請(qǐng)求返回404時(shí),會(huì)觸發(fā)onerror事件,那當(dāng)圖片請(qǐng)求返回302時(shí),會(huì)觸發(fā)onerror事件嗎?304呢?403呢?500呢?請(qǐng)求超時(shí)呢?甚至說(shuō)當(dāng)返回200,但內(nèi)容并非是圖片時(shí),也會(huì)觸發(fā)onerror么?
這些問(wèn)題需要?jiǎng)邮肿鰝€(gè)試驗(yàn)。試驗(yàn)的結(jié)果如下表所示:
| 圖片請(qǐng)求 | 觸發(fā)的事件類型 | IE | FireFox | Chrome |
|---|---|---|---|---|
| 返回404 | onerror | √ | √ | √ |
| 返回302,并且跳轉(zhuǎn)地址為一個(gè)正常的圖片 | onload 所觸發(fā)的事件類型與原始的請(qǐng)求無(wú)關(guān),而是與跳轉(zhuǎn)地址相關(guān)。 | √ | √ | √ |
| 返回304,并且緩存生效 | onload 但也要注意,如果緩存不存在,僅僅是單純地返回304,依然會(huì)觸發(fā)onerror | √ | √ | √ |
| 返回403 | onerror | √ | √ | √ |
| 返回500 | onerror | √ | √ | √ |
| 請(qǐng)求超時(shí) | onerror 返回504 | √ | √ | √ |
| 返回200,但返回的內(nèi)容并非圖片 | onerror | √ | √ | √ |
問(wèn)題6:圖片觸發(fā)onerror事件時(shí),能使用javascript獲取到圖片請(qǐng)求的響應(yīng)代碼么?
很遺憾,目前瀏覽器廠商尚未提供相關(guān)的接口。
問(wèn)題7:我們一般知道,< img>標(biāo)簽可以用來(lái)發(fā)起跨域請(qǐng)求,你能手寫出一段正確使用< img>發(fā)起跨域請(qǐng)求的javascript函數(shù)么?
這個(gè)問(wèn)題看起來(lái)很簡(jiǎn)單,或許你很快的就寫出了以下代碼:
function setImageSrc() {
var i = new Image();
i.src = "http://.../1.gif";
i.onload = function() {
// do sth.
};
i.onerror = function() {
// do sth.
}
i.onabort = function() {
// do sth.
}
}
代碼中新建了一個(gè)image對(duì)象,并綁定了onload, onerror, onabort三個(gè)事件處理函數(shù)。
但實(shí)際上,上述代碼存在幾個(gè)問(wèn)題,你能看出幾個(gè)呢?
屬性src賦值操作應(yīng)該在事件綁定之后:否則,有可能出現(xiàn)圖片已經(jīng)加載完畢、但事件綁定尚未完成的情況。例如,在上述代碼片段中,如果在第三行和第四行之間增加一句alert(1),就能重現(xiàn)這種情況。在IE6中,上述事件綁定代碼會(huì)形成一個(gè)循環(huán)引用——Image對(duì)象的onload屬性引用了一個(gè)匿名函數(shù)對(duì)象,而匿名函數(shù)通過(guò)其作用域鏈引用會(huì)Image對(duì)象,這種循環(huán)引用會(huì)在IE6中導(dǎo)致內(nèi)存泄露。因此,在onload的匿名函數(shù)中,應(yīng)該解除循環(huán)引用,正確的代碼類似于:
i.onload = function() {
// do sth.
i.onload = null;
i = null;
}
在IE6中,如果圖片是多幀的gif,會(huì)觸發(fā)多次的onload事件。因此,為避免這種情況,也需要在onload事件處理函數(shù)中解除事件函數(shù):
i.onload = function() {
// do sth.
i.onload = null;
i = null;
}
問(wèn)題8:用戶是可以設(shè)置瀏覽器不顯示圖片的,尤其是在移動(dòng)設(shè)備上,用戶為了節(jié)省流量,往往會(huì)禁止圖片顯示。那么,如何獲知用戶是否禁止瀏覽圖片呢?
注:該問(wèn)題的解決方案來(lái)源于 http://stackoverflow.com/questions/8379156/how-to-detect-if-images-are-disabled-in-browser,筆者對(duì)其中的原理和代碼bug做了相應(yīng)的解讀和修復(fù)。
在Firefox和Chrome中,可以使用Image對(duì)象的complete屬性來(lái)解決此問(wèn)題:設(shè)置Image對(duì)象的src屬性,以請(qǐng)求一個(gè)不存在的圖片,當(dāng)瀏覽器禁止顯示圖片時(shí),Image對(duì)象的complete屬性為true,否則為false。
在Opera中,也可以使用Image對(duì)象的complete屬性,但它與Firefox和Chrome的不同,設(shè)置Image的src后,在onload之前,它一直顯示為false。但我們可以將圖片的src設(shè)置為一個(gè)特殊的值:img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; 這樣,當(dāng)Opera禁止顯示圖片時(shí),Image的complete屬性為false,否則為true。
而在IE中,Image的complete屬性會(huì)一直為false。因此,但我們注意到,當(dāng)IE禁止顯示圖片時(shí),是不會(huì)觸發(fā)Image對(duì)象的onload/onerror/onabort事件的。針對(duì)該特性,我們使用setTimeout函數(shù),當(dāng)在一定的時(shí)間內(nèi)沒(méi)有檢測(cè)onload/onerror/onabort事件的發(fā)生,則認(rèn)為瀏覽器禁止顯示圖片。
參考文章:http://www.cnblogs.com/hencehong/archive/2012/10/06/something_interesting_about_image.html
————
前端·小h
紙上得來(lái)終覺淺,絕知此事要躬行