使用 CSS 與一點魔法,在 HTML 中英文交界加入空格
更新 目前(2023-02-18)改成直接在原文章中輸入空格,因為以下描述的方法實行起來有一些難處(最明顯的就是不能避掉標點符號)。
最近開始寫中文的Public Logs,寫一寫總會去預覽一下排起來的樣子。但寫最近一篇Week 39的時候,卻越看越不對勁:為什麼中文字跟英文字之間,一點空格都沒有?身為對字體排版還算有點要求的人,這種狀況實在是令人不爽。因此我開始尋找將中英稍微隔開來的方法。
直接用CSS解決?
曾經,IE支援一個名為text-autospace
的CSS設定。它的用途是指定表意文字(中日韓文)與其他語系的文字(拉丁文、西里爾文、希臘文、阿拉伯文等)中間的空格大小。在StackOverflow上也有人問過相關的問題。可惜這個設定並未被Firefox、Safari與Chrome納入,因此逐漸遭到淘汰。
目前也有人討論是否將這些設定納入w3c網頁標準規範(https://github.com/w3c/csswg-drafts/issues/6950),但目前看來沒有定論。
改幹HTML
再搜尋了ㄧ會,唯一的方法似乎剩下直接開幹HTML。我最一開始的想法是這樣子:
+–––––+———————————––+ | Markdown | 1. 取出英文區段 | | | 2.
在外圍加入<span lang="en">
| +–––––+———————————––+ |
CSS | - 加入span[en]的padding規則 | +–––––+———————————––+
因此我在我的轉換腳本_(連結失效)_中將Markdown轉成HTML的部份,加入了一個sed
處理:
cat "$i" | \
sed '2,${/^#/!s|\([A-Za-z0-9 :,.]*[A-Za-z0-9 :,.]\)|<span lang="en">\1</span>|g}' | \
pandoc -f markdown -t html | \
sed 's/→/→/g' >> "${i%.*}.html" \
|| err -f "Pandoc failed to convert, or sed has an error with $i";
最相關的部份是:
sed '2,${/^#/!s|\([A-Za-z0-9 :,.]*[A-Za-z0-9 :,.]\)|<span lang="en">\1</span>|g}'
這個方法最大的問題是,它同時會抓出純英文的部份,因此讓一些其他的Markdown格式整個跑掉。
於是我想說,能不能改抓「前面有中文字」的英文字串?查詢了一下,發現sed
很難指定抓取中文字。但這個StackOverflow答案建議,處理這種可以使用perl
:
Perl has pretty good support for dealing with Unicode. That might be a better bet for your task than sed. This one-liner works like your first sed example:
perl -CIOED -p -e 's/\p{Script_Extensions=Han}/$& /g' filename
The -CIOED tells perl to do its I/O in utf8. -p runs the given code once for each line of the input file, then prints the result. -e specifies a line of Perl code to run. See the documentation on command-line arguments for more.
The regular expression uses named ranges to identify the characters to match.
You might also want to read the Perl Unicode documentation.
因此我把原本的sed
部份改了一下,以符合perl
的格式:
cat "$i" | \
perl -CIOED -p -e 's/(\p{Script_Extensions=Han}\[?)([A-Za-z0-9 :,.]*[A-Za-z0-9 :,.])/$1<span lang="en">$2<\/span>/g' | \
pandoc -f markdown -t html | \
sed 's/→/→/g' >> "${i% .*}.html" \
|| err -f "Pandoc failed to convert, or sed has an error with $i";
用這段程式可以將下列Markdown(取自Public Logs的Week 39)
[ltlnx](../index.html) > [Public Logs](index.html) > **Week 39 (2022-09-25 – 2022-10-01)**
# Week 39 (2022-09-25 – 2022-10-01)
_(English readers: most parts of my public log will be in Chinese. Sorry about that.)_
### 2022-09-25
最近把一些東西重新裝回去了,例如新酷音。在=+=Slackware=+=將=+=fcitx=+=正式升級成=+=fcitx5=+=之後,
原本想說試試看先不裝新酷音,適應看看原生的行列;經過一個禮拜之後,深刻感受到這樣
是行不通的。接著又試著裝了=+=gcin=+=,卻發現在=+=Wayland=+=上跑會造成ㄧ大堆東西=+=segfault=+=。但
詞音打起來真的好舒服,比新酷音舒服太多了。真的好可惜。
一段時間沒寫這鬼東西了。還是希望自己多紀錄人生呢,也能稍微踏實一點。
轉為
[ltlnx](../index.html) > [Public Logs](index.html) > **Week 39 (2022-09-25 – 2022-10-01)**
# Week 39 (2022-09-25 – 2022-10-01)
_(English readers: most parts of my public log will be in Chinese. Sorry about that.)_
### 2022-09-25
最近把一些東西重新裝回去了,例如新酷音。在<span lang="en">Slackware</span>將<span lang="en">fcitx</span>正式升級成<span lang="en">fcitx5</span>之後,
原本想說試試看先不裝新酷音,適應看看原生的行列;經過一個禮拜之後,深刻感受到這樣
是行不通的。接著又試著裝了<span lang="en">gcin</span>,卻發現在<span lang="en">Wayland</span>上跑會造成ㄧ大堆東西<span lang="en">segfault</span>。但
詞音打起來真的好舒服,比新酷音舒服太多了。真的好可惜。
一段時間沒寫這鬼東西了。還是希望自己多紀錄人生呢,也能稍微踏實一點。
接下來只要再掛一個CSS樣式:
span[lang="en"]{padding: 0 0.25rem}
就大功告成了!結果就是現在看到的這個樣子。目前剩下的問題就是,這段程式碼還無法避開code
區塊,之後可能要加寫一些規則來偵測並避開它們。
2022-10-08 更新
<span>
的CSS更新如果在span外面套padding的話,會有一個問題:如果英文字在最左邊,就會有一個多出來的左邊空格。
但如果改用
span[lang="en"]:before{content: " "}
與span[lang="en"]:after{content: " "}
,因為瀏覽器將空格視為文字的一部分,問題就會消失:問題是,如果這樣設定,標題的中英文間空隙就會太大。
因此我們需要一個能將字體大小「隨著原字體大小縮小,而稍微放大」的公式。使用CSS的
calc()
,我們可以輕鬆達到這點:如果我們用以下的對應表格+———————––+————————+ | 外圍字體大小 | 空格大小 | +:=======================:+:======================:+ | 1rem | 1rem | +———————––+————————+ | 2rem | 0.5rem | +———————––+————————+
那麼我們可以推導出下列線性公式:
font-size: calc((1em * -0.5) + 1.5rem)
效果如下:
因此最終的CSS為:
span[lang="en"]:before {content: " "; font-size: calc((1em * -0.5) + 1.5rem)} span[lang="en"]:after {content: " "; font-size: calc((1em * -0.5) + 1.5rem)}
Last updated: 2022-10-08