zudo-paper

Markdownの太字が日本語の句読点の隣で効かない問題とremark-cjk-friendlyによる解決

Author: Takazudo | 作成: 2026/04/13

概要

Markdownで **太字** と書いたのに太字にならない、という現象がある。日本語の文章で句読点のすぐ隣に太字を置いたときに起きる。CommonMarkの仕様に起因する問題で、remark-cjk-friendly というプラグインで解決できる。そのまとめ。

問題の具体例

こういうMarkdownを書いたとする。

これは**重要な点。**続きのテキスト
テスト**「該当箇所」**を確認する

レンダリング結果では太字にならず、** がそのまま表示されてしまう。句読点や括弧がボールドの区切り文字 ** のすぐ内側にあり、かつその外側にCJK文字が続いている場合に起きる。

英語では単語間にスペースがあるので、この問題が起きにくい。This is **important.** Next sentence でも太字になる。日本語はスペースなしで文字が続くため、条件に引っかかりやすい。

CommonMarkの仕様: flanking delimiter run

CommonMarkという仕様がある。Markdownのパース方法を定義した仕様で、GitHubやremark(Astroが内部で使うMarkdownパーサー)はこれに準拠している。

CommonMark仕様のSection 6.2に「flanking delimiter run(区切り文字ランの隣接ルール)」というルールがある。** が太字の開始として認識されるには「left-flanking delimiter run」でなければならない、というルールだ。

left-flanking delimiter runの条件はこう。

  1. 直後が空白文字ではない
  2. かつ、直後が句読点文字(Unicode一般カテゴリ P・S)の場合は、直前が空白文字または句読点文字であること

right-flanking delimiter runも同様の条件がある。

なぜ日本語で問題が起きるか

(U+3002、句点)や (U+300C)、(U+300D)などはUnicodeの一般カテゴリが「P(Punctuation、句読点)」に分類されている。

これは**重要な点。**続きのテキスト を解析するとき、閉じの ** の直前に (句読点)がある。right-flanking delimiter runの条件として、直前が句読点の場合は直後が空白か句読点でなければならない。しかし ** の直後は (CJK文字)で、空白でも句読点でもないため、条件を満たせない。

結果として閉じの ** がright-flanking delimiter runとして認識されず、太字が閉じない。

同様に、開きの ** の直後に句読点がある場合も、left-flanking delimiter runの条件を満たせなくなる。

英語では単語間にスペースがあるので、** の外側にスペースが入り、flanking条件を満たしやすい。日本語はスペースなしで文字が続くため、句読点が ** の内側にあると条件に引っかかる。

CommonMarkのIssue

この問題はCommonMarkのIssueトラッカーでも議論されている。

CJK文字のような空白なし言語では、仕様の句読点ルールが意図しない動作を引き起こすという問題提起で、2017年から続いているIssue。仕様レベルでの対応はまだ行われていない。

影響を受ける文字の例

句読点カテゴリ(P・S)に該当するCJK文字で、よく文の前後に現れるもの:

  • (句点、U+3002)
  • (読点、U+3001)
  • (右隅付き括弧、U+300D)
  • (右白隅付き括弧、U+300F)
  • (全角右括弧、U+FF09)
  • (全角感嘆符、U+FF01)
  • (全角疑問符、U+FF1F)
  • (全角コロン、U+FF1A)

remark-cjk-friendly

remark-cjk-friendly というプラグインがある。remarkのプラグインで、CJK文字が隣接した場合でも ** が太字として認識されるようにパースを修正する。

インストール:

pnpm add remark-cjk-friendly

Astroの設定:

// astro.config.ts
import { defineConfig } from "astro/config";
import remarkCjkFriendly from "remark-cjk-friendly";

export default defineConfig({
  markdown: {
    remarkPlugins: [remarkCjkFriendly],
  },
});

これだけで、日本語の句読点に隣接した **text** が正しく太字としてレンダリングされるようになる。

余談

Markdownの太字の記法自体は何も変える必要がない。プラグインを追加するだけで既存の記事も含めて修正される。

ただ一点注意がある。このプラグインを入れると、今まで ** がそのまま表示されていた箇所が突然太字になる。意図せず ** を書いていた場所があれば表示が変わるので、適用後に確認するのが無難。