手動調整 Responsive 中日文斷行的實驗

前幾天,敝社的產品 Logdown 上了新翻譯完成的日文 Landing 首頁。這版 Landing 頁,我有做 Responsive Web Design1,讓網頁能稍微有點彈性地適應各種瀏覽寬度、而不至於看起來活像是壞掉。不過在日文的大標題填上去之後,稍微遇到了一個問題──他實際上佔的長度蠻寬的,比一開始的英文大標還要寬──而這讓他在小螢幕上面會產生斷行。

當然我可以透過 Media Query 的方法,確保他的字體在每個寬度都縮小到不致於斷到下一行,不過字體太小的標題顯然很難看起來像是「大標題」。試著實際拉了一下瀏覽器視窗,覺得還是讓他保留一定的字體大小而斷行比較好。不過在這邊引發我的興趣:要怎麼斷行,可以讓他盡量斷在「詞」的邊緣,而不是斷在「詞」的中間?

中日文的斷行規則

根據 W3C 的 CSS Text Module Level 3 文件來看,在網頁中斷行的規則通常是:斷在一個「軟性斷行機會點」(Soft Wrap Opportunity)。各式標點符號通常都是一個斷行機會點、空白也是。這對英文來說很方便,因為英文中每個單字都會以空白隔開。無論是斷在空白或是標點,都不影響一個單字被完整呈現。但是對於中文跟日文來說,根據 word-break Example 6 這邊所示範的,每個字都是斷行機會點。(雖然範例中其實只放了漢字。)

當然,這跟我們的語言特性並沒有差很多。中文跟日文因為是方塊字,其實在哪裡被斷行都不太影響我們的閱讀。特別是中文,我們從小寫作文的時候,就是在作文稿紙上逐字逐格地填入。只要遇到一行的最尾端,就直接從下一行的開頭接著寫。

即便我
今天這
樣斷行

也不至於對閱讀造成太大影響。

在「標題」上的斷行期望

不過用在標題地方的文字,基於某種一時說不出來的理由(也許是為了美觀、也許是為了「看起來」完整),我希望他斷行的時候可以斷在一組詞的邊緣、而不要從詞的中間斷掉。意思是,如果標題裡面有「姐姐」兩個字的話,我希望他不要從中間斷成


這樣兩截。

為了做點實驗,我做了一個測試用的網頁,裡面用 AKB48 最新單曲的中文曲名來示範斷詞;而這也據信是目前史上最長的歌曲名稱:《倘若在梧桐樹的路上對你說「我夢見了你的微笑」之後我們的關係會有什麼樣的變化呢﹑我兀自持續想了好多天最後有點難為情地得到了一個結論》2

在上圖中,自動斷行的結果破壞了三組詞、讓他們斷成兩行。我用顏色把他們標起來,分別是「你的」、「變化」跟「難為情(地)」。

可能的方法

為了能夠手動控制斷行點,讓他能盡量斷在詞組的邊緣,我初步想了三個方法來嘗試:

  1. word-break: keep-all; 阻止在連續的中日文間斷行
  2. span 把不應該被斷行的詞組包起來,做成 inline-block
  3. span 把不應該被斷行的詞組包起來,做成 white-space: nowrap

實驗一: word-break 方法

基於在上面所提過的 Example 6,如果我們把中文標題設定為 word-break: keep-all,看起來就能禁止瀏覽器把連續的中日文斷行斷開。在這個情況下,會讓中日文的斷行表現比較接近英文:只有在空格、標點、或是遇到其他 Unicode 上的可斷行字元時,才會產生斷行。

你可以使用 Unicode 的 U+200B ZERO WIDTH SPACE 這個特殊字元,來製造看不到間距、但可以作為斷行機會點的空白;在 HTML5 中,則可以用 <wbr> 標籤來達到同樣的效果。

所以實際的作法上會變成這樣:把整個想要手動斷行的標題,用 CSS 設定為 word-break: keep-all,然後在 HTML 中手動用 <wbr> 來標示出可以安全斷行的地方。效果其實相當好,可以從下圖看到他確實只會從給定的 <wbr> 處做斷行。

Style
h2 {
  word-break: keep-all;
}

不過缺點也很明顯:你的 HTML 裡面會佈滿 <wbr> 標籤。光用看的就覺得頭有點痛、嗯好像還稍微有點蠢。

然後目前最大的技術障礙,是 word-breakkeep-all 屬性本身。根據這份支援度表格,截至目前為止只有兩套瀏覽器支援:一是 Firefox、二是⋯⋯ IE!! 而且是從 IE8 就開始支援了。

實驗二: inline-block 方法

第二個想法,是把絕對不想被斷開的詞組,用 <span> 包起來,然後讓裡面盡量不被斷行。先嘗試的是 inline-block 方法,因為如果一個詞組被 inline-block 起來的話,要斷行就會以這個 inline-block 物件的前後邊緣優先斷行,可以達到盡量保護 <span> 內詞組的效果。

作法蠻簡單的,反正就是需要把詞用額外的標籤包起來而已。效果也很不錯,瀏覽器很順利的在寬度不夠的時候,從 inline-block 的前面優先斷行,順利的達到了期望的效果。

Style
span {
  display: inline-block;
}
Markup
<h2>
倘若在梧桐樹的路上對你說「我夢見了<span>你的</span>微笑」之後我們的關係
會有什麼樣的<span>變化</span>呢﹑我兀自持續想了好多天最後有點
<span>難為情地</span>得到了一個結論
</h2>

實驗三: white-space nowrap 方法

這個方法跟實驗二基本上一樣,只是把拿來包住詞組的 <span> 從指定為 inline-block、改為指定 white-space: nowrap 來禁止他換行而已。效果也差不多,唯一的差別在於,似乎整個被 nowrap 包住的部分,是連前後都不允許斷行的。所以從下面的 screenshot 中可以看到,斷行不會直接斷在被包住的前面、而是會再提早一個字做斷行。

Style
span {
  white-space: nowrap;
}

實驗四: 當文字過長時,inline-block 與 nowrap 方法的結果比較

基於好奇,我額外做了一個實驗,看看上述的兩個方法有什麼其他差異。由於 nowrap 法很明顯會造成裡面的文字完全無法換行,所以我就用兩個方法各包了一段一定會超出容器寬度的文字,觀察兩個方法帶來的結果。

左邊是 inline-block 方法的結果。因為 inline-block 本身並沒有禁止斷行,所以過長的文字就直接在包住的 <span> 裡面斷行了,可以看得到完整的文字。右邊則是 nowrap 方法的結果。禁止斷行的下場,就是文字超出了 <span> 容器的寬度、而 <span> 本身又超出標題的容器寬度,所以有部分文字就落到可視範圍以外,看不到了。

結論

綜合上面四個實驗的結果,我的結論是:如果需要針對中日文的文字去手動調整斷行,使用 <span> 把不想被切斷的詞組包成 inline-block,是目前比較好的方法。

方法 缺點
word-break 法 Markup 裡面會充斥 <wbr>keep-all 屬性支援度低
inline-block 法 需要額外 Markup
nowrap 法 需要額外 Markup、內容過長會超出容器看不到

CSS Text Module Level 3 裡面,並沒有明確規範瀏覽器要怎麼處理中日韓文字的斷行問題。中日文的電腦自動切詞,本身就是難事、更何況以中文來說,一個詞因為換行被切斷也不是真的太大不了的事情。可以想像,在近期內大概都不會有瀏覽器想來處理依詞斷行的問題。

本文實驗的三種方法,無論哪一種,都需要額外的 Markup。所以如果真的要用,可能也比較只適合用在標題上。「斷行斷在哪裡」這件事情,對內文來說太無足輕重了,應該是個可以忽略的問題。

OS X 從 10.9 Mavericks 開始,對中文斷詞似乎有一個明顯的進展。你在文字輸入的地方,如果在一串中文中間點兩下,你會發現他通常會選取「一組詞」(例如 電腦 ),而不像以往只會選取「一個字」。(我猜這大概做在 CoreText 裡面?)期望未來這個技術能夠再往下放到網頁上,也許某一天我們的瀏覽器就可以有效識別中日文的詞組,然後提供某種 CSS 選項、讓斷行只發生在詞組的邊緣了。


  1. 關於 Responsive Web Design 這件事情,台灣翻譯為「自適應式網頁設計」、中國翻譯為「響應式網頁設計」。或許「響應式」再貼近些,不過我始終覺得聽起來很彆扭。這裡就且讓我繼續用英文稱之。 

  2. 中文歌名光是不含標點就有 61 個字了。日文原文為《鈴懸の木の道で「君の微笑みを夢に見る」と言ってしまったら僕たちの関係はどう変わってしまうのか、僕なりに何日か考えた上でのやや気恥ずかしい結論のようなもの》 

comments powered by Disqus