Github Markdown 中的列表项之间出现额外的行

Extra lines appearing between list items in Github Markdown

我有一个包含六个列表的自述文件。

倒数第二个列表之前一切正常。问题是在这些列表项之间出现了一个额外的换行符。这个用截图会更清楚:

我在 sublime text 中使用 Markdown 预览包,如果我使用 Github Markdown 预处理器进行预览,我会看到相同的格式问题。

不过,最奇怪的是,如果我在 https://jbt.github.io/markdown-editor

中输入文字,我却看不到同样的问题

如果您想自己尝试,请使用以下字符串:

_git_

- **gl**: `git log <optional args>` _shows the revision history_
- **gpoh**: `git push origin head` _pushes the current branch_
- **gpom**: `git push origin master` _pushes the master branch_
- **grv**: `git remote -v` _lists the remotes_
- **gs**: `git status` _shows unstaged & staged changes_
- **gacm**: `git add -A; git commit -m "<message>"` _commits all changes with a message_
- **gacm-lfs**: `sudo git add -A; sudo git commit -m <message>` _it might not be this way for everyone,
  but for me `sudo git` uses git-lfs (git large filesystem) while `git` uses regular git. This function
  adds and commits all files with a message in a git-lfs repo._
- **gc**: `git checkout <branch>` _changes branches_
- **gclo**: `git clone <repo>` _clones a repo_
- **get_branch**: `git branch -f origin/<branch>; git checkout <branch>` _gets a specific branch from a remote repo_

_fish meta functions_

- **backup_functions**: `cd ~/.config/fish/functions; git add -A; git commit -m "<message>"; git push origin master; cd -` _backups the functions folder into a repo_
- **cdfns**: `cd ~/.config/fish/functions` _changes into the functions dir_
- **cfn**: `cat ~/.config/fish/functions/<name>.fish` _shows the definition of a function_
- **efn**: `nano ~/.config/fish/functions/<name>.fish` _edits a function's definition (using nano)_
- **fn**: `echo -e "function $argv[1]\n  $argv[2]\nend" > ~/.config/fish/functions/$argv[1].fish` _create a function_
- **fns**: `ls ~/.config/fish/functions` _list functions_
- **rmfn**: `rm ~/.config/fish/functions/<name>.fish` _remove a function_
- **fndoc**: `echo -e "- <text>" >> ~/.config/fish/functions/README.md` _adds a line to the readme documenting a function_
- **fs**: `funcsave <name>` _alias for funcsave, e.g.:_

      function fs
        funcsave $argv
      end
      fs fs

您的第一个列表是 "tight" 列表,而第二个列表是 "loose" 列表,因为它在其中一个列表项中包含代码块。如果您希望列表匹配,请为两者使用相同的类型。在第一个列表中的项目之间添加一个空行将使它们匹配。正如 spec 解释的那样:

A list is loose if any of its constituent list items are separated by blank lines, or if any of its constituent list items directly contain two block-level elements with a blank line between them. Otherwise a list is tight. (The difference in HTML output is that paragraphs in a loose list are wrapped in <p> tags, while paragraphs in a tight list are not.)

作为一个简单的例子,这个列表:

* line 1
* line 2

将呈现为 HTML:

<ul>
    <li>line 1</li>
    <li>line 2</li>
</ul>

而此列表:

* line 1
* line 2

  a second block

将呈现为:

<ul>
    <li>
        <p>line 1</p>
    </li>
    <li>
        <p>line 2</p>
        <p>a second block</p>
    </li>
</ul>

请注意,第二个列表项包含多个段落。因此,列表项中的每个段落都包含在 <p> 标记中,使列表成为 "loose" 列表。为了保持一致性,列表中的所有项目都包裹在 <p> 标签中(包括第一项)。虽然该示例使用了一个段落,但它同样适用于任何块级构造,包括示例中的代码块。

您还可以通过在列表项之间添加一个空行来强制列表成为 "loose" 列表。例如,这个列表:

* line 1

* line 2

结果HTML:

<ul>
    <li>
        <p>line 1</p>
    </li>
    <li>
        <p>line 2</p>
    </li>
</ul>

因此,如果您在第一个列表中的至少两个项目之间添加一个空行,则两个列表将始终显示为中间有一些白色 space。

之所以在<p>标签中包裹列表项的内容添加白色space是因为页面(CSS)的样式定义了填充and/or <p> 标签的边距。可以编辑 CSS 以在他们自己的站点上删除此 padding/margin,但在第三方主机上,这通常不是一种选择。

至于为什么有些工具似乎没有表现出这种行为;可能是它们具有默认的 CSS 样式,这导致两种类型的列表看起来相同(例如,Whosebug 就是这样做的)。另一种可能性是他们使用的是老式的 Markdown 解析器,而不是更新得多的 CommonMark 规范(GitHub 使用)。原来Markdown rules also had the concept of loose and tight lists, but the behavior was not so specifically defined so different implementations behaved slightly differently. Many followed the reference implementation and only made the list items adjacent to blank lines "loose" and all other items "tight". In your example only the last item would be "loose" but, as it is the last item in the list, would not be as noticeable. For a comparison of how various implementations behave, see Babelmark.

无论实施如何,如果您想要 "tight" 列表,始终获得该列表的唯一方法是永远不要在列表项的任何位置包含任何空行。这意味着你永远不能嵌套其他块级结构,除了一些非常具体的例外:

  1. 嵌套列表是明显的例外,但即便如此,您仍需要避免空行(参见 example):

    * parent item
        * nested item
        * Another nested item
    * sibling of parent
    * Another sibling of parent
    
  2. 嵌套代码块或块引用可以嵌套在一些实现中,但它需要从列表项的第一行开始并且不包含空行.

    * list item
    *     A code block because it is indented appropriately
    * > a blockquote
    * a list item
    

    正如您在 example 中看到的那样,它仅在某些实现中有效。值得注意的是,CommonMark 实现。换句话说,它可以在 GitHub 上运行,但可能不适用于其他工具或其他站点。

无论如何,如果您有多个子段落、代码块、and/or 块引号,您就无法拥有一个紧凑的列表。