Snow静态博客处理多图排版

snow

事情的缘由是我无意中发现之前写的部分文章里的图片没有渲染出来,才想起之前博客系统改版,从 Pelican 切换到 Snow 时竟然忘记更新,看了一下原文,大部分都是以下形式

 1<div class="row">
 2  <div class="col-md-4">
 3    [[https://s.libforest.com/images/pic/西湖/日落(二).jpg]]
 4  </div>
 5  <div class="col-md-4">
 6    [[https://s.libforest.com/images/pic/西湖/日落(三).jpg]]
 7  </div>
 8  <div class="col-md-4">
 9    [[https://s.libforest.com/images/pic/西湖/日落(一).jpg]]
10  </div>
11</div>

因为我之前的博客主题使用了 Bootstrap,为了能够让多张图片并排显示,所以用了 Bootstrap 里的 .row .col-*。但前不久移除了全部的 Bootstrap,现在当然不会生效。另外一点是我之前用的 org mode 解析器可以直接解析 HTML 中的链接,但更换了新的解析器 org-golang 后,已经无法不能解析HTML中的原始链接

此次利用 Snow 博客系统中的 shortcode 功能实现多图排版,让图片可以并排显示,多行显示。

解析原始链接

首先在主题下创建一个名为 galleryshortcode,比如我使用的主题叫做 snow,所以在 themes/snow/templates/shortcodes 目录下创建一个 gallery.html 文件

1<div class="gallery gallery-{% if params.layout %}{{ params.layout }}{% else %}grid{% endif %}">
2  {{ body | safe }}
3</div>

接着修改原始文章

1:::shortcode gallery
2![](https://s.libforest.com/images/pic/西湖/日落(一).jpg)
3![](https://s.libforest.com/images/pic/西湖/日落(二).jpg)
4![](https://s.libforest.com/images/pic/西湖/日落(三).jpg)
5:::
1#+html: <shortcode gallery>
2[[https://s.libforest.com/images/pic/西湖/日落(一).jpg]]
3[[https://s.libforest.com/images/pic/西湖/日落(二).jpg]]
4[[https://s.libforest.com/images/pic/西湖/日落(三).jpg]]
5#+html: </shortcode>

原始文章中的内容将会自动渲染成

1<div class="gallery gallery-grid">
2  <p>
3    <img src="https://s.libforest.com/images/pic/西湖/日落(二).jpg" />
4    <img src="https://s.libforest.com/images/pic/西湖/日落(三).jpg" />
5    <img src="https://s.libforest.com/images/pic/西湖/日落(一).jpg" />
6  </p>
7</div>

或者可以直接使用 HTML 内容

1<shortcode gallery>
2  <p>
3    <img src="https://s.libforest.com/images/pic/西湖/日落(一).jpg" />
4    <img src="https://s.libforest.com/images/pic/西湖/日落(二).jpg" />
5    <img src="https://s.libforest.com/images/pic/西湖/日落(三).jpg" />
6  </p>
7</shortcode>
1#+begin_export html
2<shortcode gallery>
3  <p>
4    <img src="https://s.libforest.com/images/pic/西湖/日落(一).jpg" />
5    <img src="https://s.libforest.com/images/pic/西湖/日落(二).jpg" />
6    <img src="https://s.libforest.com/images/pic/西湖/日落(三).jpg" />
7  </p>
8</shortcode>
9#+end_export

多行显示

多行显示可以利用文件解析时每次遇到空行都会生成一个新的段落,比如

1[[https://s.libforest.com/images/pic/西湖/日落(一).jpg]]
2
3[[https://s.libforest.com/images/pic/西湖/日落(二).jpg]]

就会生成

1<p>
2  <img src="https://s.libforest.com/images/pic/西湖/日落(一).jpg" />
3</p>
4<p>
5  <img src="https://s.libforest.com/images/pic/西湖/日落(二).jpg" />
6</p>

故如果需要多行显示,只用在多张图片中间添加一个空行,然后使用css自定义样式即可

图片排版

有了固定结构的HTML, 接着就可以添加 css,使多张图片可以并排显示

网格模式(Grid)

展开详情
 1.gallery img {
 2  margin: 0;
 3}
 4/* p 统一开启 flex 布局 */
 5.gallery-grid p {
 6  display: flex;
 7  flex-wrap: wrap;
 8  gap: 0.5rem;
 9  margin: 0 0 0.5rem 0;
10}
11
12/* 分配单位统一为 img/a/figure,script/link/style 天然被忽略 */
13.gallery-grid p > :is(img, a, figure) {
14  display: block;
15  flex: 1 1 calc(33.333% - 0.5rem * 2 / 3);
16  max-width: calc(33.333% - 0.5rem * 2 / 3);
17  margin: 0;
18}
19
20/* a 标签重置默认样式 */
21.gallery-grid p a {
22  text-decoration: none;
23  color: inherit;
24  display: block;
25}
26
27/* figure 内部纵向排列 */
28.gallery-grid p > figure {
29  display: flex;
30  flex-direction: column;
31}
32
33/* 所有 img 统一撑满宽度 */
34.gallery-grid p img {
35  display: block;
36  margin: 0;
37  width: 100%;
38  /* height: auto; */
39  object-fit: cover;
40  aspect-ratio: 4 / 3;
41}
42
43/* figcaption 样式 */
44.gallery-grid p figcaption {
45  margin-top: 0.25rem;
46  font-size: 0.875rem;
47  line-height: 1.4;
48  text-align: center;
49}
50
51/* 只有一个 img/a/figure:占满一行 */
52.gallery-grid p:has(> :is(img, a, figure):only-of-type) > :is(img, a, figure) {
53  flex: 1 1 100%;
54  max-width: 100%;
55  margin: 0;
56}
57
58/* 正好两个 img/a/figure:各占一半 */
59.gallery-grid p:has(> :is(img, a, figure):nth-of-type(2):last-of-type) > :is(img, a, figure) {
60  flex: 1 1 calc(50% - 0.25rem);
61  max-width: calc(50% - 0.25rem);
62}

瀑布流模式(Masonry)

展开详情
 1/* 默认:三张及以上,三栏瀑布流 */
 2.gallery-masonry p {
 3  column-count: 3;
 4  column-gap: 0.5rem;
 5  margin: 0 0 0.5rem 0;
 6}
 7
 8/* 每个图片单元(img/a/figure)作为一个不可拆分的栏内块 */
 9.gallery-masonry p > :is(img, a, figure) {
10  display: block;
11  width: 100%;
12  break-inside: avoid; /* 避免被截断到两栏之间 */
13  -webkit-column-break-inside: avoid;
14  margin-bottom: 0.5rem;
15}
16
17/* a 标签重置默认样式 */
18.gallery-masonry p a {
19  text-decoration: none;
20  color: inherit;
21  display: block;
22}
23
24/* figure 重置默认 margin,内部纵向排列 */
25.gallery-masonry p figure {
26  margin: 0;
27}
28
29/* 所有 img 统一撑满宽度,高度按原始比例自适应(瀑布流的关键:不裁切) */
30.gallery-masonry p img {
31  display: block;
32  width: 100%;
33  height: auto;
34  margin: 0;
35}
36
37/* figcaption 样式 */
38.gallery-masonry p figcaption {
39  margin-top: 0.25rem;
40  font-size: 0.875rem;
41  line-height: 1.4;
42  text-align: center;
43}
44
45/* 只有一个 img/a/figure:不分栏,占满一行 */
46.gallery-masonry p:has(> :is(img, a, figure):only-of-type) {
47  column-count: 1;
48}
49
50.gallery-masonry p:has(> :is(img, a, figure):only-of-type) > :is(img, a, figure) {
51  margin-bottom: 0;
52}
53
54/* 正好两个 img/a/figure:两栏 */
55.gallery-masonry p:has(> :is(img, a, figure):nth-of-type(2):last-of-type) {
56  column-count: 2;
57}

图片画廊

图片画廊同样可以利用 shortcode 实现。

首先在 templates/shortcodes 目录下创建 img.html 重新渲染 img

1<a href="{{ params.src }}" data-img-lightbox data-gallery="{% if params.gallery %}{{ params.gallery }}{% else %}page-images{% endif %}" data-type="image">
2  <img data-src="{{ params.src }}"
3       alt="{% if params.alt %}{{ params.alt }}{% endif %}"
4       decoding="{% if params.decoding %}{{ params.decoding }}{% else %}async{% endif %}">
5</a>

然后引入对应的画廊库,比如我使用的是 glightbox

1<link rel="stylesheet" href="{{ "libs/glightbox/glightbox.min.css" | absURL }}">
2<script src="{{ "libs/glightbox/glightbox.min.js" | absURL }}" defer></script>

图片懒加载

引入对应的懒加载库,然后根据对应库的文档初始化即可

1<img ... class="lazy">
2<script src="{{ "libs/vanilla-lazyload/lazyload.min.js" | absURL }}" defer></script>

显示效果

参考资料