a3c94ddee5
標點懸掛經實測為**機制級死路**(純 CSS 之寬度守恆矛盾):行端標點盒保持非零寬則墨色
出去多少版心內就空多少(行末實義字無法齊邊);收為零寬則釋放一整字寬、斷行器把下一字
拉上本行與標點重疊(且 justifyAtoms 預設之 inline-block 下負 margin 被 justify 吸收)。
CSS hack 接觸不到斷行器,此恒等式無解。唯一正解為原生 hanging-punctuation(僅 Safari
支援、且 jz-char 為 inline-block 原子非文本,原生懸掛不作用),屬遠期「原生管線」新功能、
與此處無共享,故不保留休眠碼。
移除:
lineedge.ts — jz-hang-* class、HANG_* 常量、applyEdge hang 分支、modeForChar、
HANG_ENABLED 總開關;行端僅餘 squeeze(半形)。
_jiya.css — jz-hang-* 三條規則(margin 半形 fallback 完整保留)。
types.ts — LineEndMode 型別、ResolvedOptions.lineEnd、features.hanging。
index.ts — lineEnd 鎖。
hanging 公開選項保留為 @deprecated no-op(API 相容)。
文檔:README「標點懸掛」節、ARCHITECTURE §6.5(開頭/§6.5.2/§6.5.4/§6.5.5/§6.5.6)、
demo(showcase §三/resize-check)全部由「停用/休眠」改為「已移除」+寬度守恆論證。
測試:防逃逸測試改寫為「hanging 為 no-op、輸出與不傳一致、各路徑不產生 jz-hang-*」。
全綠 101。dist 已無 jz-hang/lineEnd/HANG 殘留。
149 lines
12 KiB
HTML
149 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-Hant">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>聚珍(Juzhen)— 新功能效果演示(定寬對照)</title>
|
||
<link rel="stylesheet" href="../dist/juzhen.css">
|
||
<style>
|
||
/* 全頁定寬定字以確保一致:Noto Sans CJK,20px/行高 2.2。各文本框寬度經 headless
|
||
校準,配此字型可穩定重現所述效果(換字型時斷行點略異,效果方向不變)。 */
|
||
html { font: 20px/2.2 "Noto Sans CJK SC", "Noto Sans SC", "Noto Sans CJK TC", "Noto Sans TC", sans-serif; }
|
||
body { max-width: 64em; margin: 2rem auto; padding: 0 1.2rem; color: #1a1a1a; }
|
||
.juzhen:lang(zh-Hant), .juzhen [lang]:lang(zh-Hant) { font-family: "Noto Sans CJK TC", "Noto Sans TC", sans-serif; }
|
||
|
||
h1 { font-size: 1.5rem; }
|
||
h2 { font-size: 1.15rem; margin: 2.2rem 0 .3rem; color: #036; border-bottom: 1px solid #e0e0e0; padding-bottom: .2rem; }
|
||
h3 { font-size: .98rem; margin: 1.2rem 0 .3rem; color: #225; }
|
||
p.lede, p.hint { color: #555; font-size: .82rem; line-height: 1.7; }
|
||
p.lede { font-size: .9rem; color: #333; }
|
||
.look { color: #a0522d; font-size: .8rem; margin: .2rem 0 .5rem; }
|
||
.look::before { content: "看點 "; font-weight: bold; }
|
||
.note { background: #fff8e6; border: 1px solid #e8d8a0; border-radius: 4px; padding: .5rem .8rem; font-size: .82rem; color: #6a5400; line-height: 1.7; }
|
||
code { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: .85em; background: rgba(0,0,0,.05); padding: 0 .25em; border-radius: 3px; }
|
||
|
||
.toolbar { position: sticky; top: 0; z-index: 9; background: #fff; border-bottom: 1px solid #ddd; padding: .5rem 0; margin-bottom: 1rem; font-size: .82rem; }
|
||
.toolbar label { margin-right: 1.2rem; cursor: pointer; white-space: nowrap; }
|
||
|
||
/* 對照網格:左右並排兩框。 */
|
||
.cmp { display: flex; flex-wrap: wrap; gap: 1.4rem; align-items: flex-start; margin: .4rem 0 .6rem; }
|
||
.cell { font-size: .8rem; color: #444; }
|
||
.cell .tag { display: inline-block; font-weight: bold; margin-bottom: .25rem; }
|
||
.tag.on { color: #1a7f37; } .tag.off { color: #b04; } .tag.warn { color: #a60; }
|
||
|
||
/* 定寬文本框(不可拖動,確保一致)。寬度由各框 inline style 給定。 */
|
||
.box { border: 1px solid #bbb; border-radius: 4px; padding: .45rem .6rem; background: #fafafa; }
|
||
.box p { margin: 0; text-align: justify; }
|
||
|
||
/* 顯示標記(可由工具列切換)。 */
|
||
body.show-orphan jz-orphan { outline: 1px dashed rgba(170,30,170,.7); background: rgba(170,30,170,.08); }
|
||
body.show-gaps jz-hws { background: rgba(220,30,30,.12); outline: 1px solid rgba(220,30,30,.4); }
|
||
body.show-half jz-char.jz-half jz-inner, body.show-half jz-char.jz-half-le jz-inner { background: rgba(30,90,220,.14); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>聚珍 — 新功能效果演示(定寬對照)</h1>
|
||
<p class="lede">本頁以<strong>定寬文本框</strong>(不可拖動)並排對照,逐場景展示兩項新功能:<strong>功能分級</strong>(文本級/段落級)、<strong>垂懸字避免</strong>(<code>orphan</code>)。各框寬度經 headless 校準,配 Noto Sans CJK 可穩定重現所述效果。勾選下方開關可描出聚珍注入之結構(紫=垂懸字綁定、紅=中西間隙、藍=半形標點)。第三項曾規劃之「標點懸掛」經實測為機制級死路、已移除,說明見文末。</p>
|
||
|
||
<div class="toolbar">
|
||
<label><input type="checkbox" id="t-orphan"> 顯示垂懸字綁定(紫 <code>jz-orphan</code>)</label>
|
||
<label><input type="checkbox" id="t-gaps"> 顯示中西間隙(紅 <code>jz-hws</code>)</label>
|
||
<label><input type="checkbox" id="t-half"> 顯示半形標點(藍)</label>
|
||
</div>
|
||
|
||
<!-- ===================== 一、功能分級 ===================== -->
|
||
<h2>一、功能分級:文本級 vs 段落級</h2>
|
||
<p class="hint">功能分兩級——<strong>文本級</strong>(中西間隙 <code>spacing</code>、標點擠壓 <code>jiya</code>)僅依字符鄰接,<strong>任意文本片段</strong>(標題、按鈕、單行)皆適用;<strong>段落級</strong>(禁則 <code>jinze</code>、垂懸字 <code>orphan</code>、長詞 <code>longWord</code>)依賴行/段布局。塊級元素預設全功能;標 <code>data-jz-level="text"</code> 之子樹(或選項 <code>level:{text:"選擇器"}</code>)僅跑文本級。</p>
|
||
|
||
<div>
|
||
<h3>標題標為文本級(仍有間隙與半形,但不參與禁則/垂懸字)</h3>
|
||
<div class="cmp">
|
||
<div class="cell"><span class="tag on">data-jz-level="text"(標題典型)</span>
|
||
<div class="box s-std" style="width:16em"><h3 data-jz-level="text" lang="zh-Hant" style="margin:0;font:inherit;color:inherit">用 Neovim 寫程式(v0.10)真的很順手。</h3></div>
|
||
<p class="look">中西間隙(<code>Neovim</code>/<code>v0.10</code> 兩側)與標點半形照常;但此子樹<strong>不</strong>跑垂懸字/禁則(無 <code>jz-orphan</code>/<code>jz-jinze</code>)。</p>
|
||
</div>
|
||
<div class="cell"><span class="tag off">預設段落級(同內容,作正文)</span>
|
||
<div class="box s-std" style="width:16em"><p lang="zh-Hant">用 Neovim 寫程式(v0.10)真的很順手。</p></div>
|
||
<p class="look">同樣有間隙與半形,但<strong>另含</strong>禁則綁定與垂懸字(開啟「顯示垂懸字綁定」可見紫框)。</p>
|
||
</div>
|
||
</div>
|
||
<p class="hint">即:把標題/按鈕標為文本級——要中西間隙與標點半形、不要避孤字/避頭尾(那些對單行無意義)。</p>
|
||
</div>
|
||
|
||
<!-- ===================== 二、垂懸字避免 ===================== -->
|
||
<h2>二、垂懸字避免(<code>orphan</code>,方案 C)</h2>
|
||
<p class="hint">保證段末行 CJK <strong>實義字數 ≥ N</strong>(預設 2;標點/符號不計)。機制:把段末「第 N 個實義字起至段末」(含尾隨標點)包入 <code>jz-orphan</code>(<code>white-space:nowrap</code>)成不可斷整體 → 末行恒含之 ⇒ 末行實義字 ≥ N,<strong>無需量測版面</strong>、任意寬度成立。<strong>預設開</strong>。</p>
|
||
|
||
<div>
|
||
<h3>關閉 vs 開啟(同寬同文:末行從「孤字」變為保留兩字)</h3>
|
||
<div class="cmp">
|
||
<div class="cell"><span class="tag off">orphan 關閉(<code>data-juzhen-off="orphan"</code>)</span>
|
||
<div class="box s-std" style="width:14em"><p lang="zh-Hant" data-juzhen-off="orphan">春天來了萬物復甦大地生機盎然處處鳥語花香令人神往心曠神怡。</p></div>
|
||
<p class="look">末行僅剩孤字「<strong>怡。</strong>」——單字垂懸,版面失衡。</p>
|
||
</div>
|
||
<div class="cell"><span class="tag on">orphan 開啟(預設 chars=2)</span>
|
||
<div class="box s-std" style="width:14em"><p lang="zh-Hant">春天來了萬物復甦大地生機盎然處處鳥語花香令人神往心曠神怡。</p></div>
|
||
<p class="look">末行保留「<strong>神怡。</strong>」兩個實義字(開「顯示垂懸字綁定」見紫框=被綁之尾段)。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>調整保留字數(<code>orphan:{ chars: 3 }</code>)</h3>
|
||
<div class="cmp">
|
||
<div class="cell"><span class="tag on">chars = 3(同前文、同寬 14em)</span>
|
||
<div class="box s-chars3" style="width:14em"><p lang="zh-Hant">春天來了萬物復甦大地生機盎然處處鳥語花香令人神往心曠神怡。</p></div>
|
||
<p class="look">末行保留「<strong>曠神怡。</strong>」三個實義字(較預設 chars=2 之「神怡。」多拉一字下來)。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>標點/符號不計入字數(句末多個標點不佔 N)</h3>
|
||
<div class="cmp">
|
||
<div class="cell"><span class="tag off">orphan 關閉</span>
|
||
<div class="box s-std" style="width:14em"><p lang="zh-Hant" data-juzhen-off="orphan">他想了好久最後終於對著大家堅定地說出了那三個字「我願意」。</p></div>
|
||
<p class="look">末行=「<strong>意」。</strong>」——僅 <strong>1 個實義字</strong>(意),其後 <code>」。</code> 兩個標點<strong>不計入</strong>字數。</p>
|
||
</div>
|
||
<div class="cell"><span class="tag on">orphan 開啟(chars=2)</span>
|
||
<div class="box s-std" style="width:14em"><p lang="zh-Hant">他想了好久最後終於對著大家堅定地說出了那三個字「我願意」。</p></div>
|
||
<p class="look">末行=「<strong>願意」。</strong>」——保 <strong>2 個實義字</strong>(願意);尾隨 <code>」。</code> 隨尾段綁入但不佔 N(開紫框見綁定範圍含標點,且整個 <code>「我願意」</code> 禁則群組跨 <code>jz-jinze</code> 不被切割)。</p>
|
||
</div>
|
||
</div>
|
||
<p class="hint">邊界:段落實義字 < N(或單行段)→ 不綁、無副作用。極窄容器(<N 字寬)→ 該尾段可能溢出(罕見)。</p>
|
||
</div>
|
||
|
||
<!-- ===================== 三、標點懸掛(已移除) ===================== -->
|
||
<h2>三、標點懸掛(<code>hanging</code>)— 已移除</h2>
|
||
<p class="note">原計劃之標點懸掛(行端標點凸出版心)經 headless + 真實瀏覽器實測確認為<strong>機制級死路</strong>,已<strong>移除</strong>(負 <code>margin</code> 程式碼與 CSS 皆刪;<code>hanging</code> 選項保留為 no-op,無任何效果)。<strong>寬度守恆矛盾</strong>:行端標點盒若保持非零寬,墨色出去多少、版心內就空出多少(行末實義字無法齊版心右緣);若收為零寬,釋放一整字寬、斷行器把下一字拉上本行與標點重疊(且 <code>justifyAtoms</code> 預設之 inline-block 下負 margin 被 justify 吸收)。<strong>CSS hack 接觸不到斷行器,此恒等式無解。</strong>唯一正解為原生 CSS <code>hanging-punctuation</code>,惟 Chrome/Firefox 至今不支援(僅 Safari),且本庫 <code>jz-char</code> 為 inline-block 原子非文本、原生懸掛不作用之——未來若做須是繞開 jz-char 的「原生管線」新功能。詳見 <code>ARCHITECTURE.md §6.5.6</code>。</p>
|
||
|
||
<footer style="margin-top:2.4rem;color:#888;font-size:.78rem;border-top:1px solid #eee;padding-top:.6rem">
|
||
聚珍(Juzhen)· 新功能效果演示。另見 <a href="./resize-check.html">resize-check.html</a>(可拖動容器之穩定性檢查)。寬度配 Noto Sans CJK 校準;換字型時斷行點略異,效果方向不變。
|
||
</footer>
|
||
|
||
<script src="../dist/juzhen.iife.js"></script>
|
||
<script>
|
||
// 各場景以獨立實例 + **逐框 render(該框)** 渲染:屬性就近設於各框、由 CSS 後代選擇器
|
||
// 隔離(若 render(body) 則屬性落 body、跨框互相污染)。一致性:定寬 + 固定配置 + 同字型。
|
||
function renderEach(selector, opts)
|
||
{
|
||
var jz = Juzhen.createJuzhen(opts);
|
||
document.querySelectorAll(selector).forEach(function (el) { jz.render(el); });
|
||
}
|
||
|
||
// 功能分級+垂懸字(預設 orphan chars=2):繁全角/簡開明。
|
||
renderEach(".s-std", { lang: { policy: { "zh-Hant": "quanjiao", "zh-Hans": "kaiming" } } });
|
||
|
||
// 垂懸字 chars=3。
|
||
renderEach(".s-chars3", { lang: { default: "zh-Hant", style: "quanjiao" }, orphan: { chars: 3 } });
|
||
|
||
// 工具列開關。
|
||
var toggles = { "t-orphan": "show-orphan", "t-gaps": "show-gaps", "t-half": "show-half" };
|
||
Object.keys(toggles).forEach(function (id) {
|
||
var cb = document.getElementById(id);
|
||
if (cb.checked) { document.body.classList.add(toggles[id]); }
|
||
cb.addEventListener("change", function (e) {
|
||
document.body.classList.toggle(toggles[id], e.target.checked);
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|