機制 A 行內連續擠壓原對 (L,R) 兩側獨立收:L 有右空白即收,不看 R 是誰,致句末 點號接開類(。「/?「)兩側皆收、合占 1em,丟失句界視覺。修為:L 為句末點號 (bd-stop)且 R 為開類(bd-open)時保留 L 右空白、僅收開類左側 → 全角式與開明式 皆 1.5em,對稱於 。」。例外僅限句末點號+開類;句內點號 ,「 與雙括號 」「/》《 仍兩側皆收 1em。 半角式不回歸:句末點號於 banjiao 由 baseline(機制 C)已收半形,守衛僅跳過 adjacency 之重複追加、不移除 baseline 之 jz-half;實測 32 可壓縮標點全半形、句界 組合句末點號仍半形(0 回歸)。唯非可壓縮 ·・‧/…— 各式皆全寬,屬設計。 唯一改動點 jiyaAdjacencyPass.squeeze() 加 stopBeforeOpen 守衛;lineedge/baseline /jinze/spacing 不波及。新增 3 契約測試(116 全綠);README/ARCHITECTURE §6.3 同步句界例外。
26 KiB
聚珍(Juzhen)
現代簡/繁中文網頁排版套件。Han.css 之現代化重寫,沿其功能版圖,並針對 數種情況作調整:複製乾淨(中西間隙不入剪貼板)、依
lang全角/開明 自動切換、justify下句末標點只佔一份間距、跨瀏覽器一致 (Chrome/Edge/Safari/WebKit/Firefox)。
倉庫名仍為 cjk-autospace;公開 API 為 createJuzhen / 全域 Juzhen;注入之
自訂元素前綴 jz-。完整設計見 ARCHITECTURE.md。
本版(2.x)為從零重寫。v1 之
createCjkAutospace相容層已移除(最後一批 v1 消費端已遷移 v2 API);v1 原始碼保存於v1-autospace分支。
安裝與構建
npm install
npm run build # esbuild → dist/juzhen.{mjs,iife.js,css};tsc → dist/index.d.ts
npm test # jsdom DOM 正確性測試
產物(dist/,已入庫):
| 檔 | 用途 |
|---|---|
dist/juzhen.mjs |
ESM,供打包器/TypeScript |
dist/juzhen.iife.js |
IIFE,全域 Juzhen,原生 <script> 直跑 |
dist/juzhen.css |
合併樣式(必須引入,視覺尺寸全在此) |
dist/index.d.ts |
TypeScript 型別宣告 |
用法
原生 <script>
<link rel="stylesheet" href="dist/juzhen.css">
<script src="dist/juzhen.iife.js"></script>
<script>
const jz = Juzhen.createJuzhen({ scope: { include: ".prose" } });
jz.render(); // 對 document.body 套用(僅命中 .prose 子樹)
// jz.revert(); // 還原
</script>
ESM/TypeScript
import { createJuzhen } from "cjk-autospace";
import "cjk-autospace/css";
const jz = createJuzhen({ lang: { default: "zh-Hant" } });
jz.render(document.querySelector("main"));
JS 與 CSS 缺一不可:JS 只注入 jz-* 結構,所有視覺尺寸(間隙寬度、擠壓量、
justify 原子化、字體堆疊)都在 juzhen.css。
切片 1 已實作功能
| 功能 | 說明 |
|---|---|
中西間隙 spacing |
CJK↔西文邊界插入 copy-clean 之 jz-hws(user-select:none,剪貼板跳過)。「西文」涵蓋拉丁(含擴充 A/B,拼音聲調 ā ǎ ē)、希臘、西里爾、數字、貨幣(€ ₩ ₿)、數學運算符等;CJK 標點(。,「」()…… 等)不誤判為西文、不生隙。含跨樣式行內邊界與 pill/隔離元素邊界(code/kbd/.katex 與 mark,兩端補隙口徑一致;pill 緊鄰標點時穿越 jz-jinze 仍補間隙;pill 跨行右隙、間隙落行末之自我應驗皆已修)。pill 之邏輯鄰字為標點時(如 漢字。<code>)不誤加間隙(標點非 pill 鄰字;jz-char/jz-inner 透明穿越,與 collectRuns 一致)。贅餘作者空格一律正規化:CJK↔西文吸收為受管間隙、CJK↔CJK(含跨 inline 標籤)剝除不留隙。 |
長英文詞 longWord |
[A-Za-z]{6,} 包入 <span lang="en">,配合 CSS hyphens:auto 原生斷詞(DOM 無連字符 → 複製不污染)。 |
標點擠壓 jiya |
標點 charify 為 jz-char+bd-* class。三機制:①baseline 政策(全角式不擠/開明式擠句內點號+括號引號/半角式全擠);②行內連續擠壓(相鄰標點雙側獨立收——各標點若其有空白之側緊鄰另一標點即收半,故 ,「 全角式與開明式皆 1em、。」 全角式 1.5em/開明式 1em;唯句末點號接開類為句界——。「/?「 保留句末點號右空白、僅收開類,全角式與開明式皆 1.5em;透明穿越 strong/em 等行內邊界);③行端擠壓(lineedge layout pass)。半形預設以字型 halt 渲染(按字形正確定位,居中字形如 !?/繁體 。, 不重疊;不依賴 text-spacing-trim)。字型缺 halt 時可切 margin 後備模式(見下節)。 |
禁則 jinze |
行首行末避頭尾:閉類/點號綁前一字(不置行首)、開類綁後一字(不置行末),只隔離邊界字故長引文中段仍可斷。亦為 justify 綁定載體。邊界字落於透明行內樣式元素(strong/em 等)內時克隆切分只綁邊界詞元(避免整個元素入 nowrap 致行末整體掉行、上行留巨大空隙),切出之克隆標 data-jz-kind="splitoff"、revert 時自動併回原元素;不可切元素(a/abbr/ruby/帶 id,以及 pill/隔離/avoid——見「行內元素三分類」)退化為整元素綁定——pill(如行內公式 .katex)即作為原子鄰字單位整體綁入 jz-jinze,絕不下潛肢解其內部。 |
垂懸字避免 orphan |
段末行 CJK 實義字 ≥ N(預設 2;標點/符號不計)。方案 C(斷行層、無測量):把段末「第 N 個實義字起至段末」包入 jz-orphan(white-space:nowrap),整體不可斷 → 末行恒含之 ⇒ 末行實義字 ≥ N,任意寬度/字型成立。單行段無害。邊界字落於行內元素內時同樣克隆切分(只綁末 N 字、避免整個長元素入 nowrap 溢出容器;機制同禁則)。預設開(orphan:false 關,{chars:n} 調)。段落級功能。 |
hanging |
已移除(§6.5.6):純負 margin 機制為機制級死路(寬度守恆矛盾,CSS 接觸不到斷行器),原生 hanging-punctuation 為唯一正解但僅 Safari 支援、且與本庫 inline-block 原子互斥。hanging 選項仍被接受(API 相容)但無任何效果;相關程式碼/CSS 已全數刪除,原生路徑屬遠期「原生管線」新功能。 |
功能分級 level |
功能分文本級(中西間隙、標點擠壓——任意文本片段適用)與段落級(禁則、垂懸字、懸掛、長詞——需行/段布局)。塊級元素預設全功能;data-jz-level="text" 子樹或選項 level:{text:"選擇器"}(如標題/按鈕)僅跑文本級。 |
| justify 單份間距 | 每個 jz-char 為 inline-block 原子項,句末標點只貢獻一份對齊伸縮量。 |
後續(架構已預留,不返工):標點修正(簡↔繁)、著重號、注音/Ruby。
選項
createJuzhen({
lang: {
default: "zh-Hant", // 無 lang 祖先時之預設
policy: { "zh-Hant": "quanjiao", "zh-Hans": "kaiming" }, // 全角/開明/半角
},
scope: {
root: document.body, // 處理根;render(root) 可逐次覆寫
include: ".prose", // 啟用選擇器(opt-in):僅處理命中子樹
avoid: "blockquote.raw", // 追加排除選擇器
},
spacing: true,
longWord: { minLength: 6, lang: "en" },
jiya: true, // 或物件:{ halfWidth: "halt" | "margin", bias }
jinze: true,
orphan: true, // 垂懸字避免(預設開);或 { chars: 2 };false 關
// hanging:已移除、無效果(見「標點懸掛」一節)
level: { text: "h1,h2,h3,button,.ui" }, // 此選擇器子樹僅跑文本級功能(見下)
pillSelector: "code, kbd, .katex", // 整體(pill)元素(見「行內元素三分類」)
isolateSelector: "mark", // 內外隔離元素(預設 mark;"" 停用)
justifyAtoms: true, // jz-char/jz-jinze 以 inline-block 作對齊原子;
// 分頁器(Paged.js)下設 false 改 inline(見下)
blocks: [ // 分塊功能選擇
{ selector: ".code-comment", features: [ "spacing" ] },
],
});
行內元素三分類:透明/隔離/整體
行內元素對排版有且僅有三種口徑,所有遍歷原語共用同一判定(中西間隙、擠壓相鄰、 禁則綁定、垂懸字、克隆切分皆一致):
| 分類 | 選擇器 | 邊界 | 內部 | 典型 |
|---|---|---|---|---|
| 透明 | styleInlines(預設常見樣式標籤) |
穿越——間隙/相鄰/run 皆延續 | 照常處理;禁則可克隆切分(最小綁定) | strong/em/b/i/a/span |
| 隔離 | isolateSelector(預設 "mark") |
斷 run/斷相鄰/不可切分;兩端與 CJK/西文相鄰時補 jz-hws 間隙 |
照常處理(自成脈絡:內部標點照擠、內部中西照補隙) | 帶背景色之 <mark>、badge 類盒樣式行內 |
| 整體 | pillSelector(預設 "code, kbd") |
同隔離(邊界斷、兩端補隙) | 完全不可見——不 charify、不插間隙、不切分、不下潛 | code/kbd、行內公式 .katex、引用標 .cite-ref |
要點:
- 判定以元素為準、非標籤名:KaTeX 全樹皆
<span>,但.katex命中pillSelector即為整體邊界——舊版按標籤名判透明曾整棵下潛、把公式內側末字連同殼層克隆切出(肢解)。 - pill 行為覆蓋 isolate:兩者邊界口徑完全相同(兩端補隙、斷 run/斷相鄰、不可切分, 同一段邊界處理代碼),差異僅在內部;同一元素同時命中兩選擇器時 pill 勝出(內部不可見)。
- 禁則之整體綁定:pill 緊鄰禁則標點時(
…$公式$,),整個 pill 作為原子鄰字單位 綁入jz-jinze(公式本不可斷,無額外代價);隔離元素同樣整綁(切分背景盒有可見接縫)。 scope.avoid/skipAttribute/data-jz-skip以自身判定:命中元素自身即邊界、 內外皆不處理(舊版僅查祖先,元素自身命中時仍被穿越)。- 行內公式/夾注引用宜列為 pill:
pillSelector: "code, kbd, .katex, .cite-ref"—— 獨立行內單位以 pill 邊界邏輯統一處理(兩側補隙、吸收作者空格、整體綁定)。
分頁器(Paged.js 等)相容:justifyAtoms
預設 jz-char/jz-jinze 為 inline-block,作 justify 之單一對齊原子(句末標點
單份間距)。但分頁器(如 Paged.js)之對齊引擎會把每個 inline-block 邊界當伸縮點、
與 CJK inter-ideograph 疊加,於窄欄混排時字距失控、整段散架。此時設
justifyAtoms: false——jz-char/jz-jinze 改 display:inline(半形 halt 與禁則
nowrap 綁定均保留)。常規流式版面無需設定。
注意:
margin後備半形依賴inline-block(width:0.5em),故justifyAtoms:false與margin模式不可兼得——分頁器場景請用含halt之字型。
分塊功能選擇(HTML 屬性,就近繼承)
<p data-juzhen="spacing jiya">…</p> <!-- 白名單:僅此二功能 -->
<p data-juzhen-off="jiya">…</p> <!-- 黑名單:停用 jiya,其餘繼承 -->
<div lang="zh-Hans">…</div> <!-- lang 驅動全角/開明 -->
功能分級:文本級 vs 段落級(level/data-jz-level)
功能分兩級:
- 文本級(中西間隙
spacing、標點擠壓jiya):僅依字符鄰接,任意文本片段(單行 標題、按鈕、單一行內元素)皆適用且想要。 - 段落級(禁則
jinze、垂懸字orphan、標點懸掛hanging、長詞longWord):依賴 行/段布局(換行、行端、段末),對單行/非段落文本無意義甚至有害。
塊級元素(p/div/li/h1…)預設段落級(全功能)。把標題/按鈕/UI 文字標為
文本級(要間隙與標點半形、不要懸掛/避孤字/避頭尾):
<h1 data-jz-level="text">標題:只跑中西間隙與標點擠壓</h1>
<p data-jz-level="paragraph">…</p> <!-- 顯式全功能(巢狀於 text 子樹內可覆寫,最近祖先勝) -->
createJuzhen({ level: { text: "h1,h2,h3,button,.ui" } }); // 選擇器一鍵標記
標點懸掛(hanging)— 已移除
原計劃之標點懸掛(行端標點凸出版心)經實測為機制級死路、已移除(負 margin 程式碼與
CSS 皆刪)。hanging 選項仍被接受(API 相容)但無任何效果——hanging:true/
data-juzhen/blocks 任一要求皆被靜默忽略,行端僅做半形擠壓。
為何機制級不可行(純 CSS 之寬度守恆矛盾):行端標點盒若保持非零寬,則「墨色出去多少、
版心內就空出多少」(行末實義字無法齊版心右緣);若收為零寬,則釋放一整字寬、斷行器把下一字
拉上本行與標點重疊(且 justifyAtoms 預設之 inline-block 下負 margin 被 justify 吸收)。
墨色出去多少版心內就空多少;想不空就得讓斷行器重排這塊寬度,而 CSS hack 接觸不到斷行器。
補償墊片、兩階段試錯都改變不了此恒等式。
唯一正解為原生 CSS hanging-punctuation,惟 Chrome/Firefox 至今不支援(僅 Safari),且
本庫之 jz-char 為 inline-block 原子、非文本,原生懸掛不作用——未來若做,須是繞開 jz-char
的「原生管線」新功能(text-spacing-trim + hanging-punctuation,按能力門控),與已移除之
程式碼無共享。詳見 ARCHITECTURE.md §6.5.6。
標點半形:halt 預設與 margin 後備
開明/半角式把標點收成「半形」,有兩種渲染機制:
| 機制 | 設定 | 原理 | 適用 |
|---|---|---|---|
halt(預設) |
jiya: true |
字型 OpenType halt,由字型按字形正確定位、不重疊 |
字型含 halt(Noto CJK/思源系列) |
margin(後備) |
jiya: { halfWidth: "margin" } |
width:0.5em+字身依墨色偏側溢出定位(以 CSS 重現 halt) |
字型缺 halt(多數系統字型、GBK 老字型如方正書宋 GBK、PingFang) |
為何需要後備:
halt缺席時開明式擠壓「完全無效」(標點仍佔全形)。實測 方正書宋 GBK 僅含vert、無halt→ halt 模式不擠;切margin後備後, (開明式 zh-Hans)同句行寬24.0em → 19.7em、單一句內點號1.0em → 0.5em,半形生效。
句末標點含全角句點
.:句末點號為。.!?——除表意句號。(U+3002)外納入 全角句點.(U+FF0E,實測 Noto CJK 有halt)。政策行為與。!?同:全角式與開明式 句末保持全角 1em;唯 banjiao(或與鄰標點連續被收)時halt收為半形 advance 0.5em。halt即字型之「挤壓意願」:字型不提供某標點之halt(其字形占滿字框、不宜挤半, 如某些字型之全角?、〈〉)時,聚珍信任字型、保持全角不強挤(優雅降級);margin後備僅用於整體無halt之字型,逐字型以jiya.bias調教。
激活與粒度
模式由 data-jz-halfwidth 屬性所在子樹決定(CSS 後代選擇器),故粒度極靈活:
- 全域:
jiya: { halfWidth: "margin" }→render()於處理 root 自動掛屬性。 - 逐區塊/逐語言:在 HTML 任一祖先手寫
data-jz-halfwidth="margin"(或"halt"),即令該子樹用對應機制——無需另建實例。常見如「全頁halt,某用 無halt字型之區塊掛margin」,或反之(margin頁中嵌一塊halt島)。
<!-- 全頁 halt(預設),此塊改用無 halt 字型 → 局部 margin 後備 -->
<section data-jz-halfwidth="margin" style="font-family: '方正书宋_GBK'">…</section>
機制與字形偏側表(margin 模式專用,可覆寫)
margin 模式把標點 jz-char 之 inline-block 寬收為 0.5em(真半形 advance),字身
(jz-inner)以 overflow 溢出該盒,再依墨色偏側左移、使墨色落於 0.5em 盒內、
空白溢向外側——即以 CSS 盒模型重現 halt 之「收字身寬+按字形定位」。相鄰兩標點各
0.5em、合佔 1em,無鄰接疊加或單側重疊問題。
偏側須知每字之墨色中心。聚珍內建參考表(依方正書宋 GBK 實測之 glyph ink 位):
簡體點號 ,、。;:!? 偏左;繁體點號居中;彎引號 “”‘’、角括號 「」、尖括號
〈〉 墨色強偏一側(開→right、閉→left);圓/方/書名等括號 ()【】《》… 墨色
近中→center。於 charify 標為 jz-ink-{left,center,right}。因字型字身分布各異,可逐
lang 逐字覆寫:
createJuzhen({
jiya: {
halfWidth: "margin",
bias: {
"zh-Hans": { ",": "center", "(": "right" }, // 覆寫參考預設
"zh-Hant": { "。": "center" },
},
},
});
// 偏側值(決定字身於 0.5em 盒內之左移):
// left 墨偏左 → 不移(字身左對齊)
// center 墨居中 → 左移 0.25em
// right 墨偏右 → 左移 0.5em(右半入盒)
// full 無可壓縮空白 → 不收、維持全形
halt模式不讀偏側表(由字型負責定位)。偏側表僅在margin後備模式生效。demo/fallback.html用方正書宋 GBK 對照 halt 失效 vs margin 生效。配字工作流見下節。
字型適配工作流(margin 模式配字)
換用新字型時,依下列步驟確認半形渲染:
- 驗
halt:python3 tools/measure-bias.py <font.ttf>(需pip install fonttools)。 首行報該字型是否含 OpenTypehalt。- 有
halt→ 直接用預設(jiya: true,halt 模式),無需配字,到此為止。 - 無
halt(多數系統字型、GBK 老字型)→ 用margin後備,續下。
- 有
- 取偏側建議:同一工具同時量各標點 glyph 之墨色中心、印出建議偏側表
(
left|center|right|full)與可貼入jiya.bias之 JSON。 - 套用:
createJuzhen({ jiya: { halfWidth: "margin", bias: <貼入 JSON> } }); 或全用內建參考表(多數宋體系 GBK 字型與參考表相符,未必需覆寫)。 - 目視微調:以
demo/fallback.html(或自有頁面)對照原文,逐字檢查——- 標點與相鄰字重疊 → 該字墨色比量測更偏該側,偏側往「不移」方向調
(
right→center→left)。 - 標點與內容仍有空隙、不夠半形 → 往「多移」方向調(
left→center→right)。 - 某標點根本無可壓空白(字面已滿全形)→ 設
full,不收。
- 標點與相鄰字重疊 → 該字墨色比量測更偏該側,偏側往「不移」方向調
(
- 記錄:把該字型之
bias覆寫存入專案設定,作為該字型之適配結果。
偏側是「字身於 0.5em 盒內左移多少」的三檔量化(0/0.25/0.5em),量測值近門檻 (如 0.6 介於 center/right)時,以目視為準。
halt字型走 OpenType 由字型精確 定位,無此配字需求——margin配字僅為缺halt字型之務實近似。
CSS 基礎設定(消費端須知)
JS 只注入 jz-* 結構,所有視覺尺寸在 juzhen.css——故 CSS 不可或缺。消費端
須備妥下列幾項:
- 引入樣式(必須):
<link rel="stylesheet" href="dist/juzhen.css">(或 ESMimport "cjk-autospace/css")。缺此則間隙/擠壓/justify 原子化全部失效。 - 設定
lang(強烈建議):在內容容器標lang="zh-Hans"/"zh-Hant"/"ja", 驅動全角/開明政策與字形locl。無lang時回退options.lang.default。 - 作用域類(用
scope.include時):若設scope.include: ".juzhen",須給內容 容器加對應 class(如class="juzhen");juzhen.css之 normalize 亦收斂於此域, 不外溢。 - 長英文詞斷字:
longWord包出<span lang="en">後,須由消費端 CSS 提供hyphens: auto(含-webkit-hyphens)才會原生斷詞顯示連字符。 justify(選用):欲兩端對齊則自行設text-align: justify;句末標點單份間距 與行末去隙由聚珍處理,無需額外設定。- 字型由消費端負責(聚珍不管字型):聚珍不內建任何
font-family/字型堆疊 ——逐語言字型完全由消費端 CSS 決定。聚珍只確保原子(jz-*)以font: inherit繼承消費端字型、絕不強加,並顯式保留locl(見下「字型與 locl」一節)。半形擠壓 依字型 OpenTypehalt:含halt之字型(Noto CJK/思源)預設即可;缺halt之字型(如方正書宋 GBK)須改用jiya.halfWidth:"margin"後備,並按字型以jiya.bias逐字微調墨色偏側(見「字型適配工作流」)。 - 自動處理、無需消費端介入:
juzhen.css已在.juzhen範圍內以@supports關閉 Blink 原生text-spacing-trim/text-autospace(避免與託管擠壓重複作用), 並令注入間隙user-select: none(複製乾淨)。 - 段落屬性照常設、原子透明:聚珍把標點拆成 inline-block 原子,但已確保這些原子對
消費端段落樣式透明——可在段落正常設
text-indent(首行縮排)、hanging-punctuation、text-decoration(下劃線)等;庫內已歸零會被原子重複套用之繼承屬性、並令原子承接段落 裝飾,故首行縮排正常、下劃線連續不斷,無需任何額外配置(機制見 ARCHITECTURE「原子透明 原則」)。
字型與 locl(消費端設定)
聚珍不管字型;逐語言字型由你以 CSS 設定。推薦範式——逐 lang 設 font-family,
掛在 .juzhen 或帶 lang 之容器(勿直接設 jz-inner/jz-char,它們靠繼承取字型):
.juzhen:lang(zh-Hans), .juzhen [lang]:lang(zh-Hans) { font-family: "Noto Serif SC", "Source Han Serif SC", serif; }
.juzhen:lang(zh-Hant), .juzhen [lang]:lang(zh-Hant) { font-family: "Noto Serif TC", "Source Han Serif TC", serif; }
.juzhen:lang(ja), .juzhen [lang]:lang(ja) { font-family: "Noto Serif JP", serif; }
要點:
- 字型須含 OpenType
halt才能半形擠壓;否則用jiya.halfWidth:"margin"+ 按字型 以jiya.bias逐字微調墨色偏側(見「字型適配工作流」)。 - locl(地域字形):泛 CJK 字型(思源/Noto CJK)以
locl依lang選地域字形 (如「直/海/骨」之簡繁日差異)。聚珍不改寫lang、不關閉 locl,故只要你 ① 正確標lang、② 用支援 locl 之字型,locl 即正常。body 文本之 locl 全由你的字型+lang決定;標點(jz-inner)之halt已顯式併入locl,地域標點字形不致失。 - 若只想全語言同一字型,直接
.juzhen { font-family: … }即可(無需逐lang)。
自定義字符分類(charClass)
每個字符的分類(中文/西文、全寬標點各子類)抽象為規則集:內置默認規則集即聚珍
的分類表,消費端可經 options.charClass 擴充,以覆寫 spacing/jiya/jinze
等規則對特定字符之判定。語義為追加——把當前未分類之字符、或新符號歸入對應類。
createJuzhen({
charClass: {
cjk: "〇", // 追加為中文(CJK):與西文邊界補中西間隙、禁則/justify 視為單字
western: "★☆", // 追加為西文(半寬標點亦歸此):與 CJK 邊界補間隙
biaodian: { // 追加為全寬標點,按子類(jiya charify/擠壓、禁則避頭尾)
stop: ".", // 句末(。!?類)
pause: "", // 句內(,、;:類)
open: "", close: "", // 開/閉括號引號
middle: "", liga: "", // 間隔號/省略破折
},
},
});
典型用例:英文全角句號 .(U+FF0E,有別於中文句號 。 U+3002)預設未分類
——不被 charify、不挤壓、與 CJK 間不補隙。若內容用 . 作句末標點,以
charClass: { biaodian: { stop: "." } } 歸為全寬句末標點,即比照 。 處理(開明式挤半形、
全角式佔全形、行首避頭尾)。
要點:
- 向下兼容:不傳
charClass時,分類與行為與內置默認完全一致。 - 追加語義(v1):擴充內置類;不支援把內置字符「重分類/移除」(屬罕見需求,後續再議)。 勿把同一字符同時加入相衝之兩類。
- 結構性 ASCII(字母數字
A-Za-z0-9、運算符+-*/等)為固定集、不開放覆寫——它們 服務於運算符/複合詞等內部規則,非「字符類型」。 margin後備模式下若新增開/閉括號,其墨色偏側未必命中內建參考表,可一併以jiya.bias指定(見「字型適配工作流」)。
v1 向下相容 — 已移除
v1 相容層(createCjkAutospace 導出、IIFE 之 globalThis.createCjkAutospace
別名、autospaceClass 選項)已隨最後一批 v1 消費端遷移完成而移除。既有消費端
請改用 createJuzhen(options).render(root) v2 API;v1 原始碼保存於 v1-autospace
分支。
目視驗證
demo/index.html 載入 dist/ 產物,簡繁並列、可切 justify、附 copy-clean 測試區。
demo/fallback.html 以方正書宋 GBK(無 halt)對照 halt 模式失效 vs margin
後備生效。demo/resize-check.html 為可拖曳容器檢查頁:拖動方框寬度,驗證中西間隙在
各寬度下恆穩(含行末去隙之自我應驗、pill 跨行右隙、貨幣/拼音/西里爾外文補隙、全角省略號
與各式中文標點無誤隙),可切 justify 與「顯示間隙」描邊。版面相關結論(justify 單份間距、
擠壓視覺量、行端、inline-block 基線、間隙隨寬度之穩定性)須於 Chrome/Safari/Firefox
三引擎目視核對——jsdom 僅驗證 DOM 結構正確性。
授權
MIT。借鑑 Han.css/Heti 之思路與分類表(MIT),成品自含、不依賴其執行期程式碼。