写博客时除了文字和图片,还经常要嵌入视频、推文、二维码这些"非文本"内容。Hugo 的 shortcode 机制让这些嵌入都能用一行简洁的语法搞定。下面把这个主题支持的全部嵌入元素演示一遍。

一、YouTube 视频

Hugo 内置 youtube shortcode,只要把视频 ID 喂进去(URL 里 v= 后面那串):

{{< youtube aqz-KE-bpKQ >}}

效果:

自动 16:9 比例响应式,移动端也会自适应。

二、Vimeo 视频

同理,vimeo shortcode 接受视频 ID:

{{< vimeo 76979871 >}}

Vimeo 的嵌入界面比 YouTube 干净一些,适合纯作品展示。

三、X / Twitter 推文

通过 url 参数嵌入完整推文(会自动渲染头像、内容、互动数据):

{{< x url="https://x.com/twitter/status/1228393702244134912" >}}

也可以拆开传:

{{< x user="twitter" id="1228393702244134912" >}}

实际效果(需要联网加载 X 的 widgets.js):

⚠️ 如果你的访问受限(如国内不挂梯子),X 的 widgets.js 加载会失败,推文会显示为一个简单的"查看推文"链接。这是预期行为,不影响其他内容。

四、二维码

qr shortcode 即时生成二维码图(通过公共 API)。常用于"扫码加微信 / 关注公众号 / 下载 App"等场景:

{{< qr text="https://zero9501.online" size="180" caption="扫码访问博客" >}}
QR: https://zero9501.online
扫码访问博客

参数:

参数默认说明
text必填,要编码的内容(URL / 文本 / WiFi 配置 / vCard 等)
size200像素尺寸
caption图下方说明文字

五、图片排布

详细用法见之前那篇 图片排布速查,这里再快速过一遍。

单张全幅大图

{{< wide src="https://picsum.photos/id/29/2000/900" caption="一张需要呼吸感的风景" >}}
一张需要呼吸感的风景

双联横排

九宫格

六、语言代码块

```language 围栏后跟语言名即可,主题会自动渲染语法高亮 + macOS 终端风装饰条 + 复制按钮。

Python

from dataclasses import dataclass

@dataclass
class Article:
    title: str
    word_count: int

    def reading_minutes(self) -> int:
        # 按 500 字/分钟估算(中文阅读速度)
        return max(1, self.word_count // 500)


if __name__ == "__main__":
    a = Article(title="嵌入元素速查", word_count=1200)
    print(f"{a.title} - 约 {a.reading_minutes()} 分钟")

Rust

use std::time::Duration;

/// 单次重试间隔(指数退避)
fn backoff(attempt: u32) -> Duration {
    let base = 200u64;
    let ms = base.saturating_mul(2u64.saturating_pow(attempt));
    Duration::from_millis(ms.min(30_000))
}

fn main(){
    assert!(backoff(0) < backoff(3));
}

Go

package main

import (
    "fmt"
    "time"
)

type Post struct {
    Title     string
    Published time.Time
}

func (p Post) Age() time.Duration {
    return time.Since(p.Published)
}

func main() {
    p := Post{Title: "Hello", Published: time.Now().Add(-72 * time.Hour)}
    fmt.Printf("%q 发布了 %.0f 小时\n", p.Title, p.Age().Hours())
}

TypeScript

type Result<T, E = Error> =
  | { ok: true; value: T }
  | { ok: false; error: E };

async function fetchJson<T>(url: string): Promise<Result<T>> {
  try {
    const res = await fetch(url);
    if (!res.ok) {
      return { ok: false, error: new Error(`HTTP ${res.status}`) };
    }
    return { ok: true, value: (await res.json()) as T };
  } catch (e) {
    return { ok: false, error: e as Error };
  }
}

Shell

#!/usr/bin/env bash
set -euo pipefail

# 部署博客:构建 + 推送
hugo --gc --minify
git add public/ content/
git commit -m "post: 新文章"
git push

SQL

-- 找出本月发表的、阅读数前 10 的文章
SELECT title, views, published_at
FROM posts
WHERE published_at >= date_trunc('month', current_date)
ORDER BY views DESC
LIMIT 10;

无语言名(纯文本,仍带装饰条但无颜色):

+----------+      +-----------+
|  Author  | ---> |  Markdown |
+----------+      +-----------+
                        |
                        v
                  +-----------+
                  |   Hugo    |
                  +-----------+

多语言标签栏

同一段逻辑的多语言实现,用 tabs / tab 包裹,点标签切换。每组的标签名和数量随意,互不联动:

{{< tabs >}}
{{< tab "Java" >}}
(普通 Markdown 代码围栏)
{{< /tab >}}
{{< tab "Kotlin" >}}
(普通 Markdown 代码围栏)
{{< /tab >}}
{{< /tabs >}}
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
fun main() {
    println("Hello, World!")
}
package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

七、行内嵌入:链接 / 图标 / 按键

正文里也能嵌入小元素:

  • 行内代码:使用 git rebase -i HEAD~3 合并提交
  • 键盘:Cmd + Shift + P 打开命令面板
  • 链接:访问 Hugo 官网
  • 缩写:HTML 鼠标悬停看说明

八、嵌入的几个共性

元素是否依赖外部网络是否影响 SEO
YouTube / Vimeo不影响
X 推文不影响
二维码是(首次)不影响
图片(外链)与图床有关
代码块良好

所有嵌入都用了 loading="lazy"async,不会阻塞首屏渲染。代码块的复制按钮是纯前端实现,零依赖。


到这儿就把这个主题里能塞进 markdown 的"非文本"内容都展示完了。写作时按需用即可——不是每篇文章都需要这么花,多数情况下文字 + 一两张图就够。

九、音乐播放器

站内默认开启全局播放器(左下角横条),单篇文章里也可以嵌入专属播放器,或者用纯背景音乐模式。

播放平台歌单 / 单曲

aplayer shortcode 对接主流平台,无需 API Key,传 ID 即可:

{{< aplayer server="tencent" type="playlist" id="7798160336" >}}

效果:

参数:

参数默认说明
servernetease平台:netease(网易云) / tencent(QQ) / kugou / xiami / baidu
typesongsong(单曲) / playlist(歌单) / album(专辑) / artist(歌手) / search(关键词)
id必填平台对应的 ID 或搜索词
minifalse极简模式,只显示一行,省空间
autoplayfalse自动播放(浏览器一般会拦)
theme#2980b9主题色(进度条、按钮 hover 等)
loopallall 列表循环 / one 单曲循环 / none 不循环
orderlistlist 顺序 / random 随机
volume0.70~1,初始音量
listFoldedfalse播放列表默认折叠
fixedfalse固定在左下角横条(文章内不建议开,会与全局播放器重叠)

播放自定义单曲

url 直接指向音频文件(如 R2 / 自建图床),无需平台 ID:

{{< aplayer
    name="风继续吹"
    artist="张国荣"
    url="https://cdn.zero9501.online/music/feng.mp3"
    cover="https://cdn.zero9501.online/cover/feng.jpg"
>}}

效果:

自定义模式新增以下参数(其余通用参数同上):

参数默认说明
url必填音频文件完整 URL
nameUntitled歌名
artistUnknown歌手
cover封面图 URL

隐藏式背景音乐

bgm shortcode 用于"页面 BGM"场景:无可见播放器单曲循环自动播放(首次交互后触发),右上角一个浮动按钮控制暂停/播放。

建议同时在 frontmatter 里关掉全局播放器,避免两个音源同响:

---
title: "..."
disableGlobalPlayer: true
---

{{< bgm url="https://img.zero9501.online/music/talang.mp3" >}}

参数:

参数默认说明
url必填音频文件完整 URL
volume0.50~1,初始音量
positiontop-right浮动按钮位置:top-right / top-left / bottom-right / bottom-left

十、地图嵌入(Google Maps)

gmap shortcode 嵌入 Google Maps,不需要 API Key,从官方复制嵌入 URL 即可。

获取嵌入 URL 的步骤:

  1. 在 Google Maps 打开目标位置
  2. 分享 / Share → 选 嵌入地图 / Embed a map 标签
  3. 复制 iframe 标签里 src="..." 那串完整 URL
{{< gmap src="https://www.google.com/maps/embed?pb=..." >}}

# 自定义高度 + 说明文字
{{< gmap src="..." height="480" caption="东京塔附近" >}}

效果:

示例位置(日本中部山区)

参数:

参数默认说明
src必填Google Maps 嵌入 URL(必须以 https://www.google.com/maps/embed 开头)
height380iframe 高度(px)
caption地图下方说明文字

十一、相册轮播(carousel)

carousel shortcode 把多张图变成可左右切换的相册式轮播,适合"组图回顾"、“对比图”、“旅行片段"这类场景。每行一张图,| 后跟可选说明文字。

{{< carousel >}}
https://picsum.photos/id/1015/1600/900 | 峡谷河湾
https://picsum.photos/id/1018/1600/900 | 雪山湖泊
https://picsum.photos/id/1016/1600/900
{{< /carousel >}}

效果(鼠标移上去显示左右箭头,底部圆点指示当前张数;移动端可左右滑动):

带自动播放(每 3 秒切一张)+ 4:3 比例:

{{< carousel ratio="4/3" autoplay="3000" >}}
url1 | caption1
url2 | caption2
{{< /carousel >}}

参数:

参数默认说明
ratio16 / 9容器宽高比(如 16/9 / 4/3 / 1/1 / 3/2
autoplay0自动切换间隔毫秒,0 关闭;常用 3000~5000
looptrue走到最后一张是否回到第一张;false 时尾页会禁用"下一张"按钮

交互:

  • 鼠标悬停 显示左右切换按钮,自动播放也会暂停
  • 触摸滑动(移动端)拖动 > 40px 触发翻页
  • 键盘 容器获取焦点后 / 切换
  • 单图 自动隐藏所有控件,退化成普通大图

十二、视频文件播放(video)

前面的 YouTube / Vimeo 是嵌入第三方平台。如果视频文件就在自己的图床 / R2 / 静态目录里(.mp4 等),用 video shortcode 直接播放——自带一套贴合主题的深色播放器,零依赖、不加载任何外部脚本:

{{< video src="https://cdn.zero9501.online/video/demo.mp4" >}}

效果(默认 16:9 比例,鼠标移上去显示控制条,播放中静止片刻自动隐藏):

0:00 / 0:00

带封面图 + 适配非 16:9 视频(下面这段是 12:5 的宽幅片,给 ratio 设成它的真实比例即可不留黑边):

{{< video src="/video/wide.mp4" poster="https://picsum.photos/id/180/1600/900" ratio="12/5" >}}
0:00 / 0:00

参数:

参数默认说明
src必填视频文件完整 URL 或站内绝对路径
poster封面图,未播放时显示
ratio16 / 9容器宽高比;非 16:9 视频建议设为其真实比例以免黑边,如 4/3 / 1/1 / 12/5
loopfalse是否循环播放
mutedfalse是否静音(配合 autoplay 才能自动播放)
autoplayfalse是否自动播放(多数浏览器要求同时 muted
preloadmetadata预加载策略:none / metadata / auto

交互:

  • 播放 / 暂停 点画面、中央大按钮,或控制条按钮
  • 进度条 点击跳转,按住左右拖拽快速预览
  • 音量 鼠标移到喇叭上展开音量条,点图标静音
  • 全屏 右下角按钮,或快捷键 F
  • 键盘 容器获得焦点后:空格 / K 播放暂停、 / 快退快进 5 秒、 / 调音量、M 静音、F 全屏
  • 控制条 播放中静止约 2.5 秒自动隐藏,移动鼠标重新显示