{"id":50913223,"url":"https://github.com/p4suta/jp-typeset","last_synced_at":"2026-06-16T12:02:42.641Z","repository":{"id":361464294,"uuid":"1254540530","full_name":"P4suta/jp-typeset","owner":"P4suta","description":"日本語Web組版のドロップインCSSプリセット — 禁則・約物アキ詰め・和欧間アキ・文頭字下げ・両端揃え・ぶら下げ・文節改行・ルビ・圏点・ブロック引用を \u003clink\u003e 一発で","archived":false,"fork":false,"pushed_at":"2026-05-30T18:23:45.000Z","size":1165,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-30T20:10:52.404Z","etag":null,"topics":["cjk","css","dropin","japanese","japanese-typography","jlreq","kinsoku","typesetting","typography","web-typography"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/P4suta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-30T17:39:55.000Z","updated_at":"2026-05-30T18:23:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/P4suta/jp-typeset","commit_stats":null,"previous_names":["p4suta/jp-typeset"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/P4suta/jp-typeset","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P4suta%2Fjp-typeset","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P4suta%2Fjp-typeset/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P4suta%2Fjp-typeset/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P4suta%2Fjp-typeset/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/P4suta","download_url":"https://codeload.github.com/P4suta/jp-typeset/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/P4suta%2Fjp-typeset/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34404748,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cjk","css","dropin","japanese","japanese-typography","jlreq","kinsoku","typesetting","typography","web-typography"],"created_at":"2026-06-16T12:02:41.611Z","updated_at":"2026-06-16T12:02:42.626Z","avatar_url":"https://github.com/P4suta.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jp-typeset\n\n[![CI](https://github.com/P4suta/jp-typeset/actions/workflows/ci.yml/badge.svg)](https://github.com/P4suta/jp-typeset/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](./LICENSE)\n\n日本語Web組版の「標準的な書き方の規則」を、最新の CSS だけで実現するドロップインCSSプリセット。\n`\u003clink\u003e` 一発で、**文頭字下げ・禁則処理・約物のアキ詰め・和欧間アキ・両端揃え・ぶら下げ・文節改行・ルビ・圏点(傍点)**が効く。\n\nスクラッチの組版エンジンではない。意見を持った1枚の CSS を、対応ブラウザに素直に流し込むだけ。\n未対応の機能は無視されても本文を壊さず、ブラウザが対応すれば自動でよくなる(`@supports` による段階強化)。\n\n\u003e [!NOTE]\n\u003e 標準のセマンティックHTMLだけを対象にする独立したCSSであり、特定の記法やフレームワークには依存しない。\n\u003e 横書きを既定とし、**縦書き・縦中横はオプトインのユーティリティ**で対応する。\n\u003e ページ組版(`@page`)・原稿用紙のマス目グリッドは**対象外**。段組など汎用レイアウトは標準CSSで(プリセットは日本語テキスト組版に集中)。\n\n## クイックスタート\n\n### CDN(貼るだけ)\n\n```html\n\u003chtml lang=\"ja\"\u003e\n  \u003chead\u003e\n    \u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/jp-typeset/dist/jp-typeset.min.css\" /\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cp\u003e吾輩は猫である。名前はまだ無い。\u003c/p\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n### npm\n\n```sh\npnpm add jp-typeset\n```\n\n```css\n@import \"jp-typeset\"; /* または \"jp-typeset/min\" */\n```\n\n## 適用範囲\n\n`lang=\"ja\"` が付いた要素に**自動適用**される。明示的に効かせたいときは `class=\"jp\"` を付ける。\n\n```html\n\u003carticle lang=\"ja\"\u003e…\u003c/article\u003e\n\u003cdiv class=\"jp\"\u003e…\u003c/div\u003e\n```\n\nすべてのルールは `:where()` で**詳細度ゼロ**に書かれているので、利用者側の CSS で何も考えず上書きできる。\n\n## 何をするか\n\n| 機能                                 | プロパティ                             | ネイティブ対応(2026)   |\n| ------------------------------------ | -------------------------------------- | ---------------------- |\n| 禁則処理(行頭・行末)                 | `line-break: strict`                   | 全エンジン             |\n| 和文の折り返し                       | `word-break: normal` + `overflow-wrap` | 全エンジン             |\n| 和欧間アキ・和数アキ                 | `text-autospace: normal`               | 全4エンジン(2025-11〜) |\n| 文頭字下げ(段落)                     | `text-indent`                          | 全エンジン             |\n| ルビ(ふりがな)                       | 標準の `\u003cruby\u003e` / `\u003crt\u003e`               | 全エンジン             |\n| 強調を圏点(傍点)で                   | `\u003cem\u003e` → `text-emphasis`               | 全エンジン             |\n| ブロック引用(和文の字下げ作法)       | `blockquote` 字下げ(左罫線なし)        | 全エンジン             |\n| 両端揃え・行間                       | `text-align: justify` / `line-height`  | 全エンジン             |\n| 約物のアキ詰め・行頭開き括弧の半角化 | `text-spacing-trim`                    | Chromium のみ          |\n| ぶら下げ組                           | `hanging-punctuation`                  | Safari のみ            |\n| 文節での自然改行                     | `word-break: auto-phrase`              | Chromium のみ          |\n| 均等割り                             | `text-justify: inter-character`        | Safari 以外            |\n| 行末処理(末行の孤立防止・見出し均等) | `text-wrap: pretty` / `balance`        | Chromium / Safari      |\n| 見出しの前後アキ                     | `margin-block` (JLReq §4.1.3)          | 全エンジン             |\n| 添え字(行送りを乱さない)             | `sub` / `sup`                          | 全エンジン             |\n\n下4つは `@supports` で段階強化しているため、対応エンジンでのみ有効になる。\n文節改行(`word-break: auto-phrase`)は見出し・短文にのみ適用する(本文全体への適用は Chrome 公式も非推奨)。\n均等割り(`text-justify: inter-character`)は英数字を多く含む行で字間が広がることがある。\nエンジン差のある**約物詰め・ぶら下げ・文節改行**は、任意の JS 層で非対応ブラウザも補える(下記「ブラウザ差を埋める JS」)。\n\n\u003e [!TIP]\n\u003e 約物のアキ詰め(`text-spacing-trim`)は、`halt`/`chws` を持つフォント(Noto Sans CJK / 源ノ角ゴシック等)でのみ効く。\n\u003e プリセットはフォントを強制しない。`--jp-font-family` で推奨フォントを指定できる。\n\n\u003e [!NOTE]\n\u003e `text-autospace`(和欧アキ)は Chromium / Firefox では正しく描画されるが、**一部の WebKit ビルドではアキ挿入時にグリフの送り(advance)が壊れ文字が重なる**既知の上流バグがある(CSS の値変更では回避不可。Playwright の WebKit-Linux ビルドで再現)。仕様準拠かつ大多数のエンジンで正しいため base に置いている。\n\n## 強調と引用(和文の作法)\n\n和文の強調は欧文(bold/italic)と発想が違う。本プリセットは `\u003cem\u003e` を**斜体ではなく圏点(ゴマ点)**で強調する(`text-emphasis`)。和文では斜体を使わないため、`em`/`i`/`cite`/`dfn` の擬似斜体も解除する。\n\n\u003e [!NOTE]\n\u003e 「明朝本文→ゴシックで強調」という書体変更も和文の伝統的な強調手段だが、これを確実に出すには具体的なフォント名の指定が必要(総称ファミリでの明朝/ゴシックの出し分けはブラウザ・OS依存で、特に Chromium-on-Linux では効かない)。本プリセットは具体フォントを同梱しない方針のため、書体変更による強調は提供しない。必要な場合は利用側で書体を指定する。\n\n**ブロック引用**は和文の字下げ作法に寄せている。左を全角2字下げ＋前後アキとし、欧文的な左の縦罫線・斜体・鍵括弧は付けない(字下げ自体が引用の合図)。`--jp-quote-indent` / `--jp-quote-gap` で調整できる。\n\n## Markdown / GFM との相性\n\n標準のセマンティックHTMLを対象にしているため、Markdown(GitHub Flavored Markdown)から生成した\nHTML にもそのまま効く。見出し・段落・リスト・引用・表・強調・取り消し線・リンク・タスクリストなどに\n和文の組版が適用される。`demo/gfm.html` が一通りの GFM 要素を日本語で並べた見本。\n\n\u003e [!IMPORTANT]\n\u003e **コード(`code` / `pre` / `kbd` / `samp`)は等幅を保ち、和欧間アキも入れない**(和文の文字組みを持ち込まない)。\n\u003e Markdown のコードブロック・インラインコードがプリセットで等幅でなくなることはない。\n\n## ユーティリティ(縦書き・縦中横・行長)\n\nオプトインのクラス。付けた要素にだけ効く。\n\n| クラス         | 効果                                                                                                                                                        |\n| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `.jp-vertical` | 縦書き(`writing-mode: vertical-rl`)。論理プロパティ基盤なので禁則・字下げ・両端揃え・ぶら下げ・ルビ・圏点がそのまま縦組みに移行する。表示には高さを与える。 |\n| `.jp-tcy`      | 縦中横。縦組み中の半角数字・欧字を1文字幅で横に並べる(`text-combine-upright: all`)。例: `\u003cspan class=\"jp-tcy\"\u003e12\u003c/span\u003e月`                                  |\n| `.jp-measure`  | 読みやすい行長に制限して中央寄せ(`--jp-measure`、既定 全角およそ40字)。                                                                                     |\n\n```html\n\u003carticle class=\"jp-vertical\" lang=\"ja\" style=\"block-size: 20em\"\u003e\n  \u003cp\u003e本文…\u003cspan class=\"jp-tcy\"\u003e2026\u003c/span\u003e年…\u003c/p\u003e\n\u003c/article\u003e\n```\n\n## カスタマイズ(デザイントークン)\n\n調整可能な値はすべてカスタムプロパティに集約されている。上書きするだけで全体を調律できる。\n\n```css\n:root {\n  --jp-indent: 1em; /* 文頭字下げの量 */\n  --jp-leading: 1.8; /* 行間 */\n  --jp-paragraph-gap: 0; /* 段落間アキ(既定は字下げで段落を示す) */\n  --jp-text-align: justify; /* 本文の行揃え */\n  --jp-font-family: inherit; /* 推奨和文フォント(既定は強制しない) */\n  --jp-mono: monospace; /* コード(等幅)要素のフォント */\n  --jp-rt-scale: 0.5em; /* ルビ文字の大きさ */\n  --jp-rt-leading: 1; /* ルビの行送り */\n  --jp-emphasis: filled sesame; /* 圏点(傍点)のスタイル */\n  --jp-quote-indent: 2em; /* ブロック引用の字下げ(全角2字) */\n  --jp-quote-gap: 1em; /* ブロック引用の前後アキ */\n  --jp-heading-margin-block: 1.5em 0.5em; /* 見出しの前後アキ(前 後) */\n  --jp-measure: 40em; /* .jp-measure の行長 */\n}\n```\n\n## ブラウザ差を埋める JS(`jp-typeset/enhance`)\n\nCSS だけでは全ブラウザで揃わない項目(文節改行・ぶら下げ・約物のアキ詰め)を、**任意の JS 層**で補える。\n各機能は `CSS.supports()` で対応を判定し、**ネイティブ対応があれば何もしない**(対応が来たら自動で消えるブリッジ)。\nCSS コア(`import \"jp-typeset\"`)は実行時依存ゼロのまま。この層と BudouX 依存は `jp-typeset/enhance` だけが背負う。\n\n### 使い方\n\nCDN なら CSS の `\u003clink\u003e` に `\u003cscript\u003e` を1行足すだけ(`lang=\"ja\"`/`.jp` を自動強化):\n\n```html\n\u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/jp-typeset/dist/jp-typeset.min.css\" /\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/jp-typeset/dist/enhance.iife.js\" defer\u003e\u003c/script\u003e\n```\n\nバンドラなら ESM を明示的に呼ぶ(tree-shakeable):\n\n```js\nimport { enhance } from \"jp-typeset/enhance\";\n\nenhance(); // 既定は文節改行のみ。SPA の再描画後に呼び直してもよい(冪等)\nenhance(document, { hanging: true, spacingTrim: true }); // 実験ブリッジを追加\n```\n\n### できること\n\n| オプション          | 既定 | 内容                                              | ネイティブ対応(no-op になる条件) |\n| ------------------- | ---- | ------------------------------------------------- | -------------------------------- |\n| `phrasing`          | on   | BudouX で見出し・短文を文節改行(`\u003cwbr\u003e` を挿入)   | `word-break: auto-phrase`        |\n| `dialogueIndent`    | off  | 始め括弧で始まる段落の先頭字下げを詰める          | (CSS に等価なし・opt-in)         |\n| `hanging`(実験)     | off  | ぶら下げ組(行頭開き括弧・行末句読点を版面外へ)    | `hanging-punctuation: first`     |\n| `spacingTrim`(実験) | off  | 連続する全角約物のアキを詰める                    | `text-spacing-trim`              |\n| `observe`           | off  | layout 依存ブリッジ(ぶら下げ)を resize 時に再適用 | —                                |\n\n- **旗艦は文節改行**。`word-break: auto-phrase` 非対応の Safari / Firefox でも、見出しが意味のまとまりで折れる。本文(`p`)には当てない(CSS と同じスコープ)。\n- 区切りは不可視の `\u003cwbr\u003e` を使うので、コピー\u0026ペースト・スクリーンリーダー・検索を汚さない。ルビ・圏点などインライン要素も壊さない。\n- **実験**印の `hanging` / `spacingTrim` は layout 測定やフォント依存の近似を含むため既定 OFF。行末ぶら下げ(allow-end)は reflow で崩れるので `observe: true` で再計測できる。\n- 文節改行は冪等(`\u003cwbr\u003e` を二重に挿さない)。`dialogueIndent` を既定 OFF にするのは、CSS 側の「会話文も一律に字下げ」という意図的な判断を尊重するため。\n- **縦書き(`.jp-vertical`)でも全ブリッジが動く**。挿入する余白はすべて論理プロパティ(`margin-inline-*` / `text-indent`)で、ぶら下げの行末判定だけは `writing-mode` を見て軸を切り替える(縦組みは「列の下端」が行末)。文節改行・ぶら下げ・約物詰め・字下げがそのまま縦組みへ適応する。\n\n\u003e [!NOTE]\n\u003e CDN 版(`enhance.iife.js`)は BudouX と日本語モデルを内包する単一ファイル(およそ 145KB gzip)。\n\u003e npm/ESM 版は `budoux` を外部依存とし動的 import するため、**ネイティブ対応ブラウザではモデルを一切読み込まない**。\n\n## 開発\n\nすべての作業は Docker コンテナ内(非root・UID/GID 1000)で完結し、ホストを汚さない。\nホストに必要なのは **docker** だけ。タスクはホストの薄いラッパー `./x` から呼ぶ(中身は `just`)。\n\n```sh\ndocker compose build      # 開発イメージをビルド(初回のみ)\n./x install               # 依存インストール\n./x fix                   # 自動修正(stylelint --fix / biome / prettier / typos)\n./x check                 # 一括検証(lint → fmt → typecheck → typos → build → test)\n./x dev                   # 開発サーバ → http://localhost:5173/demo/\n./x hooks                 # コミット時に自動修正する git フックを設置\n```\n\n`./x` 無しで直接叩く場合は `docker compose run --rm dev just \u003crecipe\u003e`。\n\n### ツールチェーン\n\npnpm / [Lightning CSS](https://lightningcss.dev/)(ビルド) / Vite(開発サーバ) /\nStylelint + Biome(lint・整形) / Prettier(整形) / [typos](https://github.com/crate-ci/typos)(誤字) /\n[just](https://github.com/casey/just)(タスク) / Playwright(3エンジンのテスト) / lefthook(自動修正フック)。\n\n### 検証について\n\n`./x check` が確かめるのは **CSS の規律・構文・宣言の適用**(Stylelint・ビルド・computed-style テスト)であり、\n**組版の視覚的な美しさそのものではない**。視覚回帰(`tests/visual.spec.ts`)は「変わったかどうか」を検出するが、\n基準画像が「組版として正しいか」の最終判断はブラウザ(特に Chromium / Safari)での人手目視が必要。\n\n視覚回帰の基準画像はレンダリング環境(エンジン・フォント)に依存する。基準は Docker イメージ(Noto CJK 同梱)で生成しており、\n環境やフォントが変わって差分が出たら `./x test-update` で再生成する。決定論的な検証は computed-style テスト側が担う。\n\nJS ブリッジ層(`jp-typeset/enhance`)も同じ2層で検証する。**決定論層** `tests/enhance.spec.ts` が、\nページ内 `CSS.supports` を基準にした no-op/ゲート・`\u003cwbr\u003e` 挿入・冪等・非破壊・IIFE 成果物に内包した\nBudouX の実動作を3エンジンでアサートし(`ci:gate` に含む)、**視覚回帰層** `tests/enhance.visual.spec.ts` が\n文節改行・字下げ・ぶら下げ・約物詰めを固定狭幅で撮る(`test:visual`・非ゲート)。`./x dev` で\n`demo/enhance-esm.html` / `demo/enhance-iife.html` を各ブラウザで目視できる。\n\n### Playwright のバージョン\n\n`@playwright/test` は Docker イメージ(`mcr.microsoft.com/playwright:vX.Y.Z-noble`)に同梱されるブラウザと\nバージョンを一致させる必要がある。両者は同時に更新すること(`package.json` と `Dockerfile`)。\n\n## 今後(スコープ外)\n\n- 行末ぶら下げ(`hanging-punctuation` の allow-end)の忠実な JS polyfill。現状は best-effort の実験オプション\n  (`enhance({ hanging })`)に留め、行ごとの再計測が要る完全実装は見送り(ネイティブに委ねる)。\n- 縦書き本文への JS ブリッジ、ページ組版(`@page`)など(明確にスコープ外)。\n\n## ライセンス\n\n[MIT](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp4suta%2Fjp-typeset","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fp4suta%2Fjp-typeset","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp4suta%2Fjp-typeset/lists"}