---
title: 两个空格引发的排版惨案 -- 探讨 Markdown 换行规则
date: 2025-03-01
modified: 2025-03-01
url: https://yuuu.org/post/markdown-line-breaks
categories: ["未分类"]
tags: []
description: "我现在才知道，Markdown 中的换行规则居然是两个空格加回车才算真正换行！之前我一直以为连续回车两次就是换行，但实际上，那只是开启了一个新的段落。"
---
## 问题的发现与解决

我现在才知道，Markdown 中的换行规则居然是两个空格加回车才算真正换行！之前我一直以为连续回车两次就是换行，但实际上，那只是开启了一个新的段落。<!--more-->

~~在 Obsidian 里，使用的是 **GitHub Flavored Markdown (GFM)**，但是它却默认关闭了严格换行。它的换行方式非常直观——只需要回车一次即可。而这样的 Markdown 文件在 VS Code 中打开，编辑时看起来确实是单次换行，但由于缺少末尾的两个空格，预览时却并不会真正换行。~~  
~~也就是说，同样一份 Markdown 文件，在 Obsidian 里看是正常换行的，而在 VS Code 里看则只是源文件上的换行，预览时仍然连在一起。我一直以为 Obsidian 的渲染方式才是「正确」的，而 VS Code 可能只是渲染器有点小问题，结果直到现在才搞清楚真相。~~  

后来更进一步研究，却发现并不是如上文那些画了删除线的文段这样的。我的 obsidian 默认是编辑视图，也就是说，其实我一直都是在预览源码，而源码和渲染其实并不一样，源码换行了不代表渲染是要有换行符的，只是单纯的给真的给这段换了一行。
但是如果使用 obsidian 的阅读模式，它便会正常的渲染那些我写的不堪入目的渲染后的文件了，这和 vscode 上的渲染一摸一样。🤣 ~~（我甚至连 obsidian 都没玩明白）~~  

说起来，我用了这么多年 Markdown，「连按两个空格」才是换行这个观念，居然能错这么久，也真是太可笑了。不过话又说回来，直接开一个新段落其实也没什么问题，毕竟可读性更好 ~~（狡辩）~~。  

于是，为了更好地规范 Markdown 语法，我在 Obsidian 里安装了 Linter，希望它能帮助我更合理地使用 Markdown，避免类似的坑。  

还有就是！各位读者：  
真的真的对不起！(＞人＜;)。十分抱歉我之前的文章都用了这么混乱的排版，之前发的文章排版简直像被猫咪滚过的毛线团！换行和换段落简直一团糟。现在已经修正了绝大部分的错误。

## 额外资料（自用，可不看）

### Daring Fireball: Markdown 中的资料

而且我在原始创建者 John Gruber 中找到了这么一句话：

> When you _do_ want to insert a `<br />` break tag using Markdown, you end a line with two or more spaces, then type return.  
> 当你想使用 Markdown 插入一个 `<br />` 断行标签时，你需要在行尾输入两个或更多空格，然后按回车键。  
> Yes, this takes a tad more effort to create a `<br />`, but a simplistic "every line break is a `<br />`" rule wouldn’t work for Markdown. Markdown’s email-style [blockquoting](https://daringfireball.net/projects/markdown/syntax#blockquote) and multi-paragraph [list items](https://daringfireball.net/projects/markdown/syntax#list) work best — and look better — when you format them with hard breaks.  
> 是的，创建一个 `<br />` 需要更多一点的努力，但简单的「每一行换行就是 `<br />`」规则并不适用于 Markdown。Markdown 的电子邮件风格块引用和多段落列表项，用硬换行格式化效果最好——看起来也更美观。

哎呀，创始人早就写好了这个规则了啊。

### GFM 中的规则

去找了一下 github flavored markdown，发现这里的说法是换行有软硬换行之分，

也就是说软换行就是

```html
<p>换行 换行</p>
```

而 HTML 中，多个连续的空白字符（包括换行、空格和制表符）都会被浏览器解析为**一个空格**。所以会被解析为：  

```html
换行 换行
```

硬换行就是

```html
<p>
  换行<br />
  换行
</p>
```

这和原始的那个规则好像大差不差，总之就是，`<br/>`的话就要用两次及以上的空格！

### GitHub Flavored Markdown 上的中英对照

**6.12 Hard line breaks**  
A line break (not in a code span or HTML tag) that is preceded by two or more spaces and does not occur at the end of a block is parsed as a hard line break (rendered in HTML as a `<br />` tag):  
换行符（不在代码跨度或 HTML 标签中）若前面有两个或更多空格且未出现在块末尾，则会被解析为硬换行（在 HTML 中渲染为 `<br />` 标签）：

```markdown
foo(空格)(空格)
baz
```

```html
<p>
  foo<br />
  baz
</p>
```

For a more visible alternative, a backslash before the line ending may be used instead of two spaces:  
若需更直观的替代方案，可在行尾使用反斜杠代替两个空格：

```markdown
foo\
baz
```

```html
<p>
  foo<br />
  baz
</p>
```

More than two spaces can be used:  
可以使用超过两个空格：

```markdown
foo(空格)(空格)(空格)(空格)(空格)
baz
```

```html
<p>
  foo<br />
  baz
</p>
```

Leading spaces at the beginning of the next line are ignored:  
下一行开头的空格会被忽略：

```markdown
foo(空格)(空格)
(空格)(空格)(空格)(空格)(空格)bar
```

```html
<p>
  foo<br />
  bar
</p>
```

```markdown
foo\
(空格)(空格)(空格)(空格)(空格)bar
```

```html
<p>
  foo<br />
  bar
</p>
```

Line breaks can occur inside emphasis, links, and other constructs that allow inline content:  
换行符可出现在允许内联内容的强调、链接等结构中：

```markdown
_foo(空格)(空格)
bar_
```

```html
<p>
  <em
    >foo<br />
    bar</em
  >
</p>
```

```markdown
_foo\
bar_
```

```html
<p>
  <em
    >foo<br />
    bar</em
  >
</p>
```

Line breaks do not occur inside code spans:  
换行符不会出现在代码跨度内部：

```markdown
`code(空格)(空格)
span`
```

```html
<p><code>code span</code></p>
```

```markdown
`code\
span`
```

```html
<p><code>code\ span</code></p>
```

or HTML tags:  
或 HTML 标签中：

```markdown
<a href="foo(空格)(空格)
bar">
```

```html
<p>
  <a
    href="foo(空格)(空格)
bar"
    >...</a
  >
</p>
```

```markdown
<a href="foo\
bar">
```

```html
<p>
  <a
    href="foo\
bar"
    >...</a
  >
</p>
```

Hard line breaks are for separating inline content within a block. Neither syntax for hard line breaks works at the end of a paragraph or other block element:  
硬换行用于在块内分隔内联内容。硬换行的语法在段落或其他块元素末尾无效：

```markdown
foo\
```

```html
<p>foo\</p>
```

```markdown
foo(空格)(空格)
```

```html
<p>foo</p>
```

```markdown
### foo\
```

```html
<h3>foo\</h3>
```

```markdown
### foo(空格)(空格)
```

```html
<h3>foo</h3>
```

---

**6.13 Soft line breaks**  
A regular line break (not in a code span or HTML tag) that is not preceded by two or more spaces or a backslash is parsed as a softbreak. (A softbreak may be rendered in HTML either as a line ending or as a space. The result will be the same in browsers. In the examples here, a line ending will be used.)  
普通换行符（不在代码跨度或 HTML 标签中）若未被两个以上空格或反斜杠修饰，则解析为软换行（在 HTML 中可能渲染为换行或空格。浏览器效果相同。以下示例使用换行符）：

```markdown
foo(无空格)
baz
```

```html
<p>foo baz</p>
```

Spaces at the end of the line and beginning of the next line are removed:  
行尾和下一行开头的空格会被移除：

```markdown
foo(空格)
(空格)baz
```

```html
<p>foo baz</p>
```

A conforming parser may render a soft line break in HTML either as a line break or as a space.  
合规解析器可将软换行在 HTML 中渲染为换行或空格。

A renderer may also provide an option to render soft line breaks as hard line breaks.  
渲染器也可提供将软换行渲染为硬换行的选项。  

## 可能有用的链接

- [Daring Fireball: Markdown](https://daringfireball.net/projects/markdown/)
- [CommonMark](https://commonmark.org)
- [GitHub Flavored Markdown](https://github.github.com/gfm/)
