Yuanji's Blog

这个博客已通过认证

使用 Markdown Render Hooks 要注意

📅 ( 更新 ) | 🏷️ , ,
文章目录

在制作 Hugo 主题的过程中,免不了要和 Markdown 打交道,尤其是希望在 Markdown 转 HTML 的过程中想要额外做点儿什么的时候。

比如常见的使用场景:

Hugo 为了让用户方便的实现这个需求,提供了 Markdown Render Hooks。利用这个钩子就可以劫持 Markdown 生成 HTML 这一过程,目前支持 imagelinkheadingcodeblock。详细的信息请参考:Markdown Render Hooks 官方文档

本文并非是要讲如何使用这一功能,而是分享一个“滥用”这个功能产生的一个副作用。

问题点

话不多说直接上有问题的代码,像是这样的一个 Render Hook 一般位于 layouts/_default/_markup/render-image.html

<figure>
  <img
    src="{{ .Destination | safeURL }}"
    alt="{{ .Text }}"
  />
  <figcaption>{{ .Title }}</figcaption>
</figure>

乍一看似乎毫无问题,就是让 Hugo 在渲染图片的时候不要把 ![Text](Destination "Title") 默认转成 HTML 的 img 元素,而转成 figure。这样显示图片的时候还能配上一段解说的文字,对用户较为友好。

不过其实问题不是出在这里,而在于尽管图片被转成了figure,它仍被包裹在一个 p 段落元素中。简单地说,figure 作为 p 的子元素就是问题。

代码复现

比如下面这段代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>figure debug</title>
  </head>
  <body>
    <p>
      <figure>
        <img src="https://example.com/" alt="figure debug" />
        <figcaption>figure debug</figcaption>
      </figure>
    </p>
  </body>
</html>

其实是不符合规范的,我们可以复制到 The W3C Markup Validation Service 里验证会得到下面的错误

Nu HTML Checker 的错误信息
Nu HTML Checker 的错误信息

如果我们新建一个 HTML 文档再用 Chrome 打开,用 DevTools 查看元素结构会得到一个奇怪的现象,figure 元素前后分别出现一个空的 p 元素。

DevTools 元素结构
DevTools 元素结构

查阅 MDN 文档

通过查阅文档得知,按照规范,p 元素允许的子元素要是 Phrasing Content,而 figure 并不在其中。

同样的道理,我们也不能把 div 元素放到 p 元素下,因为 div 同样不是 Phrasing Content。

回避方法

得知了这个错误的原因后,基本上有这么两种方法回避的方法:

  1. 老老实实在 Markdown 转 HTML 的过程中,碰到图片标记转成 img 而非 figure
  2. 干脆不用 Markdown 来表现图片,而用 Hugo 自带的 shortcodes 功能

出于兼容性的考虑,我选择了第一种方法。并且通过一点儿 CSS 来实现了图片说明文字的展示。

最后

通过遭遇这次的问题,我发现 Nu HTML Checker 是个好东西,可以用来检查文档的 HTML 是否符合规范,为了更简单地一键检查,我在本站 footer 最后加上了一个小徽章,只要点一下就可以查看当前页面的检查报告了,是不是非常方便?顺便一提,这个徽章来自:bradleytaunt/html5-valid-badge