? ? ? 話說自從在某些地方用了display:inline-block取代float之后,問題出來了一次又一次,歸根結底還是那個“傳說”中的空白符問題,追究其原因,度娘竟然告訴我說它是歷史遺留問題,就是西文的排版問題。好吧,既然度娘就這么說了,那該怎么解決呢?我總不能向科幻電影中那樣坐著時光機或者通過蟲洞穿越到那個西文剛出來的年代,然后義憤填膺的告訴他們,你們的西文不能這個排版,不然,千年之后會對你們的子孫后代造成很大的麻煩的!不過。牢騷歸牢騷,問題還是得解決的,不然,boss就會指著你的腦袋告訴你,這點問題都不能解決,我要你何用,卷鋪蓋滾蛋吧!然后你就抱著鋪蓋,喝著西北風,大罵創造西文的那些人,恨不得將他們掘墓鞭尸(尸體估計都歸于塵土了)!好吧我承認,這些都是我臆想出來的。第一次在這里寫東西記錄自己所學,就不說廢話了。
? ? ? 度娘告訴俺造成間隙你的原因有兩種:一是空白字符;二是font-size。那空白字符到底是什么呢?原來代碼中的一些tab、回車、空格、換行這些都是,這些在瀏覽器渲染頁面的時候都會被轉換成“\n”。至于font-size為什么會導致間隙,原因很簡單,既然是字符,當然不會擺脫font的控制。換行符導致的問題可以將代碼寫成一行就可以解決了,如果寫成一行代碼的可讀性就會明顯降低,就要著手從font-size上做文章。方案一:給父元素設置font-size:0,此方案存在問題,font-size還要被重寫一次,較老版本的瀏覽器兼容性不好,向IE7以下依然會留下1px的間隙,較老版本的webkit對于小于12px的font-size設置不友好,chrome還可以設置-webkit-text-size-adjust:none用以支持較小的字體,Safari即使設置了也不能搞定,但是,ie8及以上瀏覽器,FireFox,Opea,Safari6,Chrome18均可使用;方案二:font-size + 負margin,但是,至于這個負margin的值到底是多少像素,不同的瀏覽器不一樣,不同的字體也不一樣,所以不建議此方案。方案三:font-size + word-spacing:normal,font-family指定字體不同,間隙也會隨之而變;同時為了避免受到上下文font設置影響,在局部我們將之設置為12px的arial,為什么選擇arial?主要是為了兼容盡可能多的平臺,通常windows和Mac OS都會有arial字體,選擇Arial字體后間隙將變成3px,對于子元素你仍然可以重置為想要的字體;這樣無論外部環境如何變化,這個間隙將始終是3px。使用屬性級hack設置字體大小12px [;font-size:12px;] ,因為IE7及以下瀏覽器也能識別該hack,所以用*font-size:0重置一次;因為word-spacing對chrome和Safari的間隙調整均無效果,可以使用letter-spacing:normal替代,現在所有的主流瀏覽器應該都可以使用了。但是,如果覺得這樣的樣式設置還是比較麻煩的話,就要去尋找更好的解決方案了。
? ? ? 在解決這個問題的道路上,我無意間查看了頁面的源代碼,發現一個問題,我覺得這個問題就是我解決留白問題的關鍵所在。那這個問題是什么呢?直接看圖吧。
好吧,圖太大了,就這樣吧,就不處理了,重點不是圖的大小,而是圖展示的內容。同樣是兩個網站的源代碼,第一個網站的源代碼是一行顯示,第二個網站的源代碼就分行顯示的。對于剛剛發現這個問題的我并不知道一行顯示的是被壓縮了,當時我知道壓縮代碼這個事情,但是愚蠢的我并沒有往那個方面想。當時我覺得是瀏覽器渲染代碼的問題,就拼命的去找尋答案,去了解瀏覽器渲染代碼的機制。既然我就那么費盡心思的去了解渲染的機制了,那就說說吧,也不枉我一番心血。
? ? ? ? 經大師指點 + 各種網站,終于有了自己的思路: 盜用一下別人的圖
主線是四個步驟,就是上圖四個黃色的色塊。第一步,瀏覽器解析三個東西,一是:HTML/XHTML/SVG,這三個文件分別對應Webkit內核中C++的三個類,會將它們解析成一個DOM Tree(Webkit的命名)/Content Tree(Gecko的嗎,命名);二是CSS,瀏覽器會將它解析成CSS Rule Tree(CSS規則樹);三是Javascript腳本,主要是通過DOM Tree開放的DOM API 和CSS Rule Tree 開放的CSSOM API 來操作DOM Tree 和CSS Rule Tree 。第二步,解析完成后,瀏覽器引擎會通過DOM Tree 和CSS Rule Tree生成Rendering Tree(渲染樹Webkit的命名)/Frame Tree (Gecko的命名),當然,這個Render Tree和DOM Tree 是不一樣的,至于哪里不一樣,為什么不一樣會在下面寫到,這里先不多說了。CSS Rule Tree 主要是為了完成匹配把CSS Rule 附加到Rendering Tree 的每一個Element 上,也就是DOM 節點 或者Frame 。第三步,計算每個Element(frame/dom 節點)的位置,這個過程叫layout 或者reflow 。第四步,就是調用操作系統的Native GUI 的API進行繪制,頁面也就出來了。
? ? ? ?剛剛我們說過,Rendering Tree 和DOM Tree是不一樣的,現在我們來說說它們之間的區別:1、Rendering Tree 使用來顯示的,就相當于“MVC模式”中的'V",既然是用來顯示的,那么一些不會被現實在頁面上的東西當然就不會出現在Rendering Tree中,比如head ,display:none等等,這就造成了有些DOM沒有Rendering來對應,有些又有多個Rendering對應,比如select ,一種rendering不能夠準確的描述它等等。2、Rendering和DOM的位置可能不一樣,比如那些添加了float 或者position:absolute的元素,在Rendering中顯示的就是經過計算定位后的實際位置。3、DOM 的根節點是document ,而Rendering的根節點是RenderView(Webkit命名)或者viewPortframe(Gecko命名)
? ? ? ? 到這里,瀏覽器的渲染機制基本上算是介紹清楚了,接下來我們言歸正傳,繼續介紹我的尋找答案之旅。說到這里,我基本上鉆進了牛角尖里,一頭猛的扎進瀏覽器的渲染機制里,甚至還打算繼續尋找,為什么瀏覽器沒有過濾掉結束標簽后的那個換行\n 我百思不得其解,當然,這種情況下,度娘也沒有什么能夠告訴我的了。就像朱棣在要進軍應天一直以為都要打開山東的大門,但是在當時朱棣的軍力根本不足以攻打山東,并且當時山東還有鐵鉉和盛庸在鎮守,在這關鍵時刻,攪亂時局的道衍的一句話點醒了朱棣“去應天不一定要過山東”。雖然我不能跟朱棣相提并論,但是也有這么一個人的一句話將我從死胡同里拽了出來,當然,他也不是當時攪動風云的道衍,他的那句“不是瀏覽器渲染機制的問題”你僅僅是徹底否定了我之前的思路,還將我又打回了原形,一切好像又要從頭開始了。我又年開始迷茫了,這是什么問題呢,我又仔細的研究了一下,回想這個過程,查看之前看過的資料,終于我發現了一個我以為的關鍵,當然,事實證明那就是關鍵。就是node_before 和node_after 函數,
/*** 此為會跳過空白符節點及注釋節點的 |previousSibling| 函數
* ( |previousSibling| 是 DOM 節點的特性值,為該節點的前一個節點。)
** @參數? sib? 節點。
* @傳回值? ? ? 有兩種可能:
*? ? ? ? ? ? ? 1) |sib| 的前一個“非空白、非注釋”節點(由 |is_ignorable| 測知。)
*? ? ? ? ? ? ? 2) 若該節點前無任何此類節點,則傳回 null。
*/
function node_before( sib )
{while ((sib = sib.previousSibling)) {
if (!is_ignorable(sib)) return sib;
}
return null;
}
/**
* 此為會跳過空白符節點及注釋節點的 |nextSibling| 函數
* @參數? sib? 節點。
* @傳回值? ? ? 有兩種可能:
*? ? ? ? ? ? ? 1) |sib| 的下一個“非空白、非注釋”節點。
*? ? ? ? ? ? ? 2) 若該節點后無任何此類節點,則傳回 null。
*/
function node_after( sib )
{
while ((sib = sib.nextSibling)) {
if (!is_ignorable(sib)) return sib;
}
return null;
}
由這兩個函數,在我代碼中我找到了UglifyJS,度娘告訴我他是壓縮的工具,我當時才恍然大悟,原來我費了那么大力氣,就兩個字就解決了,那就是壓縮,當然,UglifyJS 的出現當然不是為了解決display:inline-block的留白問題,只是在壓縮這種情況下,留白不會存在而已,這種解決辦法的原理還是第一種,將代碼壓縮在一行。其實我現在是又氣憤又高興,氣憤的是自己明明知道代碼壓縮了會變成一行,但當時為什么就沒有想起來呢。高興的是,幸虧自己沒有想起來,才會大費周章的去了解瀏覽器的渲染機制,也算是大有收獲吧。
至于UglifyJS,現在我就不多說了,因為我也沒有搞清楚,等我搞清楚了再記錄一下吧、!!