Quotation marks look ugly in my Quarto website. Here is how I fix it.
問題描述
Quarto 生成 HTML 時,原稿中使用英文半形的單引號「
'」 會變成「’」,如下圖當中的「What's new」:原稿裡面本來是小而美的單引號,經過 Quarto 生成網頁之後,變成了大而不當的彎彎一撇。
如何能讓 Quarto 輸出的文件顯示比較美觀的單引號?
原因分析
以前使用 Hugo 來將 markdown 文件轉換成靜態網站時,我也曾碰過類似情形。當時是調整 Hugo 組態檔的 [markup.goldmark.extensions.typographer] 選項來解決。於是這次我直覺推測,可能是 Quarto 生成靜態網站過程中有某個轉換程序,會把單引號字元替換成「排版友善字元」。
基於這個假設,我向幾個 AI agents 提問,得到的答案大同小異:問題指向 Quarto 生成 HTML 時,英文半形單引號會被自動轉換成 「排版友善字元」(例如彎曲的右單引號),而此行為的根源是 Pandoc 的智慧標點(smart punctuation)功能。
然而,試過 AI agents 提供的多種解法後,全都無效——有些甚至導致 Quarto 顯示語法錯誤。正懊惱時,突然靈光一閃:「會不會跟網頁使用的字體有關?」
結果證明,的確是網頁使用的字體影響了單引號的顯示。接著細說。
解決方法
最初 AI agents 提供的方法都無法解決,例如在 .qmd 文稿的 front matter 中使用 from: markdown-smart:
---
title: What's new
from: markdown-smart
---
後來,我想到或許跟網頁使用的字體有關,於是嘗試把中文字體的順序往後移,便解決了。例如原本在 _quarto.yml 中的設定是這樣:
format:
html:
mainfont: Noto Sans TC, Roboto, -apple-system, BlinkMacSystemFont
把 "Noto Sans TC" 順序放到後面即可解決:
format:
html:
mainfont: Roboto, "Noto Sans TC", -apple-system, BlinkMacSystemFont
👉 提醒:如果你發現上面的設定對你無效,請檢查你的網站是否有其他自訂 CSS 覆蓋了 Quarto 的設定。例如:
:root {
--bs-body-font-family: Noto Sans TC, -apple-system, Segoe UI, Roboto;
}
為什麼把英文字體放前面能解決?
- 瀏覽器會按照 font-family (或 Quarto 的
mainfont屬性)優先順序,選第一個「包含該 Unicode 字元的字體」來 render 該字元。換言之,字元是哪個字體畫出來,取決於 font-family 的順序 + 哪個字體有該 glyph。 - 許多 CJK(中日韓)字體同時帶有拉丁字元與標點,但這些拉丁字元/標點的設計跟英文字體不同(寬度、比例、位置、字形設計會不一樣),因此當中文字體供應了撇號或右單引號(U+2019 / U+0027)時,呈現看起來就會「不協調」或偏寬。Noto CJK 社群亦有相關討論,例如這個 issue:The apostrophe (') character width issue in Noto CJK Chinese fonts。
- 使用英文撰寫的文稿,常用的「撇號/右單引號」通常是 U+2019(typographic apostrophe);而 ASCII 的
'是 U+0027。瀏覽器顯示的是 HTML 裡實際的 code point,但使用者看到的字元外觀則是由呈現該 code point 的字體來決定。
因此,當我們把 Roboto 或其他英文字體放在前面,瀏覽器會優先用 Roboto 字體來呈現拉丁標點,其外觀就會顯得正常且美觀。
補充:使用 unicode-range 明確劃分字體責任區
如果要更嚴謹,也可以用 CSS 或 @font-face 的 unicode-range 把字體責任區分清楚:拉丁字元由英文字體負責,中文由 CJK 字體負責。以下是個參考範例(AI 生成,僅供參考):
/* 只讓 Roboto 負責基本拉丁區段 */
@font-face{
font-family: 'Site-Roboto';
src: local('Roboto'), url('/fonts/roboto.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0100-024F; /* Basic Latin + Latin Extended */
}
/* 只讓 Noto Sans TC 負責中文區段 */
@font-face{
font-family: 'Site-NotoTC';
src: local('Noto Sans TC'), url('/fonts/notosanstc.woff2') format('woff2');
unicode-range: U+4E00-9FFF, U+3000-303F, U+FF00-FFEF; /* CJK 範圍 (示意) */
}
body {
font-family: 'Site-Roboto', 'Site-NotoTC', sans-serif;
}
附註:關於「智慧標點 (Smart Punctuation)」
當 Pandoc 的「智慧標點 (Smart Punctuation)」功能開啟(預設啟用)時,它會自動將 Markdown 裡的直線型 ASCII 標點(如 ', ", --, ...)轉換成印刷用的彎區引號、長破折號、省略號等,讓文件在視覺上更「優雅」。
以下是字元轉換對照表:
| 原始輸入 | 轉換結果 | 說明 |
|---|---|---|
'word' | ‘word’ | 直引號變成彎曲的單引號(curly single quote)。 |
"word" | “word” | 直引號變成彎曲的雙引號 (curly double quote)。 |
-- | – | en dash,即短破折號,用於表示範圍,例如 1–10。 |
--- | — | em dash,即長破折號,用於句中斷開。) |
... | … | 省略號(ellipsis)。 |
TeX's | TeX’s | 單引號自動識別為彎曲的一撇。 |
1990's | 1990’s | 同上,變成彎區的一撇。 |
--foo 或 bar-- | –foo / bar– | 自動轉換為 en dash。 |
延伸閱讀
相關討論串:
- Quarto is rendering "--" to "–"
- How to get swiss quotation marks for a html website with rmarkdown/quarto
此外,將來如果碰到 Quarto 生成的網頁或文件有特殊的格式轉換需求,是現有方法都無法解決的,還可以嘗試自行撰寫 filter。參見:
沒有留言: