demo: 功能分級+垂懸字效果演示(showcase 定寬對照 + resize-check)
新增 demo/showcase.html:定寬文本框並排對照,逐場景演示功能分級(標題標 data-jz-level=text 僅文本級)與垂懸字(關閉/開啟孤字對照、chars=3、標點不計入 N),工具列描出 jz-orphan/ 中西間隙/半形標點;附「標點懸掛已停用」說明節。逐框 render(該框) 隔離屬性。 resize-check.html:增垂懸字(orphan)拖曳檢查+關閉對照。標點懸掛已停用,兩頁均不含懸掛。
This commit is contained in:
+15
-1
@@ -33,6 +33,9 @@
|
|||||||
body.show-gaps jz-hws.jz-hws-trim { outline-color: rgba(30,120,220,.5); background: rgba(30,120,220,.06); }
|
body.show-gaps jz-hws.jz-hws-trim { outline-color: rgba(30,120,220,.5); background: rgba(30,120,220,.06); }
|
||||||
body.show-gaps code { background: rgba(0,0,0,.06); }
|
body.show-gaps code { background: rgba(0,0,0,.06); }
|
||||||
code { font-family: ui-monospace, Menlo, Consolas, monospace; }
|
code { font-family: ui-monospace, Menlo, Consolas, monospace; }
|
||||||
|
|
||||||
|
/* 顯示垂懸字綁定範圍(jz-orphan:段末不可斷之尾段)。 */
|
||||||
|
body.show-orphan jz-orphan { outline: 1px dashed rgba(180,30,180,.6); background: rgba(180,30,180,.07); }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -42,6 +45,7 @@
|
|||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<label><input type="checkbox" id="t-justify"> 兩端對齊 justify</label>
|
<label><input type="checkbox" id="t-justify"> 兩端對齊 justify</label>
|
||||||
<label><input type="checkbox" id="t-gaps"> 顯示間隙(紅=有隙 jz-hws,藍=已去隙 trim)</label>
|
<label><input type="checkbox" id="t-gaps"> 顯示間隙(紅=有隙 jz-hws,藍=已去隙 trim)</label>
|
||||||
|
<label><input type="checkbox" id="t-orphan"> 顯示垂懸字綁定(紫=jz-orphan 尾段)</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>E 中西混排(重點:拖動時「最後一個間隙」不應消失、標點不應緊貼)</h2>
|
<h2>E 中西混排(重點:拖動時「最後一個間隙」不應消失、標點不應緊貼)</h2>
|
||||||
@@ -64,10 +68,16 @@
|
|||||||
<h2>對照:簡體內容(zh-Hans 字形與標點)</h2>
|
<h2>對照:簡體內容(zh-Hans 字形與標點)</h2>
|
||||||
<div class="box juzhen" lang="zh-Hans" style="width:24em"><p>这是简体测试,包含 Python 与 €99;引号“示例”和标点,;:。混排间隙与标点均应正确。</p></div>
|
<div class="box juzhen" lang="zh-Hans" style="width:24em"><p>这是简体测试,包含 Python 与 €99;引号“示例”和标点,;:。混排间隙与标点均应正确。</p></div>
|
||||||
|
|
||||||
|
<h2>垂懸字避免(重點:拖窄時,段末行 CJK 實義字恒 ≥ 2,標點不計)</h2>
|
||||||
|
<p class="hint">慢慢拖窄方框,使最後一行將塌為單字;垂懸字(方案 C)會把段末末二實義字+尾隨標點綁為不可斷之 <code>jz-orphan</code>(勾選上方「顯示垂懸字綁定」描出紫框),故末行恒含 ≥2 字。對照組關閉 orphan,可能出現孤字末行。</p>
|
||||||
|
<div class="box juzhen" lang="zh-Hant" style="width:14em"><p>這是一段用於檢查垂懸字避免的測試文字,拖窄後觀察段末行是否恒保留至少兩個實義字而不孤零。</p></div>
|
||||||
|
<p class="hint">對照(orphan 關閉,<code>data-juzhen-off="orphan"</code>):</p>
|
||||||
|
<div class="box juzhen" lang="zh-Hant" style="width:14em" data-juzhen-off="orphan"><p>這是一段用於檢查垂懸字避免的測試文字,拖窄後觀察段末行是否恒保留至少兩個實義字而不孤零。</p></div>
|
||||||
|
|
||||||
<script src="../dist/juzhen.iife.js"></script>
|
<script src="../dist/juzhen.iife.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// 全頁一次渲染(quanjiao 全角式,與下游回饋之政策一致);各框由其 lang 屬性
|
// 全頁一次渲染(quanjiao 全角式,與下游回饋之政策一致);各框由其 lang 屬性
|
||||||
// 驅動簡/繁字形。
|
// 驅動簡/繁字形。(標點懸掛已停用,見 ARCHITECTURE §6.5.6。)
|
||||||
Juzhen.createJuzhen({ scope: { include: ".juzhen" }, lang: { style: "quanjiao" } })
|
Juzhen.createJuzhen({ scope: { include: ".juzhen" }, lang: { style: "quanjiao" } })
|
||||||
.render(document.body);
|
.render(document.body);
|
||||||
|
|
||||||
@@ -79,6 +89,10 @@
|
|||||||
{
|
{
|
||||||
document.body.classList.toggle("show-gaps", e.target.checked);
|
document.body.classList.toggle("show-gaps", e.target.checked);
|
||||||
});
|
});
|
||||||
|
document.getElementById("t-orphan").addEventListener("change", function (e)
|
||||||
|
{
|
||||||
|
document.body.classList.toggle("show-orphan", e.target.checked);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
<!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>hanging</code> 選項仍被接受但無任何效果)。原因:純負 <code>margin</code> 機制下,句號墨色偏字框左下角,安全凸出量(< 1em)只把空白半框推出版心、墨色仍在內(視覺不懸掛);凸出滿 1em 又釋放一整字寬、把下一字拉上本行致重疊;且 <code>ResizeObserver</code> 重排時標記錯亂。真正的解是原生 CSS <code>hanging-punctuation</code>,惟 Chrome 至今不支援、且與本庫 inline-block 對齊原子結構衝突。程式碼與 CSS 保留休眠,俟原生支援成熟再議。詳見 <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>
|
||||||
Reference in New Issue
Block a user