受到日本的直書排版推廣委員會啟發,決定也來嘗試一波。
用 CSS 做直書排版
在需要直書的區塊中(例如範例中的 div
),加入 writing-mode
樣式即可。
div {
writing-mode: vertical-rl;
}
不能再更簡單。多加入一些文字看看。
當畫面較小的時候,網頁自動排版會溢出。當然我們可以模擬橫書的解法,加上高度限制,例如:
div {
writing-mode: vertical-rl;
height: 100%;
}
然後你就會得到一篇超~級寬的竹簡。若能確保每篇頁面的字數都不會太多,其實也沒關係。例如《新明解国語辞典》線上日文辭典就是這樣實作。
用 MacBook 的觸控板可以很容易左右滑動。而對於使用滑鼠的人,頂多加上一些簡單 Javascript 語法,把滾動方向改成左右滑動即可。但文章一長,這將會是災難般的閱讀體驗。所以我們勢必得找到方法讓長篇文章可以垂直分段。
直書分段
為直書垂直分段,單純使用 height
樣式調整的話,會導致所有文字往左邊溢出。這邊將使用分欄的小技巧,讓文字在 div
區塊寬度和高度同時受限制之下,依然能夠自然往下分段。又在文字排版完之前,我們無從得知最終區塊高度,所以要移除 height 設定。改成如下:
div {
writing-mode: vertical-rl;
width: 100%; /* 寬度限制 */
column-width: 7rem; /* 每段高度 7rem,約 7 個中文字 */
column-rule: solid 1px #ccc; /* 加入段落之前的分隔線 */
column-gap: 1em; /* 設定段落之間的距離 */
}
再讓我們看一次效果:
搞定?還沒。還有些問題需要調整,讓我們繼續看下去。
加入 Javascript 修正
單純靠 CSS,我們能做的調整有限。從這裡開始加入一些 JS 輔助。
英數混雜的排版顯示調整
首先,英文數字全部倒橫了。長的就當作沒辦法,一兩個英文字母、或者兩位數以內數字等,我們希望可以把它轉 90 度,讓我們不用常常歪頭。
雖然這件事 CSS 可以做到,但是需要在字的兩旁加入 HTML 標籤。才能夠搭配相應 CSS 來調整顯示方向,例如:
.tcy {
text-combine-upright: all;
}
<div>哆啦<span class="tcy">A</span>夢</div>
將輸出以下:
手動加入太麻煩,讓我們寫一點 JS 來自動做這件事。
function textCombineUpright( elem ) {
const regs = [
/(\s)(¥?\b\d{1,2}\b)(\s)/g, // short number, ie: 4, 12, ...
/(\s)\b([A-Z]{1,2})\b(\s)/g, // short capitalized chars, ie: A, IE, ...
];
regs.forEach(reg => {
elem.innerHTML = elem.innerHTML.replaceAll(reg, '<span class="tcy" data-before="$1" data-after="$3">$2</span>');
});
}
window.onload = function() {
// 請自行修改目標對象 Selector
const postContent = document.querySelector('div');
const targetElements = [
'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'blockquote',
];
targetElements.forEach(elem => {
postContent.querySelectorAll(elem).forEach( dom => {
textCombineUpright(dom);
});
});
};
這樣只要文章中出現「空白包夾的短英文、或數字」,就會自動幫我們加入帶有 .tcy
Class 的 span
標籤,以套用轉向樣式。
看起來舒服多了。但還有一個大問題。
高度無法自動調配問題
這時候的文章高度其實是超過 div
本身的。讓我們在 div
的 CSS 中加入 outline: 2px solid red;
印個紅色外框看看。
當 div
後面還有東西,第二段以後的文字會全部和後面元素重疊在一起,無法閱讀。
原因是因為,目前的 CSS 中沒有指定欄位數量,而預設是 1 欄,在直書排版中就是一個段落。但是每篇文章的字數不一,因此所需段落數量也不一樣。也就沒辦法在 CSS 中寫死一個固定值。網路找了半天找到了一個 JS 解法:直接將區塊高度指定為與內文等高。底下是一個簡化過的版本。有需要的人請再自行修改條件。
function getAbsolutePosition(element) {
/*
getBoundingClientRect gives us relative offsets to the screen,
it changes when scrolling,
so convert to absolute position before we want to calculate the height.
*/
const rect = element.getBoundingClientRect();
return {
top: rect.top + window.scrollY, // Add vertical scroll
left: rect.left + window.scrollX, // Add horizontal scroll
bottom: rect.bottom + window.scrollY,
right: rect.right + window.scrollX,
height: rect.height,
};
}
window.onload = function() {
// 請自行修改目標對象 Selector
const postContent = document.querySelector( 'div' );
function onResize(container) {
let childs = Array.prototype.slice.call( container.children );
let maxBottom = 0;
// 歷遍子元素,以找出最底下的 Offset
childs.forEach( c => {
if (c.innerHTML.trim() == '') {
return;
}
const bound = getAbsolutePosition(c);
let currButtom = bound.top + bound.height;
if (currButtom > maxBottom) {
maxBottom = currButtom;
}
});
// 將最底 Offset 扣掉 父元素的 Top 以設定為容器高度
const topOffset = getAbsolutePosition(container.children[0]).top;
container.style.height = (maxBottom - topOffset) + 'px';
}
onResize(postContent);
};
粗暴,但簡單。終於搞定!
排版調整
標點符號處理
當一切看似安好,直到從 Safari 換到 Firefox 再看一次。
「:」等標點符號的方向竟然不一樣!不知道是字體的問題,還是 Firefox 不懂中文直式排版。也許換個字體就可以搞定。想說為了相容性,稍微調整一下當初做文字轉向的 Javascript。把冒號分號也加入轉向樣式。
function textCombineUpright( elem ) {
const regs = [
/(\s)(¥?\b\d{1,2}\b)(\s)/g, // short number, ie: 4, 12, ...
/(\s)\b([A-Z]{1,2})\b(\s)/g, // short capitalized chars, ie: A, IE, ...
/()([:;])()/g, // add this line
];
regs.forEach(reg => {
elem.innerHTML = elem.innerHTML.replaceAll(reg, '<span class="tcy" data-before="$1" data-after="$3">$2</span>');
});
}
搞定。預覽圖就不放了。
字元間距調整
如果你覺得標點符號的距離有點遠,可以加入 font-feature-settings
樣式做微調。例如:
font-feature-settings: "halt";
仔細看逗號頓號等標點符號,可以發現字元間距縮短,排版較為緊密。青菜蘿蔔各有喜好,按照個人需求增加即可。也不是每個字體都有支援,請自行參閱下方參考資料連結做嘗試。
後記
在英文橫行天下的時代,網頁設計也大多為了混排中英夾雜的文章,而採用橫式設計。CSS 本身的設計模式,當然也不例外,預設是由左上往右下排列。網頁滾動,也是上下滑動最為自然。因此對於任一橫版排列的網頁——就算是阿拉伯文等由右往左邊讀的文字——CSS 都得心應手。
雖然中日文等文字,直書橫書都可以,但直排才是漢字文化圈傳統,是其特色。身為一名中文使用者,我不入地獄誰入地獄,也就決定來試試直書在網頁上能夠呈現的效果。為普通的部落格,增添一點文藝氣息。
希望有更多的中文圈使用者,也一起來挑戰一下直書排版網頁 🙂
參考資料
- CSSで文字を縦書きに!初心者がつまずきやすいポイントを丁寧に解説! | 東京フリーランス
- 【CSS】文字を縦書きにする指定方法を解説 │ TechMania
font-feature-settings
參考一覽表