fix: 修复行缘、切分还原与语言解析并同步文档
保留逐字 margin/jiya.bias 字体后备方案;补齐 demo 重排、量测边界说明及共享规则 1.0.1 反例向量。 验证:完整构建通过,Node 376 项、WKWebView 64 项及原生 demo 9 项通过;Firefox 仍暂缓。
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
|
||||
> 現代簡/繁中文網頁排版套件。Han.css 之現代化重寫,沿其功能版圖,並針對
|
||||
> 數種情況作調整:**複製乾淨**(中西間隙不入剪貼板)、**依 `lang` 全角/開明
|
||||
> 自動切換**、**`justify` 下句末標點只佔一份間距**、**跨瀏覽器一致**
|
||||
> (Chrome/Edge/Safari/WebKit/Firefox)。
|
||||
> 自動切換**、**`justify` 下句末標點只佔一份間距**、**跨瀏覽器一致的設計目標**
|
||||
> (Chrome/Edge/Safari/WebKit/Firefox;實際驗收範圍見 UPDATES,Firefox 暫緩)。
|
||||
|
||||
倉庫名仍為 `cjk-autospace`;公開 API 為 `createJuzhen` / 全域 `Juzhen`;注入之
|
||||
自訂元素前綴 `jz-`。消費端契約見本文的[用法](#用法)與[標記說明](#行內元素三分類透明隔離整體),
|
||||
@@ -11,7 +11,9 @@
|
||||
|
||||
2026-10-02 的 Web/CSS 邊界與生命週期修復已推送至 `main`;
|
||||
[修復提交 `b1a16c4`](https://git.commilitia.net/admin/cjk-autospace/commit/b1a16c49698dc418aa733e41a04bdbc9922927be)
|
||||
包含配套構建產物。套件版本仍為 `2.0.0`、共享規則仍為 `1.0.0`,未進行 npm 發佈;
|
||||
包含配套構建產物。2026-10-03 的全專案掃描修復亦已提交並推送至 `main`,
|
||||
共享規則 `1.0.1` 補充既有語言契約的反例向量,詳見 [UPDATES](./UPDATES.md)。
|
||||
套件版本仍為 `2.0.0`,未進行 npm 發佈。
|
||||
使用倉庫產物時須一併更新 JS 與 CSS,具體升級影響見上述消費端更新記錄。
|
||||
|
||||
> 本版(2.x)為從零重寫。v1 之 `createCjkAutospace` 相容層**已移除**(最後一批
|
||||
@@ -44,7 +46,7 @@ npm run test:wkwebview # macOS 原生 WKWebView 版面/observer E2E(需 Xco
|
||||
|
||||
## 共享規則契約
|
||||
|
||||
`rules/` 是 Web/CSS 與並行 XeLaTeX 實作之唯一規則權威源;初版規則版本為 `1.0.0`。
|
||||
`rules/` 是 Web/CSS 與並行 XeLaTeX 實作之唯一規則權威源;初版規則版本為 `1.0.0`,目前為 `1.0.1`(契約澄清與新增反例向量)。
|
||||
規則以 Unicode code-point 區間、語言政策、標點寬度、間隙、禁斷與段末約束描述「應發生
|
||||
什麼」,不規定 DOM/CSS、TeX node/glue/penalty 或其他 adapter 的實作機制。
|
||||
|
||||
@@ -166,7 +168,7 @@ jz.observe(document.body); // 之後 DOM 變動即自動增量恢復
|
||||
| **中西間隙** `spacing` | CJK↔西文邊界以 copy-clean 之 `jz-hws` 與 `margin-right` 留隙;**不插入空白字元**,故剪貼板不多出空格。唯跨節點 IVS 產物以 `::after` 產生的 `U+200B` 斷行機會設 `user-select:none`;它不進入 DOM/`textContent`。「西文」涵蓋拉丁(含擴充 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/隔離**——見「行內元素三分類」)退化為**整元素綁定**——pill(如行內公式 `.katex`)即作為原子鄰字單位整體綁入 `jz-jinze`,絕不下潛肢解其內部。兩側須符合作用域、paragraph 級別與 `jinze` 功能閘;不可切時也不把 avoid/text/off 後代整綁帶入。 |
|
||||
| **禁則** `jinze` | 行首行末避頭尾:閉類/點號綁前一字(不置行首)、開類綁後一字(不置行末),只隔離邊界字故長引文中段仍可斷。亦為 `justify` 綁定載體。邊界字落於**透明**行內樣式元素(`strong`/`em` 等)內時**克隆切分**只綁邊界詞元(避免整個元素入 `nowrap` 致行末整體掉行、上行留巨大空隙),切出之克隆標 `data-jz-kind="splitoff"`、`revert` 時驗來源身份及屬性後併回原元素;若外部插入兄弟、替換來源或改樣式而無法安全合併,保留片段元素與文字位置並撤銷聚珍標記;不可切元素(`a`/`abbr`/`ruby`/帶 `id`,以及 **pill/隔離**——見「行內元素三分類」)退化為**整元素綁定**——pill(如行內公式 `.katex`)即作為原子鄰字單位整體綁入 `jz-jinze`,絕不下潛肢解其內部。兩側須符合作用域、paragraph 級別與 `jinze` 功能閘;不可切時也不把 avoid/text/off 後代整綁帶入。 |
|
||||
| **垂懸字避免** `orphan` | 段末可處理的連續區域 CJK 實義字 ≥ N(預設 2;標點/符號不計,完整碼點及 base+VS 算一字)。方案 C(斷行層、無測量):把段末「第 N 個實義字起至段末」包入 `jz-orphan`(`white-space:nowrap`),整體不可斷 → 末行恒含之 ⇒ 末行實義字 ≥ N,任意寬度/字型成立。單行段無害。邊界字落於行內元素內時同樣**克隆切分**(只綁末 N 字、避免整個長元素入 `nowrap` 溢出容器;機制同禁則)。**預設開**(`orphan:false` 關,`{chars:n}` 調)。段落級功能。avoid/text/off/`isSkipped` 區域中斷計數,只綁其後的合法尾部;不足 N 字或不可切容器含排除內容時不綁。 |
|
||||
| **功能分級** `level` | 功能分文本級(中西間隙、標點擠壓——任意文本片段適用)與段落級(禁則、垂懸字、長詞——需行/段布局)。塊級元素預設全功能;`data-jz-level="text"` 子樹或選項 `level:{text:"選擇器"}`(如標題/按鈕)僅跑文本級。 |
|
||||
| **justify 單份間距** | 每個 `jz-char` 為 `inline-block` 原子項,句末標點只貢獻一份對齊伸縮量。 |
|
||||
@@ -184,7 +186,7 @@ createJuzhen({
|
||||
lang: {
|
||||
default: "zh-Hant", // 無 lang 祖先時之預設
|
||||
style: "kaiming", // 全域政策一鍵覆寫(quanjiao|kaiming|banjiao)
|
||||
policy: { "zh-Hant": "quanjiao", "zh-Hans": "kaiming" }, // 逐 lang(最高優先)
|
||||
policy: { "zh-Hant": "quanjiao", "zh-Hans": "kaiming" }, // 逐 lang(低於逐元素覆寫)
|
||||
},
|
||||
scope: {
|
||||
root: document.body, // 處理根;render(root) 可逐次覆寫
|
||||
@@ -217,7 +219,7 @@ createJuzhen({
|
||||
|
||||
| 選項 | 型別 | 預設 | 作用 |
|
||||
|---|---|---|---|
|
||||
| `lang.default` | string | `"zh-Hant"` | 無 `lang` 祖先時之預設語言標籤 |
|
||||
| `lang.default` | string | `"zh-Hant"` | 自身及祖先皆無 `lang` 時之預設;空字串表示未知 |
|
||||
| `lang.style` | `quanjiao|kaiming|banjiao` | 逐語言內建(繁→全角、簡→開明) | **全域政策一鍵覆寫** |
|
||||
| `lang.policy` | `Partial<Record<LangClass, PunctStyle>>` | `{}` | 按語言分類覆寫:鍵僅為 `zh-Hans`、`zh-Hant`、`ja`、`other`;如 `zh-TW` 先歸入 `zh-Hant`,不直接作為鍵 |
|
||||
| `lang.stylePolicy` | `{selector,style}[]` | `[]` | **逐元素樣式覆寫**(選擇器命中之子樹用指定樣式;如 `[{selector:"h1,button,.ui",style:"banjiao"}]`);配合 `data-jz-style` 屬性,優先於 lang |
|
||||
@@ -481,7 +483,7 @@ CSS 皆刪)。`hanging` 選項仍被接受(API 相容)但**無任何效果
|
||||
**墨色出去多少版心內就空多少;想不空就得讓斷行器重排這塊寬度,而 CSS hack 接觸不到斷行器**。
|
||||
補償墊片、兩階段試錯都改變不了此恒等式。
|
||||
|
||||
唯一正解為原生 CSS `hanging-punctuation`,惟 **Chrome/Firefox 至今不支援**(僅 Safari),且
|
||||
原生 CSS `hanging-punctuation` 是未來可評估路徑,須另行核對各引擎能力及字型行為,且
|
||||
本庫之 `jz-char` 為 inline-block 原子、非文本,原生懸掛不作用——未來若做,須是繞開 `jz-char`
|
||||
的「原生管線」新功能(`text-spacing-trim` + `hanging-punctuation`,按能力門控),與已移除之
|
||||
程式碼無共享。詳見 `ARCHITECTURE.md §6.5.6`。
|
||||
@@ -566,11 +568,14 @@ createJuzhen({
|
||||
換用新字型時,依下列步驟確認半形渲染:
|
||||
|
||||
1. **驗 `halt`**:`python3 tools/measure-bias.py <font.ttf>`(需 `pip install fonttools`)。
|
||||
首行報該字型是否含 OpenType `halt`。
|
||||
- **有 `halt`** → 直接用預設(`jiya: true`,halt 模式),無需配字,到此為止。
|
||||
- **無 `halt`**(多數系統字型、GBK 老字型)→ 用 `margin` 後備,續下。
|
||||
首行報該字型是否含 OpenType `halt`;特性存在不保證所有標點/語言字形均覆蓋。
|
||||
- **有 `halt`** → 先在目標瀏覽器、字型及 `lang` 下逐標點驗證預設 halt 模式;
|
||||
覆蓋及定位符合要求者可免配字,未覆蓋者改用局部 `margin`。
|
||||
- **無 `halt`** → 用 `margin` 後備,續下。
|
||||
2. **取偏側建議**:同一工具同時量各標點 glyph 之墨色中心、印出建議偏側表
|
||||
(`left|center|right|full`)與可貼入 `jiya.bias` 之 JSON。
|
||||
(`left|center|right|full`)與可貼入 `jiya.bias` 之 JSON。工具只量預設 cmap glyph,
|
||||
不做 shaping/`locl`;第二個語言參數僅選 JSON 分類鍵,不會改變所量字形。泛 CJK 地域字形須
|
||||
以瀏覽器實際輸出微調,不能把各語言同值建議當成逐語言字形驗收。
|
||||
3. **套用**:`createJuzhen({ jiya: { halfWidth: "margin", bias: <貼入 JSON> } })`;
|
||||
或全用內建參考表(多數宋體系 GBK 字型與參考表相符,未必需覆寫)。
|
||||
4. **目視微調**:以 `demo/fallback.html`(或自有頁面)對照原文,逐字檢查——
|
||||
@@ -582,7 +587,7 @@ createJuzhen({
|
||||
|
||||
> 偏側是「字身於 0.5em 盒內左移多少」的三檔量化(0/0.25/0.5em),量測值近門檻
|
||||
> (如 0.6 介於 center/right)時,以目視為準。`halt` 字型走 OpenType 由字型精確
|
||||
> 定位,無此配字需求——`margin` 配字僅為缺 `halt` 字型之務實近似。
|
||||
> 定位;是否完整覆蓋仍須核對——`margin` 配字是缺 `halt` 或覆蓋不足字型之務實近似。
|
||||
|
||||
---
|
||||
|
||||
@@ -594,7 +599,9 @@ JS 只注入 `jz-*` 結構,**所有視覺尺寸在 `juzhen.css`**——故 CSS
|
||||
1. **引入樣式(必須)**:`<link rel="stylesheet" href="dist/juzhen.css">`(或 ESM
|
||||
`import "cjk-autospace/css"`)。缺此則間隙/擠壓/justify 原子化全部失效。
|
||||
2. **設定 `lang`(強烈建議)**:在內容容器標 `lang="zh-Hans"`/`"zh-Hant"`/`"ja"`,
|
||||
驅動全角/開明政策與字形 `locl`。無 `lang` 時回退 `options.lang.default`。
|
||||
驅動全角/開明政策與字形 `locl`。自身及祖先均無 `lang` 時回退 `options.lang.default`;顯式 `lang=""` 為未知語言
|
||||
(`other`),不繼承外層語言。簡繁分類只讀 BCP 47 的 script/region 位置,忽略
|
||||
extension/private-use 內的同名字串(如 `zh-Hans-x-hant` 仍為簡體)。
|
||||
3. **作用域類**:受管內容容器須加 `class="juzhen"`,以啟用內建原生間距禁用樣式。
|
||||
`scope.include` 只控制 JS 處理範圍,不會改寫 CSS 選擇器;若使用 `.prose` 等自訂
|
||||
選擇器,請同時加類別(如 `class="prose juzhen"`)。
|
||||
@@ -645,6 +652,9 @@ JS 只注入 `jz-*` 結構,**所有視覺尺寸在 `juzhen.css`**——故 CSS
|
||||
|
||||
## 自定義字符分類(`charClass`)
|
||||
|
||||
`cjk`/`western` 是 regex 字元類片段,特殊字元須轉義;`biaodian` 各子類則是
|
||||
逐碼點字串,不解析範圍。追加三個圈碼應寫 `"①②③"`;`"①-③"` 會追加 `①`、`-`、`③`。
|
||||
|
||||
每個字符的分類(中文/西文、全寬標點各子類)抽象為**規則集**:內置默認規則集即聚珍
|
||||
的分類表,消費端可經 `options.charClass` **擴充**,以覆寫 `spacing`/`jiya`/`jinze`
|
||||
等規則對特定字符之判定。語義為**追加**——把當前未分類之字符、或新符號歸入對應類。
|
||||
|
||||
Reference in New Issue
Block a user