主题开发

FlatPaper 新特性预览:堆叠相册、渐进开屏与打字机

2026-09-01 #FlatPaper#视觉设计#主题#图片

feat/pr-9 这一批改动来自贡献者 jinghuashang 的 PR #9。功能设计是他的,最终重新实现了一些功能,调整了一些不兼容的配置。

一共六项:堆叠相册、渐进式开屏大图、窄屏独立背景图、打字机、滚动渐入、页脚图标链接与署名位置。其中两项可以直接在文章里演示,剩下四项是站点级的——这个页面本身就在跑,往下翻的时候留意一下页脚和回到首页的开屏。

堆叠相册

引入了 {% stackalbum 480,480 %} 标签:

一叠像扑克牌一样码在一起的照片。点最上面那张,它会被抽起来,然后滑到牌堆最底下。

见滝原的黄昏
晓美焰
叛逆的物语
圆环之理

写法就是一个标签包一组普通的 markdown 图片:

1
2
3
4
5
6
{% stackalbum 480,480 %}
![见滝原的黄昏](https://img.nep.me/bg/bg-madoka-1.webp "h")
![晓美焰](https://img.nep.me/bg/bg-homura.webp "v")
![叛逆的物语](https://img.nep.me/bg/devil-homura.webp "h")
![圆环之理](https://img.nep.me/bg/bg-madoka-2.webp)
{% endstackalbum %}

几个细节:

  • 参数 宽,高 可选,默认 480,480。
  • markdown 的 title 位置填 "h" 是横卡(480×320),"v" 是竖卡(320×480)。不填的按图片自己的宽高比在浏览器端判断——上面第四张就没填。
  • 容器高度按卡片实际占位算,取「高 参数」和「卡片真正需要的空间」里较大的那个。所以竖图多、张数多的时候不会溢出到下面的正文里。
  • 窄屏会整体缩放到放得下为止。缩放看的是牌堆实际有多少地方可用,不是某个像素断点——所以窄侧栏、平板分栏和手机是同一套逻辑。
  • 键盘可用:牌堆本身可以聚焦,Enter 或 → 翻到下一张。堆叠状态下只有最上层是清晰的,不给键盘路径的话其余照片对不用鼠标的人就是不存在的。Space 有意没绑——它是翻页键。

主题的 Fancybox 灯箱会自动包裹正文图片,但相册里的图片带了 no-zoom,所以点击只翻牌、不会弹出大图。

悬停翻牌

引入了 {% stackalbumnav %} 标签:

小一号的变体,一个牌堆配一列名字。鼠标移到名字上(或者用 Tab 键聚焦),对应的封面会翻到最上层;移开就恢复原来的顺序。

标签的参数是一条数据路径:

1
{% stackalbumnav collections.anime %}

第一段是 source/_data/ 下的文件名,后面按点号往下钻,最终指到一个列表。这个例子读的是 source/_data/collections.yml:

1
2
3
4
anime:
- title: 魔法少女小圆
link: https://www.bilibili.com/bangumi/media/md1177
image: https://img.nep.me/bg/bg-madoka.webp

文件名和键名都是你自己定的。

字段接别名:名字用 name 或 title,链接用 href / link / url,封面用 cover / image / src。

渐进式开屏大图

这项要回首页看。开启后开屏背景是这样加载的:先铺一张高斯模糊的小图占位,等背景大图解码完成再淡出交接;同时往下滚的时候图片会轻微放大、整个开屏渐隐。

1
2
3
4
5
6
home_hero:
enable: true
image: https://example.com/hero.jpg
image_progressive: true
# 可选:模糊层用的小图,省略时用纸面底色,仍然有淡入
image_placeholder: /images/hero-lqip.jpg

关键在于图源仍然只有 image 一个。image_progressive 改变的是它怎么加载,不是换一个图源进来,所以 image_overlay、mobile_image、多图随机轮播全部照常生效。加载失败、脚本没跑、或者浏览器禁用 JS,都会直接显示 image 本身——模糊层带着 hidden 属性出场,由脚本揭开,两秒内没人接手就自己藏回去。

原 PR 那版滚动时还会逐帧加 blur()。 目前主题只保留了 opacity 和 transform。

窄屏可以单独指定一张

mobile_image 从开关变成了「开关或图源」:

1
2
3
4
home_hero:
mobile_image: true # 默认,沿用上面的 image
# mobile_image: false # 窄屏回退到纸张背景
# mobile_image: /images/hero-mobile.jpg # 窄屏用这张

填链接的时候,窄屏(≤760px)单独用那张图,适合另外准备一版竖版裁切。这时候开屏仍然是照片模式,文字和按钮配色不变——只有背景图那一条声明变了。

打字机

页脚版权行右边那一句,还有首页开屏 bio 的位置——这个站两处都开着,翻到本页最底下就能看到。

1
2
3
4
5
6
7
8
9
footer:
typed:
enable: true
effect: true # false 就直接显示 sub 第一行,不做动画
loop: true
type_speed: 150
source: 1 # false 仅 sub | 1 一言 | 2 一句网 | 3 今日诗词
sub:
- 桃李春风一杯酒,江湖夜雨十年灯

home_hero.typed 是同一套字段。两处同时开启也只会请求一次 Typed.js。

CDN 不可达的时候不会转圈:onerror 和 6 秒超时走同一个出口,退回纯文本显示 sub 第一行。hero 那一侧 sub 为空时会回退到 hero.bio / profile.bio,不会渲染出一个空段落。

滚动渐入

也是回首页看:精选轮播、章节标题、文章卡和侧栏卡进入视口时逐个上浮渐显,文章卡按位置交错出场。

值得说的是没有 JS 的时候会怎样。.reveal 的初始状态是 opacity: 0,如果就这么发出去,禁用 JS 的读者会看到一个空首页。所以隐藏这件事由 <head> 里的内联脚本决定:只有在 IntersectionObserver 存在时才给根元素加 reveal-ready,并且挂一个两秒的看门狗——main.js 没接上观察器的话就把这个类摘掉。没有 JS,就没有任何东西被隐藏过。

交错延迟走的是自定义属性 --reveal-delay 加 animation-delay,而不是内联 transition-delay。后者会顺带延迟卡片自己的 hover 抬升,每行靠后的卡片鼠标移上去要等最多 300ms 才有反应。

页脚图标链接与署名位置

看本页页脚右侧那一行:归档 · 分类 · 标签 · [CC 图标组] · Powered by Theme FlatPaper。

条目可以只有图标、没有文字:

1
2
3
4
5
6
7
8
9
10
11
12
13
footer:
links:
-
- name: 归档
link: /archives
- link: /copyright
title: 版权协议
aria-label: 版权协议
icons:
- fa-regular:copyright
- fa-brands:creative-commons-by
- fa-brands:creative-commons-nc
- fa-brands:creative-commons-nd

icons 是数组,一个链接里可以并排几个图标。主题的图标按需打包机制同步认这个字段,所以只有真正用到的 SVG 才会进产物。纯图标链接没有可读的名字,aria-label 会补上。

主题署名的位置换了配置面:

1
2
3
4
5
footer:
powered:
prefix: Powered by Theme
name: FlatPaper
row: first # first(默认)| last | own
  • first —— 并入第一组链接行的末尾,也就是这个站现在的样子
  • last —— 并入最后一行末尾
  • own —— 独占一行

默认布局变了。 v0.4.0 里署名是独占第一行的,现在默认并入第一组链接行。如果你配了 footer.links,升级后右侧会从两行变成一行。想要旧的样子就写 row: own。

为什么默认从「独占一行」改成「并入」:.site-footer__right 是一行一个 row 的 grid,配了备案信息的站点会得到

1
2
Powered by Theme FlatPaper
蜀ICP备XXXXXXXX号-X · 版权协议

主次颠倒了——备案信息才是主体,主题署名压在它头上。

赞赏名单

在关于页一类的独立页面正文里写一段结构化 HTML,就能得到手账便签风格的赞赏卡片。没有新增配置项。

焰 晓美焰
¥100
圆 鹿目圆
¥50
沙 美树沙耶香
¥20
杏 佐仓杏子
¥10
巴 巴麻美
¥5

共 5 人 · 最新更新时间:

金额徽章的颜色不用自己写:脚本扫 .reward-list__amount 的文本,解析出数字后按人民币纸币面额自动上色——≥100 红、≥50 绿、≥20 棕黄、≥10 蓝、≥5 紫、≥1 橄榄绿。markup 里已经写了 reward-list__amount--50 这类档位类的话,以你写的为准。

纸色档位 --p1 到 --p5 循环使用,胶带颜色跟着纸色走。头像可以放 <img class="reward-list__avatar no-zoom"> 贴在右上角,也可以像上面这样用 .reward-list__avatar--text 显示名字首字。

1
2
3
4
5
6
7
8
9
10
11
<div class="reward-list">
<div class="reward-list__item reward-list__item--p1">
<img class="reward-list__avatar no-zoom" src="/images/donor.jpg" alt="昵称"
loading="lazy" referrerpolicy="no-referrer">
<span class="reward-list__name">昵称</span>
<div class="reward-list__bottom">
<span class="reward-list__amount">¥100</span>
<time class="reward-list__date">2026-08-14</time>
</div>
</div>
</div>

配置速查

功能 配置 / 写法 默认
堆叠相册 {% stackalbum 宽,高 %} … {% endstackalbum %} ——
悬停翻牌 {% stackalbumnav 数据路径 %} ——
渐进开屏 home_hero.image_progressive / image_placeholder 关
窄屏背景图 home_hero.mobile_image(true / false / 链接) true
打字机 footer.typed / home_hero.typed 关
滚动渐入 无配置项,首页自动生效 开
页脚图标 footer.links[].icons / title / aria-label ——
署名位置 footer.powered.row first
赞赏名单 正文写结构化 HTML ——

细节见仓库里的 配置说明 与 自定义标签与页面。

原 PR 里还有一项侧边栏定位欢迎卡片(按访客 IP 显示归属地和距离),最后决定不合并进主题。它需要把每个访客的 IP 发给第三方接口,可以通过外挂 JS 实现。

评论
微信
支付宝
分享

评论