HTML 中的“空白符”包括空格 (space)、制表符 (tab)、換行符 (CR/LF) 三種。
我們知道,在默認(rèn)情況下,HTML 源碼中的空白符均被顯示為空格,并且連續(xù)的多個(gè)空白符會(huì)被視為一個(gè),或者說,連續(xù)的多個(gè)空白符會(huì)被合并。
然而在有些時(shí)候,我們希望 HTML 源碼中的多個(gè)連續(xù)空格在網(wǎng)頁瀏覽器中可以真實(shí)地呈現(xiàn),或者需要源碼中的換行符能起到真正的換行作用。于是,我們發(fā)現(xiàn)了 <pre>
標(biāo)簽,它可以真實(shí)還原它內(nèi)部文本的空白符的真實(shí)情況。
于是我們經(jīng)常會(huì)把一段表示計(jì)算機(jī)代碼的文本放進(jìn) <pre>
標(biāo)簽中,它們?cè)跒g覽器中會(huì)表現(xiàn)出自身的空格縮進(jìn)和換行效果,而不需要我們?cè)黾宇~外的樣式和標(biāo)簽來控制它的縮進(jìn)和換行。
隨著對(duì) CSS 的了解不斷深入,我們發(fā)現(xiàn),原來這一切都是 white-space
屬性在安排。<pre>
元素之所以如此神奇,是因?yàn)樗陨砭哂?{white-space: pre;}
這一默認(rèn)樣式。
CSS 中的 white-space
屬性用于設(shè)置文本空白符的處理規(guī)則,這其中包括:是否合并空白符、是否保留換行符、是否允許自動(dòng)換行。各屬性值的不同行為如下表所示:
屬性值 | 空白符 | 換行符 | 自動(dòng)換行 | 最早出現(xiàn)于 |
---|---|---|---|---|
normal | 合并 | 忽略 | 允許 | CSS 1 |
nowrap | 合并 | 忽略 | 不允許 | CSS 1 |
pre | 保留 | 保留 | 不允許 | CSS 1 |
pre-wrap | 保留 | 保留 | 允許 | CSS 2.1 |
pre-line | 合并 | 保留 | 允許 | CSS 2.1 |
(注:在 CSS1/2 下,white-space
屬性只可應(yīng)用于塊級(jí)元素;在 CSS 2.1 下,可應(yīng)用于所有元素。)
如果我們需要某個(gè)容器元素具有類似 <pre>
元素的空白符處理行為,則為它設(shè)置 {white-space: pre;}
樣式即可。
我們先解釋一下上述表格中的“自動(dòng)換行”行為,它是指某元素內(nèi)部的文本流按照文本方向排版,當(dāng)文本流遇到限制其繼續(xù)延伸的邊界時(shí),是否換行。“不允許自動(dòng)換行”則意味著文本流會(huì)溢出該元素。
因此,{white-space: pre;}
樣式有時(shí)候并不能滿足我們的期望。比如,在某些不需要特別嚴(yán)謹(jǐn)?shù)膱?chǎng)合,或者排版某些對(duì)換行不敏感的代碼片斷(比如 HTML 或CSS)的時(shí)候,我們不希望代碼片段中的一行長(zhǎng)代碼令它的容器元素產(chǎn)生水平滾動(dòng)條,因?yàn)槟菢硬槐汩喿x。我們希望在這種情況下,長(zhǎng)代碼自動(dòng)換行就好。
這時(shí),對(duì)照一下上表中各屬性值的不同行為特征,我們會(huì)發(fā)現(xiàn) pre-wrap
這個(gè)屬性值脫穎而出——它正是我們所需要的。
再來看另一種實(shí)戰(zhàn)中可能會(huì)遇到的情形。
表單中的文本域(<textarea>
元素)可以接受包含換行符的文本數(shù)據(jù),這是它有別于文本框(text
類型的 <input>
元素)的重要特征之一,所以我們通常也稱它為“多行文本框”。
隨之而來的一個(gè)問題就是,我們通過多行文本框提交多行文本數(shù)據(jù),是為了在網(wǎng)頁上最終顯示出多行文本。但由于瀏覽器對(duì) HTML源代碼默認(rèn)進(jìn)行空白符合并處理,為了確保我們提交的多行文本數(shù)據(jù)最終在網(wǎng)頁上正確地呈現(xiàn)出多行的形態(tài),通常需要在服務(wù)器端做處理,比如將文本中的換行符轉(zhuǎn)換為 HTML 的換行標(biāo)簽 <br>
,再寫入數(shù)據(jù)庫;或者從數(shù)據(jù)庫中讀出文本數(shù)據(jù)時(shí)進(jìn)行類似的轉(zhuǎn)換操作。
這樣當(dāng)服務(wù)器向網(wǎng)頁輸出這些文本數(shù)據(jù)時(shí),原始的回車狀態(tài)才能得到再現(xiàn)。
但是,由于設(shè)計(jì)失誤(或系統(tǒng)有意限制),服務(wù)器端可能就不會(huì)做這樣的處理。從而導(dǎo)致這些文本信息中的換行符無法呈現(xiàn)出換行效果,取而代之的是一個(gè)小空格。
(下圖為 cnBeta 網(wǎng)站對(duì)評(píng)論文本的兩種不同處理方式:左側(cè)為普通評(píng)論,可能為了限制各條評(píng)論的高度、防止惡意刷屏,系統(tǒng)未做換行符轉(zhuǎn)換處理;右側(cè)為熱門評(píng)論,系統(tǒng)進(jìn)行了處理。)
如果服務(wù)器端因?yàn)槭韬鰶]有做換行符轉(zhuǎn)換處理,那么在前端是否可以用最小的代價(jià)來補(bǔ)救?這時(shí),pre-wrap
就可以發(fā)揮作用——無需做任何的額外處理,直接為文本的容器元素設(shè)置 {white-space: pre-wrap;}
樣式,就可以還原多行文本的真實(shí)狀態(tài)。
再來看一下上面的表格,我們發(fā)現(xiàn) pre-wrap
是從 CSS 2.1 才開始引入的屬性值。然而,目前網(wǎng)民使用最為廣泛的 IE6 和 IE7 瀏覽器都是基于 CSS1 和部分 CSS2 的,它們完全不能識(shí)別 pre-wrap
,當(dāng)然也無法實(shí)現(xiàn) pre-wrap
的空白符處理行為。
在瘋狂地問候了微軟、IE 及其相關(guān)人等之后,網(wǎng)頁開發(fā)者們還是不得不面對(duì)這個(gè)問題——如何在 IE6,7 下實(shí)現(xiàn) pre-wrap
的效果?
經(jīng)常反復(fù)測(cè)試,我們找到了在 IE6,7 下變通實(shí)現(xiàn) pre-wrap
效果的方法。
比如,有如下 HTML 結(jié)構(gòu):
<div class="content">這是一段多行文本數(shù)據(jù)
其中某些文本行會(huì)非常長(zhǎng)從而溢出容器比如你現(xiàn)在看到的這行
行與行之間有換行符
但沒有使用 HTML 換行標(biāo)簽</div>
我們需要將 .content
元素設(shè)置為 pre-wrap
樣式,理想情況下只需要編寫如下 CSS 代碼就可以了。
.content {
white-space: pre-wrap;
}
但為了應(yīng)付 IE6,7,我們需要將上述 CSS 代碼修改如下:
.content {
white-space: pre-wrap;
*white-space: pre;
*word-wrap: break-word;
}
這樣就可以了,我們?cè)诟鳛g覽器中實(shí)測(cè)一下,可以發(fā)現(xiàn)我們需要的效果完美實(shí)現(xiàn)。
當(dāng)然,你可能注意到了,我們使用了一點(diǎn)兒 CSS hack。別擔(dān)心,它們條理清晰并且容易維護(hù),我覺得這可以接受。在面對(duì)低能瀏覽器的時(shí)候,我們只能給予它們一些額外關(guān)照。
如果你是一個(gè)實(shí)用主義者,那么文章到這里已經(jīng)結(jié)束了。你可以把代碼存下然后走人,或者繼續(xù)瀏覽 CSS魔法 的其它文章。如果你是一個(gè)充滿好奇心的 CSS 學(xué)習(xí)者,那么我很樂意與你一起來分析一下它的實(shí)現(xiàn)原理。
在上面的最終版 CSS 代碼中,很顯然對(duì)于標(biāo)準(zhǔn)瀏覽器,我們是用正常的 {white-space: pre-wrap;}
來實(shí)現(xiàn)所需效果的。而對(duì)于 IE6,7,我們使用了 CSS hack,讓它接受額外的樣式聲明,使用其它方法來實(shí)現(xiàn)類似 pre-wrap
的效果。
首先,在 IE6,7 下,{white-space: pre-wrap;}
這條樣式聲明由于不能識(shí)別而被丟棄,于是我們?yōu)?.content
另外設(shè)置了 {white-space: pre;}
的樣式。我們已經(jīng)很熟悉 pre
了,它的特性與我們想要的 pre-wrap
效果只有一點(diǎn)區(qū)別,即 pre
不允許自動(dòng)換行,也就是說,較長(zhǎng)的文本行可能會(huì)溢出其容器元素。
因此,接下來,為了讓這些較長(zhǎng)的文本行自動(dòng)換行,我們?yōu)?.content
元素設(shè)置 {word-wrap: break-word;}
樣式(謹(jǐn)慎起見,我們用 CSS hack 將這條聲明隔離給 IE6,7;不過即使將它暴露給所有瀏覽器,它也是無害的)。這條聲明負(fù)責(zé)對(duì) .content
元素內(nèi)的文本行進(jìn)行約束,并強(qiáng)制其換行。也就是說,{white-space: pre;}
完成了識(shí)別文本換行符的任務(wù),剩下的自動(dòng)換行的任務(wù)交由 {word-wrap: break-word;}
來完成。
插播 word-wrap 的相關(guān)資料
CSS 發(fā)展至今經(jīng)歷了多個(gè)版本,但它對(duì)文本排版的控制仍然不夠精確和靈活。于是微軟的 IE 瀏覽器開發(fā)了一些私有屬性,擴(kuò)展了 CSS的文本排版功能,尤其可貴的是,這些擴(kuò)展屬性大多考慮到了非拉丁語系語言的排版規(guī)則。由于這些私有擴(kuò)展屬性確實(shí)很有價(jià)值,它們被整理并收錄到了 CSS3草案中。
word-wrap
屬性就是其中很有代表性的例子。它決定了文本行超過容器的邊界時(shí)是否斷開轉(zhuǎn)行。目前這一屬性已經(jīng)得到了絕大多數(shù)主流瀏覽器的支持。
回到前面的原理分析,其實(shí)我們會(huì)發(fā)現(xiàn)一個(gè)矛盾,{white-space: pre;}
很倔犟地不愿換行,而 {word-wrap: break-word;}
則要求內(nèi)部文本自動(dòng)換行。面對(duì)這樣的沖突,瀏覽器如何決斷?
在 CSS 中,控制文本換行方式的屬性有很多,當(dāng)發(fā)生沖突的時(shí)候,某些屬性在文本排版中的優(yōu)先級(jí)更高,因而會(huì)在沖突中勝出,決定最終的文本樣式。很顯然,在上面的這起沖突中,{word-wrap: break-word;}
更加強(qiáng)勢(shì),倔犟的文本行最終還是乖乖地?fù)Q行了。
感謝你看到了這里,希望這篇文章對(duì)你有所幫助!
聯(lián)系客服