让博客支持实况照片(Live Photos)
iPhone 拍的实况照片(Live Photo)会连带记录按下快门前后约三秒的画面。导出到电脑、上传到博客之后,这段动态就丢了,剩下一张普通的静态图——那一刻的风、表情、光线都没了。
于是我给博客加了实况照片的支持。
先看效果
桌面端把鼠标移上去,移动端长按,就会播放——这就是这张实况照片在按下快门那两秒里真实捕捉的画面。松开后回到静态图,左上角的 ◉ LIVE 角标和 iOS 上一致。
它是怎么工作的
一张实况照片其实是 一张静态图 + 一段约三秒的视频。页面默认只显示静态图,交互时再把视频淡入播放:
- 桌面:悬停播放,移开复位
- 移动:长按播放,松手复位
- 键盘:聚焦后按空格 / 回车切换
视频用了 muted loop playsinline preload="none"——默认不下载,只有真正交互时才加载,不浪费流量。
我没有引入 Apple 官方的 LivePhotosKit(那是一个约 200KB、需要从 Apple CDN 加载的库),而是自己写了大约 40 行原生 JS 加一段 CSS,完全自托管,符合本站 useCDN = false 的取向。代价是动效不是 Apple 那种弹簧式的逐帧擦除,但「静态图 → 动态」的体验已经很接近。
怎么用
三步。
1. 转换素材。 iPhone 导出的是 HEIC 静态图加 MOV 视频,浏览器既不认 HEIC、也未必能播 MOV,所以先转成网页能用的 JPEG + MP4:
./scripts/livephoto.sh ~/IMG_1234.HEIC ~/IMG_1234.MOV 名字
脚本会在 static/imgs/livephotos/ 下生成 名字.jpg 和 名字.mp4,并直接打印出可以粘贴的短代码(连宽高都填好了)。
2. 在文章里开启。 在 frontmatter 的 [extra] 下加一行——这样播放脚本只会在用到的文章里加载:
[extra]
livephoto = true
3. 正文里嵌入。 把脚本打印的短代码贴进来:
{{ livephoto(still="/imgs/livephotos/名字.jpg", video="/imgs/livephotos/名字.mp4", alt="说明", width=1080, height=1440) }}
width / height 用来提前占好比例,图片加载时页面不会跳动。
实现要点
几个值得记一笔的地方:
- 短代码
templates/shortcodes/livephoto.html:渲染一个<figure>,里面是叠在一起的静态图<img>和<video>,外加一个纯 CSS 画的 LIVE 角标。JS 没加载时,静态图照样显示,优雅降级。 - 按需加载脚本:复用了本站已有的「按文章开关」模式(和 KaTeX 一样,
page.extra.<flag>),没开livephoto的页面一行 JS 都不会多加载。 - 和全局样式打架:站点有几条全局规则会漏到实况照片上——
img { border }、figure img { max-height }、桌面端figure { padding }——都得在.livephoto里逐一覆盖,否则静态图和视频两层会对不齐。 - 转换脚本用 macOS 自带的
sips做 HEIC → JPEG,用ffmpeg做 MOV → MP4(yuv420p++faststart,并去掉音轨,因为实况照片本就是静音的)。
小结
加完之后,博客里那些来自 iPhone 的照片终于能动起来了。代码很少,依赖为零,按需加载。下次写游记,就能把按下快门那一刻的风一起放进来。