使用属性选择器为 Markdown 里的图片添加样式

最后更新:

在写 上一篇文章 的时,文章开头有一张示例图,为了节省空间,我用的图片一般都不会很大,并且那张图只是Google出来的,没有调整就直接放上来了。

在列表页看着图片居左就很难受,想要把它居中放置,但是不想用 HTML 的方式来写,就突然想起来早前有看到过 肉大的一篇分享,是通过 CSS属性选择器 来实现的,就想着自己也可以整理一下,然后放到博客的主题当中使用,以后图片排版就会方便很多。

首先 就是讲述一下 Markdown 语法当中的图片标记:

![alt text](/src/of/image.jpg "title")

说实话,我在写这篇分享之前,完全不知道 图片标记 是有一个可选的 title 属性的,一直以为只有 pathalt 两个属性。(当然我是知道有一些 Markdown 扩展/转换器提供了一些额外的拓展属性,比如 Kramdown)

按照 肉大 以及 Baron Schwartz 的说法,可以使用 #hash?query 或者直接使用 alttitle 属性的形式来实现。
但使用 alttitle 来实现,我的想法与 Baron 一致并不赞同以及提倡滥用 alttitle 属性。

所以还是考虑使用 #hash 的方式来实现,为何不使用 ?query 的形式,因为我国内的镜像是放在 Aliyun OSS 当中,一些多余的 query 参数可能会影响资源的加载。

实现

实现的部分其实不用多说,其实就是在语法当中的 path 部分加上 #hash 值,然后使用 CSS 的属性选择起来匹配:

![test](/test.jpg#center "test")
img[src$="#center"]{
  margin-left: auto;
  margin-right: auto;
}

结果预览 👉
test

但是如果想使用多个属性就会有一些问题,比如说我该怎么去 分隔 他们。

Baron 的想法是使用 空格分隔 (space-delimited),并且修改 $ 使用 ~ 来匹配:

![test](/test.jpg# center border "test")
img[src~="center"]{
  margin-left: auto;
  margin-right: auto;
}
img[src~="border"] {
  border: 2px solid black
}

但是 Hexo 在编译时,会认为语法错误,直接输出成为文本内容。
👉 ![test](/test.jpg# center border "test")

所以需要改成转义后的 空格%20)来书写,才可以被编译为图片,但是这样书写就不能被属性选择器的 ~ 符所匹配到。

而且我觉得 %20 也不便于记忆,所以我继续选择使用 # 来分隔,并且在每个样式之前都加上 #,例如:

![test](/test.jpg#center#border "test")

同样的,属性选择器也需要变更,因为多个样式,就不能使用 $~ 来匹配了,需改成 * 来匹配。
具体可以查看 属性选择器 | MDN

img[src*="#center"]{
  margin-left: auto;
  margin-right: auto;
}
img[src*="#border"] {
  border: 2px solid black
}

结果预览 👉
test

暂时还没有发现任何影响,如果你知道这样书写会有问题,那么请 📧 Mail 给我吧


尾声

✨ 为什么不用书写 HTML 的方式来实现,不是更加自由吗?

因为编译会有问题,如果在 markdown 中书写了,HTML 标签,那么在标签闭合之前,其中所有的内容都不会被处理,比如说 Baron Schwartz 在文中提到的:

<div style="width:150px; height:100px">
![Kitten](/media/2018/08/kitten.jpg)
</div>

会被直接输出到页面中,所以结果如下,会直接输出 ![Kitten](/media/2018/08/kitten.jpg),并不会把中间的 markdown 图片语法 转换成 <img> 标签

<div style="width:150px; height:100px">
![Kitten](/media/2018/08/kitten.jpg)
</div>

参考文档:

给 Markdown 里的图片增加样式 – 山维空间
How to Style Images With Markdown

属性选择器 - CSS | MDN


Update 03/06/2024

因为 淘宝镜像证书过期 的缘故,借机升级了一下博客的依赖项。发现 hexo-renderer-marked3.1.0 之后其实已经支持了 postAsset 选项,开启后会将文章内的图片自动解析为其对应文章的路径。 🔗 资源文件夹 | Hexo

# _config.yml
post_asset_folder: true
marked:
  prependRoot: true
  postAsset: true

所以我就移除了 hexo-asset-image 这个依赖项(本来就有小BUG多年没有修复了)。

但是其内部使用 findById 这个方法在数据文件(db.json)中寻找资源时,并没有移除文件路径中的 hash 值。所以如果我们在图片路径中使用 hash 值来实现额外样式时就会查询不到文件资源。导致路径解析失败,直接返回未处理的资源路径。