Markdown で文章を書いていると、句点 (。
) の後ろで 1 回だけ改行している状況があります。このとき、執筆者はこの改行がそのまま改行として解釈されて欲しいと感じていることでしょう。
しかし、改行を強制改行として解釈しない Markdown パーサでは、改行が半角スペースとなってしまいます。
本記事では、このような改行が改行として解釈されない原因と CSS による対応方法を紹介します。
Markdown における改行の処理
Markdown の仕様の 1 つである CommonMark では、パラグラフ内の改行は “Soft line breaks” と呼ばれる仕様に記載されています。
この Soft line breaks は、ソース内の改行や空白文字に関して以下のように規定します。
そのため、Markdown から HTML に変換されても、ソース内の改行がそのまま <p>
タグに入ってきます。(改行を分かりやすくするために、改行を ↵
としています)
吾輩は猫である。↵
名前はまだない。
⇓
<p>吾輩は猫である。↵
名前はまだない。</p>
では、HTML 内にある改行はどうして反映されないのでしょうか。
これは CSS の影響を受けるため です。
ちなみに、ソース内の改行が強制改行に解釈されるパーサ(例えば Qiita)では、改行位置で <br>
が挿入されるようになります。
すなわち、以下の HTML のように解釈されています。
<p>吾輩は猫である。<br>
名前はまだない。</p>
この場合、Markdown ソース内の改行は <br>
となるため、CSS に関わらず強制的に改行となります。
プロパティによる制御
white-space
は文章の折り返しや改行や空白文字等を制御するためのプロパティです。このプロパティを変更することでソース内の改行を改行として扱わせることが出来ます。
この white-space
は以下 6 つの値を採ります。
(white-space
は行末の空白文字に関する挙動も制御しますが、Markdown では行末の空白文字を強制改行または無視するため、ここでは省略しています)
折り返し | 連続する 空白文字 |
改行 | |
---|---|---|---|
normal (default) |
有 | まとめる | まとめる |
pre-line |
有 | まとめる | そのまま |
pre-wrap |
有 | そのまま | そのまま |
break-spaces |
有 | そのまま | そのまま |
nowrap |
無 | まとめる | まとめる |
pre |
無 | そのまま | そのまま |
※ 改行は “まとめる” となっていますが、まとめた上で半角スペースに置き替えられています。
これを踏まえると、改行が半角スペースとして置き替えられていた原因は、デフォルトの white-space: normal
となっていたからでした。
このプロパティを使って、<p>
タグ内の改行をそのまま出力するように構成すれば目標達成です。
今回、求めている white-space
の状態は、以下のような状態です。
- 折り返し ⇒ 有
- 連続する空白文字 ⇒ まとめる
- 改行 ⇒ そのまま
そのため、pre-line
がふさわしいでしょう。
もちろん、この処理は意図的に改行を改行として機能させるため、マンページのような特定の文字数で改行するような文章には不向きな構成になっていることに注意してください。
具体的な CSS の構成
<p>
タグの white-space
を pre-line
にすれば良いので、以下のように構成します。
p {
white-space: pre-line;
}
ここでは <p>
タグ内のみに影響します。そのため、<li>
や <blockquote>
タグ内には影響しない可能性があります。影響させたい場合は、適宜 CSS を編集する必要があります。
複数改行したいとき
Markdown ファイル内で複数回にわたる改行をした場合、どのような結果になるでしょうか。
例えば、以下のような状況です。
吾輩は猫である。↵
↵
↵
名前はまだない。
このとき、white-space: pre-line
が指定されていた場合、改行はそのままになるはずだと考えるかもしれません。
しかし、実際このような複数回の改行は無視されます。
これは Markdown の処理による影響 です。
CommonMark に依れば、改行が 2 回以上続くような場合、パラグラフブロックとしての意味が途切れます。
すなわち、上の例では 1 文目と 2 文目は異なるパラグラフ (<p>
) として処理されるため、HTML では次のように処理されています。
<p>吾輩は猫である。</p>
<p>名前はまだない。</p>
そのため、異なる <p>
タグ内に含まれている以上、どれだけ改行をしても改行が陽に出てくることはありません。2
もしも、Markdown 内で改行を陽に出したい場合は、強制改行を利用する必要があります。
強制改行
強制改行を行うには、Markdown による方法と HTML による方法の 2 つがあります。
- 行末に
\
を置く (Markdown)吾輩は猫である。\↵ 名前はまだない。
- 行末に連続した 2 つの半角スペースを置く (Markdown)
吾輩は猫である。 ↵ 名前はまだない。
- 文章の途中で
<br>
を置く (HTML)吾輩は猫である。<br>名前はまだない。
いずれの方法であっても同じ結果を得ます。(もちろん、HTML 内に改行が残る残らないの違いはあります)
余談
Qiita や Zenn といったサービスの Markdown は改行に強制改行が挿入される仕様なので、CSS による方法を取る必要はありません(そもそも CSS はいじれない)が、はてなブログのような改行が強制改行にならないが CSS はいじれるようなサービス 3 であれば、非常に有用なテクニックになると思います。
改行をそのまま無くすには
日本語を含む CJK 圏での文章では分かち書きをしません。そのため、1 つの文を複数行に改行する場合(マンページのような特定の文字数で改行する場合)には、単に改行を取り除くことが求められます。
しかし、現在の HTML ではソース内の改行を単に取り除くことは出来ません。
先に示した white-space
プロパティによって、ソース内の改行がまとめられて半角スペースになるかそのままになるかの 2 通りです。
例えば、white-space: normal
の場合、次のような文章の改行毎に半角スペースが挿入されます。
<p>隴西の李徴は博学才穎、天宝の末↵
年、若くして名を虎榜に連ね、つ↵
いで江南尉に補せられたが、性、↵
狷介、自ずから恃むところ頗る厚↵
く、賤吏に甘んずるを潔しとしな↵
かった。</p>
そのため、日本語を含む CJK 圏で文章の途中で改行することは現実的ではありませんでした。
この問題に対して、改行の前後のコンテキストに応じて(例えば、CJK の場合)改行を単に取り除くとする案が W3C ドラフト として提起されています。4
行頭インデント
本記事の趣旨とは若干離れますが、Markdown パラグラフの問題の 1 つにパラグラフの行頭インデントが無いことが挙げられます。
Markdown が CommonMark の Soft line breaks 仕様に従う限り、行頭の空白文字は無視されます。そのため、行頭インデントを全角スペース等で行うことは出来ません。
しかし、CSS を調整できるのであれば、text-indent
から行頭インデントを指定できます。
p {
text-indent: 1em;
}
ちなみに、力技として  
を行頭に置くことで疑似的なインデントを課すことも出来ますが、あまりお薦めしません。変なので。
ちなみに、white-space: pre-line
による改行後の行頭にはインデントが課されません。(<p>
の頭にインデントが課されるだけなので)5
-
Markdown では、行頭と行末の半角スペースは特別な意味を持つことがあります。
- 行頭に 4 つ以上の半角スペース:
Indented code block として解釈される - 行末に 2 つ分以上の半角スペース:
強制改行に解釈される
- 行頭に 4 つ以上の半角スペース:
-
仮に
white-space: pre-line
下で HTML を用いて次のように書いたとしても、改行は上手く処理されません。<p>吾輩は猫である。↵ ↵ ↵ 名前はまだない。</p>
Markdown は、この複数行にわたる改行のために 1 文目と 2 文目のブロックを異なるブロックとして扱います。(1 文目は HTML ブロック、2 文目はパラグラフです)
そのため、 以下の HTML のように解釈されてしまいます。
<p>吾輩は猫である。 <p>名前はまだない。</p></p>
このような結果は不正であり、HTML で複数回の改行をするべきではありません。 ↩
-
はてなブログでは、“デザイン設定” ⇒ “カスタマイズ 🔧” ⇒ 高度な設定の “デザイン CSS” で CSS を記述すれば完了です。 ↩
-
CSS でパラグラフどうしの間隔を狭めれば、
white-space: pre-line
にこだわらずに各パラグラフに行頭インデントを課せます。(HTML 的にはこれが最適解?) ↩