這一篇其實有點虎頭蛇尾,主因是研究CSS排版比預期花超過太多時間,考慮一些排版細節,最後還是決定回到主流排版工具的懷抱,所以暫停相關的研究與實現,所以比起文章,更像自己的筆記。
目標
在全開源工具下,實現由XHTML+CSS達成出版品排版,以及可自動化的工作流程。
為什麼要XHTML+CSS ? 這其實是關於電子出版品規格標準的大主題,簡單來說,我認為XHTML+CSS組合,會成為統一電子出版製作規格的未來(對,是未來而不是現在)。
- O’Relly 新一代標準HTMLBOOK基於XHTML5
- EPUB3 基於XHTML5+CSS
困難
- CJK文字排版更為複雜,雖然W3C有中文排版需求標準,但是相關中文資源缺乏,日文部份相對成熟許多
- CSS印刷排版支援度低,有些甚至沒有瀏覽器支援,目前僅chrome、opera系列瀏覽器支援度「堪用」。
- 工具缺乏,並且成熟度都還需加強。
綜合以上3點,我們可以總結為:「CSS排版難,用CSS中文排版更難,找到完整工具,特別難。」如果對於熟悉Indesign、Scribus,甚至Word排版的人,相信CSS排版會讓你有回到石器時代,不如歸去的念頭;但如果你還是堅持像我一樣想不開,就繼續看下去吧!
工具與資源
工具
pandoc:如果經常有需要文件轉檔的人,應該都聽過鼎鼎大名的pandoc,如果不考慮CSS,它會是非常好的萬用工具,可惜我們正是踏在考慮CSS的不歸路上。
weasyprint - 由python寫成的渲染引擎,將html與css渲染成pdf,個人感覺在CJK上,比商業的prince支援度還好(個人觀感),不幸的是,它並不像princeXML是一個完整的解決方案,也有很多css屬性不支援,例如生成Table of Content(TOC)的target-counter https://github.com/Kozea/WeasyPrint/issues/23,就不支援,即使如此,目前它跟wkhtmltopdf是最成熟的開源方案。
vivliostyle.js -由vivliostyle公司開源的工具,可以在網頁上以電子書的像是即時預覽,還可以依據出版頁面尺寸調整,非常方便的工具,但是小心它還沒有完全支援w3c paged media 所有模組(大部分支援),並且會修改預設的css,因此還是以weasyprint輸出為主比較好,然而即時預覽非常便利。vivliostyle有出商業的vivliosyle formatter,可在非營利出版品免費使用。
wkhtmltopdf:也是另外一個強大、歷史悠久的函式庫,但不支援css @page的功能,使用自己實現的方法,由於不支援css的page,筆者裝完沒多久就放棄,沒有實際使用過,另外安裝流程有點複雜,筆者使用fedora,安裝流程如下:
sudo dnf install wkhtmltopdf-0.12.4-1.fc27.x86_64
wget https://downloads.wkhtmltopdf.org/0.12/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
tar xvf wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
sudo mv wkhtmltox/bin/wkhtmlto* /usr/bin/
sudo wkhtmltopdf --disable-smart-shrinking --lowquality --enable-external-links --enable-internal-links test.html test.pdf
princeXML - 商業出版工具,也是目前網路資源最多的,非營利出版品可以免費使用,單論歐美語系出版,應該是最好的選擇,然而CJK語系在使用過程中,還是有些錯誤發生,例如頁眉的中文無法顯示,但是在weasyprint可以正確顯示的情形,筆者有嘗試使用
@font-face
試圖替代預設serif、monospace字型,但還是失敗,錯誤log與截圖如下:
prince: page 52: warning: no font for CJK character U+4FE1, fallback to '?' |
- 書籍、網頁資源
- W3C @PAGE規範:必看
- CSS-Page-Tutorial - 類似 cookbook 書。
- 用HTML+CSS进行图书出版:少數中文CJK印刷品排版,使用princeXML。
- CSSではじめる同人誌制作:同樣也是CJK印刷品排版的指導手冊,可以在網路上購買(日文),即使不會日文,也可以看漢字與原始碼範例。
- CJK CSS排版相關:CJK CSS WEB排版其實早就是另外一個巨坑,更別提出版品了,簡直崩潰。
- 其他列舉:由於CSS出版的相關工具真的太少,因此下列列舉沒用過,但是可能有用的工具:
- css-polyfills:CSS PAGE有很多功能根本沒有被支援,有時就需要polyfill協助。
- 刪除額外元素工具
- 印刷框架Gutenberg
- 另外一個印刷框架Hartija—CSS-Print-Framework
- 董福興 medium:董福興是長期關注台灣電子出版品、參與W3C中文排版制定的專家。
CSS出版品排版規則
- 使用 chrome或opera預覽,並且打開Emulate CSS media的print,或是乾脆直接使用vivliostyle.js預覽
- 使用絕對單位
- 調整由整體至局部
@page
@page { |
標號
標題標號
vivliostyle.js沒有支援 string-set 與 string(var
) 的功能,無法預覽
h2 { |
頁數標號
/*左頁頁數標號*/ |
章節標號
body { |
TOC
#TOC a::after { |
pandoc轉換成html時,其實本身就可以根據標題自動生成TOC了,然而平面出版的TOC,比起網頁TOC多了頁數與版型對齊的需求。目前,我使用的工具裡面,僅僅Prince可以完美支援,weasyprint目前還不支援其中的關鍵功能:target-counter。
由於我還是希望以weasyprint為主(prince有其他問題),所以只好用lxml+weasyprint硬幹一個不怎麼漂亮的TOC。簡單來說,weasyprint本身就可以藉由生成pdf文件的bookmark來獲取標題所在頁數,再根據lxml解析、直接修改原本的網頁版TOC。
結果會長這樣:
可以發現這個硬幹版本還很陽春,雖然頁數對了,排版卻歪七扭八,困難點在於
- 無法針對版型做調整(寫死在內文)
- 中英文字大小不一,我還沒有試過等寬字型,可能也沒時間做了
# toc.py |
最後我改成這樣,較為單純。
def generate_toc(page_info, input_html): |
分頁
建議一律使用 page-break-after|before|inside
,而不要使用break-after|before|inside
,即使功能近似,但是語意更明確。
/* 在該標籤以後分頁,簡稱前分頁 */ |
值得一提的是,當標籤內的內容過多時,斷頁幾乎無可避免,即使有特別設置內分頁也不能完全避免,這時需要orphans/ windows
,分別處理內容在一頁範圍底端的最少數量行,與內容在一頁範圍頂端的最少數量行。
常見分頁與否規則
- h1使用前分頁
- h2、h3避免後分頁
- 表格、程式碼避免內分頁
h1 { |
段落
文字換行
雖然中文字不會像英文字發生過長需要斷行的情形,但是在中英文夾雜的文本內,還是要考慮換行問題,常見的作法是強迫換行,以及依單字換行兩種。
文字強迫換行 word-break: break-all; |
字體字型
匯入思源黑體
@import url(https://fonts.googleapis.com/earlyaccess/notosanstc.css); |
中文書籍字號與行距
根據董福興2014年在知乎的說法(https://www.zhihu.com/question/19621096/answer/30280453),中文書籍內文使用10.5pt,行距使用1.7em。
由於書籍的字體變化相對較少,在html全局加入font-size,之後就可以統一使用rem相對單位來調整大小。
html { |
中英文字
空格與非空格的兩難
- https://www.zhihu.com/question/19587406
- https://github.com/vinta/pangu.js
- 中英文之間為什麼要有空格?我問。
- python自動加入空白的腳本
手動加空格,並且設置text-align: justify;
的慘劇:
進階技巧: