? ? ? 話說自從在某些地方用了display:inline-block取代float之后油猫,問題出來了一次又一次岛请,歸根結底還是那個“傳說”中的空白符問題剩辟,追究其原因,度娘竟然告訴我說它是歷史遺留問題桩引,就是西文的排版問題。好吧收夸,既然度娘就這么說了坑匠,那該怎么解決呢?我總不能向科幻電影中那樣坐著時光機或者通過蟲洞穿越到那個西文剛出來的年代卧惜,然后義憤填膺的告訴他們厘灼,你們的西文不能這個排版,不然咽瓷,千年之后會對你們的子孫后代造成很大的麻煩的设凹!不過。牢騷歸牢騷茅姜,問題還是得解決的闪朱,不然,boss就會指著你的腦袋告訴你匈睁,這點問題都不能解決监透,我要你何用,卷鋪蓋滾蛋吧航唆!然后你就抱著鋪蓋胀蛮,喝著西北風,大罵創(chuàng)造西文的那些人糯钙,恨不得將他們掘墓鞭尸(尸體估計都歸于塵土了)粪狼!好吧我承認,這些都是我臆想出來的任岸。第一次在這里寫東西記錄自己所學再榄,就不說廢話了。
? ? ? 度娘告訴俺造成間隙你的原因有兩種:一是空白字符享潜;二是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丢胚,對于子元素你仍然可以重置為想要的字體;這樣無論外部環(huán)境如何變化酬姆,這個間隙將始終是3px嗜桌。使用屬性級hack設置字體大小12px [;font-size:12px;] ,因為IE7及以下瀏覽器也能識別該hack,所以用*font-size:0重置一次辞色;因為word-spacing對chrome和Safari的間隙調整均無效果骨宠,可以使用letter-spacing:normal替代浮定,現在所有的主流瀏覽器應該都可以使用了。但是层亿,如果覺得這樣的樣式設置還是比較麻煩的話桦卒,就要去尋找更好的解決方案了。
? ? ? 在解決這個問題的道路上匿又,我無意間查看了頁面的源代碼方灾,發(fā)現一個問題,我覺得這個問題就是我解決留白問題的關鍵所在碌更。那這個問題是什么呢裕偿?直接看圖吧。
好吧痛单,圖太大了嘿棘,就這樣吧,就不處理了旭绒,重點不是圖的大小鸟妙,而是圖展示的內容。同樣是兩個網站的源代碼挥吵,第一個網站的源代碼是一行顯示重父,第二個網站的源代碼就分行顯示的。對于剛剛發(fā)現這個問題的我并不知道一行顯示的是被壓縮了忽匈,當時我知道壓縮代碼這個事情房午,但是愚蠢的我并沒有往那個方面想。當時我覺得是瀏覽器渲染代碼的問題脉幢,就拼命的去找尋答案歪沃,去了解瀏覽器渲染代碼的機制。既然我就那么費盡心思的去了解渲染的機制了嫌松,那就說說吧沪曙,也不枉我一番心血。
? ? ? ? 經大師指點 + 各種網站萎羔,終于有了自己的思路: 盜用一下別人的圖
主線是四個步驟液走,就是上圖四個黃色的色塊。第一步贾陷,瀏覽器解析三個東西缘眶,一是:HTML/XHTML/SVG,這三個文件分別對應Webkit內核中C++的三個類髓废,會將它們解析成一個DOM Tree(Webkit的命名)/Content Tree(Gecko的嗎巷懈,命名);二是CSS慌洪,瀏覽器會將它解析成CSS Rule Tree(CSS規(guī)則樹)顶燕;三是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 節(jié)點 或者Frame 鸵膏。第三步租副,計算每個Element(frame/dom 節(jié)點)的位置,這個過程叫l(wèi)ayout 或者reflow 较性。第四步,就是調用操作系統的Native GUI 的API進行繪制结胀,頁面也就出來了赞咙。
? ? ? ?剛剛我們說過,Rendering Tree 和DOM Tree是不一樣的糟港,現在我們來說說它們之間的區(qū)別:1攀操、Rendering Tree 使用來顯示的,就相當于“MVC模式”中的'V",既然是用來顯示的秸抚,那么一些不會被現實在頁面上的東西當然就不會出現在Rendering Tree中速和,比如head ,display:none等等剥汤,這就造成了有些DOM沒有Rendering來對應颠放,有些又有多個Rendering對應,比如select 吭敢,一種rendering不能夠準確的描述它等等碰凶。2、Rendering和DOM的位置可能不一樣鹿驼,比如那些添加了float 或者position:absolute的元素欲低,在Rendering中顯示的就是經過計算定位后的實際位置。3畜晰、DOM 的根節(jié)點是document 砾莱,而Rendering的根節(jié)點是RenderView(Webkit命名)或者viewPortframe(Gecko命名)
? ? ? ? 到這里,瀏覽器的渲染機制基本上算是介紹清楚了凄鼻,接下來我們言歸正傳腊瑟,繼續(xù)介紹我的尋找答案之旅聚假。說到這里,我基本上鉆進了牛角尖里扫步,一頭猛的扎進瀏覽器的渲染機制里魔策,甚至還打算繼續(xù)尋找,為什么瀏覽器沒有過濾掉結束標簽后的那個換行\(zhòng)n 我百思不得其解河胎,當然闯袒,這種情況下,度娘也沒有什么能夠告訴我的了游岳。就像朱棣在要進軍應天一直以為都要打開山東的大門政敢,但是在當時朱棣的軍力根本不足以攻打山東,并且當時山東還有鐵鉉和盛庸在鎮(zhèn)守胚迫,在這關鍵時刻喷户,攪亂時局的道衍的一句話點醒了朱棣“去應天不一定要過山東”。雖然我不能跟朱棣相提并論访锻,但是也有這么一個人的一句話將我從死胡同里拽了出來褪尝,當然,他也不是當時攪動風云的道衍期犬,他的那句“不是瀏覽器渲染機制的問題”你僅僅是徹底否定了我之前的思路河哑,還將我又打回了原形,一切好像又要從頭開始了龟虎。我又年開始迷茫了璃谨,這是什么問題呢,我又仔細的研究了一下鲤妥,回想這個過程佳吞,查看之前看過的資料,終于我發(fā)現了一個我以為的關鍵棉安,當然底扳,事實證明那就是關鍵。就是node_before 和node_after 函數垂券,
/*** 此為會跳過空白符節(jié)點及注釋節(jié)點的 |previousSibling| 函數
* ( |previousSibling| 是 DOM 節(jié)點的特性值花盐,為該節(jié)點的前一個節(jié)點。)
** @參數? sib? 節(jié)點菇爪。
* @傳回值? ? ? 有兩種可能:
*? ? ? ? ? ? ? 1) |sib| 的前一個“非空白算芯、非注釋”節(jié)點(由 |is_ignorable| 測知。)
*? ? ? ? ? ? ? 2) 若該節(jié)點前無任何此類節(jié)點凳宙,則傳回 null熙揍。
*/
function node_before( sib )
{while ((sib = sib.previousSibling)) {
if (!is_ignorable(sib)) return sib;
}
return null;
}
/**
* 此為會跳過空白符節(jié)點及注釋節(jié)點的 |nextSibling| 函數
* @參數? sib? 節(jié)點。
* @傳回值? ? ? 有兩種可能:
*? ? ? ? ? ? ? 1) |sib| 的下一個“非空白氏涩、非注釋”節(jié)點届囚。
*? ? ? ? ? ? ? 2) 若該節(jié)點后無任何此類節(jié)點有梆,則傳回 null。
*/
function node_after( sib )
{
while ((sib = sib.nextSibling)) {
if (!is_ignorable(sib)) return sib;
}
return null;
}
由這兩個函數意系,在我代碼中我找到了UglifyJS泥耀,度娘告訴我他是壓縮的工具,我當時才恍然大悟蛔添,原來我費了那么大力氣痰催,就兩個字就解決了,那就是壓縮迎瞧,當然夸溶,UglifyJS 的出現當然不是為了解決display:inline-block的留白問題,只是在壓縮這種情況下凶硅,留白不會存在而已缝裁,這種解決辦法的原理還是第一種,將代碼壓縮在一行足绅。其實我現在是又氣憤又高興捷绑,氣憤的是自己明明知道代碼壓縮了會變成一行,但當時為什么就沒有想起來呢氢妈。高興的是胎食,幸虧自己沒有想起來,才會大費周章的去了解瀏覽器的渲染機制允懂,也算是大有收獲吧。
至于UglifyJS衩匣,現在我就不多說了蕾总,因為我也沒有搞清楚,等我搞清楚了再記錄一下吧琅捏、I佟!