品牌外观
本页覆盖站点外观:站名与 Logo 写在 hugo.yml,配色与字体走 SCSS 入口,页宽与页脚形态是参数。前提是站点已能构建(十分钟上手)。
需要改动的文件有四个:hugo.yml、static/ 下的图标、assets/scss/_variables_project.scss、assets/scss/_styles_project.scss。不要改主题目录里的文件:主题是 Hugo Module,升级时整个目录会被替换。
站名
站名出现在顶栏、浏览器标题与页脚。多语言站每种语言各写一个:
顶层 title 是兜底,languages.<lang>.title 优先。
Logo 与字标
主题默认使用自带的 assets/icons/logo.svg。替换步骤是把图标文件放进站点的 assets/ 或 static/,再在配置里指向它。
params.logo是方形图标,顶栏、侧栏与页脚共用。放在assets/下会经过 Hugo 资源管线(可指纹化),放在static/下按原样发布;两种写法都是相对assets/、static/根的路径。params.wordmark是横向字标。设置后顶栏用它替代「图标 + 站名」,窄屏放不下时回落到params.logo。不设置则保持「图标 + 站名」。
源 SVG 应紧贴图形边缘裁切,否则各处尺寸对不齐。SVG 必须带 viewBox,颜色继承 currentColor,或者在深浅色下都有足够对比度。
本站两个参数都不设:顶栏用主题自带的 assets/icons/logo.svg 搭配以展示字体渲染的站名。
favicon
favicon 没有参数。主题扫描站点 static/ 目录里的约定文件名,发现哪个就在每个页面输出对应的 <link>:
| 文件 | 生成的链接 |
|---|---|
static/favicon.ico |
rel="icon" |
static/favicon.svg |
rel="icon" type="image/svg+xml" |
static/favicon-32x32.png |
rel="icon" 带 sizes,按尺寸升序输出 |
static/apple-touch-icon.png |
rel="apple-touch-icon" |
static/apple-touch-icon-180x180.png |
rel="apple-touch-icon" 带 sizes |
够用的最小组合是 favicon.ico + favicon.svg + apple-touch-icon.png。带尺寸后缀的文件必须是正方形(NxN),否则不会被识别。
这些文件用任意图形工具生成即可。主题不需要 Node.js,Hugo 只发布 static/ 里已经存在的文件。
Web App Manifest 一类的额外 head 元数据不在扫描范围内,用 layouts/_partials/hooks/head-end.html 钩子自行输出;要改变发现规则本身(换目录、增加文件名),在站点 layouts/ 下覆盖 layouts/_partials/favicons.html。
主色与配色
配色分两层:Bootstrap 的语义色(编译期 Sass 变量)和 OINK 的品牌层(运行期 CSS 自定义属性)。
先改语义色,它决定按钮、链接、提示块的色调:
这个文件在 Bootstrap 与 OINK 默认值 之前 加载,是覆盖 Sass 变量的位置。需要引用 Bootstrap 已定义的变量或 map 时,改用 _variables_project_after_bs.scss。
品牌层是一组 CSS 自定义属性,浅色和深色 必须成对覆盖,否则一种模式下会漏色:
可覆盖的品牌属性有 --td-brand-elev(浮层底色)、--td-brand-silk(次要文字)、--td-brand-copper 与 --td-brand-copper-dim(强调色与它的弱化版)、--td-brand-line-strong(分隔线)、--td-brand-header-bg(顶栏背景)、--td-brand-shadow-sm / --td-brand-shadow-md(阴影)、--td-brand-mark-from / --td-brand-mark-to / --td-brand-mark-gradient(品牌渐变)。
深浅色模式
主题默认 不显示 深浅色控件。开启方式:
开启后顶栏出现一个主题控件:点击在浅色与深色之间切换,悬停或键盘聚焦展开「跟随系统 / 浅色 / 深色」。读者的选择存在浏览器本地,没有选择时跟随 prefers-color-scheme。切换脚本在首屏绘制前设置好 data-bs-theme,不会出现主题闪烁。
只要深色调色板、不要控件时写 dark_mode: { show_menu: false, enable: true };dark_mode: false(默认)两者都不启用。
自定义组件在两种模式下都要给出可读的悬停、聚焦、禁用、选中状态,正文对比度至少 4.5:1、大号文字 3:1。
字体
字体有两档预设,在构建期决定,不涉及 JavaScript:
technical(默认):界面与正文用随主题分发的 Inter(可变字重,拉丁 / 西里尔 / 希腊 / 越南语子集,中文与 emoji 落到平台字体),标题装饰用 Chakra Petch,代码用 IBM Plex Mono。字体文件都是本地的,不请求 Google Fonts。system:界面、展示、元数据、打印与等宽角色全部回到平台字体栈,浏览器不请求品牌字体。字体文件仍随主题分发,只是不被引用。
非法取值让构建失败(invalid params.ui.typography)。选中的值写入 <html data-td-typography="…">,可在浏览器中确认。
自定义字体
字体角色是七个 CSS 自定义属性,覆盖它们即可,不必查找组件选择器:
| 属性 | 用在哪 |
|---|---|
--td-ui-font-family |
导航、控件与界面文字 |
--td-body-font-family |
正文与博客 |
--td-heading-font-family |
正文标题 |
--td-code-font-family |
代码与终端 |
--td-display-font-family |
字标与展示型大标题 |
--td-meta-font-family |
技术标签与元数据 |
--td-print-font-family |
打印正文 |
把 .woff2 放进站点 static/webfonts/,在项目样式里声明字面,再改写角色:
角色按 CSS 规则继承,只给某类内容换字体也不必复制组件选择器:
等宽字体要带中文兜底,否则中英混排的代码块会对不齐:
从 Docsy 迁移过来的站点不必改写法。旧的 Sass 变量仍然喂进对应角色,写在 _variables_project.scss 里照样生效,优先级高于预设默认值:
| 旧 Sass 变量 | 喂给的字体角色 | 说明 |
|---|---|---|
$td-fonts-serif |
--td-ui-font-family / --td-body-font-family |
Docsy 的界面字体栈,赋值给 $font-family-sans-serif |
$font-family-sans-serif |
--td-ui-font-family / --td-body-font-family |
项目给出自己的栈时,technical 预设不再把 Inter 放在它前面 |
$font-family-base |
--td-ui-font-family / --td-body-font-family |
Bootstrap 的正文变量,经 --bs-body-font-family 进入角色 |
$headings-font-family |
--td-heading-font-family |
不设置时标题继承正文角色 |
$font-family-code |
--td-code-font-family |
代码、终端与 pre / code / kbd |
$td-font-family-monospace |
--bs-font-monospace |
赋值给 $font-family-monospace |
$font-family-monospace |
--bs-font-monospace |
system 预设下,项目的显式取值优先于平台等宽栈 |
Docsy 的三个 Google Fonts 变量 $td-enable-google-fonts、$td-google-font-name 与 $td-web-font-path 主题已不再读取。它们留在 _variables_project.scss 里不影响构建,也不产生任何效果:随主题分发的是 Inter、Chakra Petch 与 IBM Plex Mono,两档预设都不向 Google Fonts 发请求。打印角色 --td-print-font-family 跟随正文角色,主题不为纸张单独提供字体。
YAML 里不接受远程字体 URL,也不接受任意 CSS:字体文件与样式都必须是可审查的本地输入。
页宽
page_width 控制外壳整体宽度,可逐页或按分区 cascade 覆盖。Book 页另有一个 reading_width(slim / normal / wide),改的是正文阅读行宽,不是外壳。两个键取值非法都让构建失败。
页脚
fat(默认):多列链接网格 + 版权行;slim:只有版权行;none:不渲染页脚。
页面 front matter(含分区 cascade)可以覆盖它,本站的文档栏目用的是 footer_style: slim。无法识别的取值让构建失败。
多列网格的数据在 data/footer/<语言>.yaml,写法见导航与菜单。配了 fat 但没有数据时自动降级成 slim,可以先开启再补内容。
params.copyright 接受 Markdown 字符串,或 authors / from_year / to_year 三键的 map(present 表示今年)。footer_center_info 是页脚中间的行内 Markdown,显式设为空字符串即隐藏中间区域。
SCSS 入口与不该做的事
站点的 SCSS 覆盖进入主题的同一个样式包,生产构建仍然只有一份带指纹与完整性校验的样式表。三个入口文件放在站点 assets/scss/ 下:
| 文件 | 什么时候用 |
|---|---|
_variables_project.scss |
在 Bootstrap 与 OINK 默认值之前设置 Sass 变量($primary、字体变量) |
_variables_project_after_bs.scss |
设置依赖 Bootstrap 已有定义的变量或 map |
_styles_project.scss |
在主题组件样式之后写选择器与 CSS 自定义属性 |
编译顺序是:Bootstrap 函数 → 项目变量 → OINK 默认值与 Bootstrap → Bootstrap 之后的项目变量 → OINK 组件与品牌层 → 项目样式。
CSS 接口有明确边界。字体那一节的七个字体角色与 --td-brand-* 品牌属性是公开接口,主题在小版本之间保持它们的名字与含义。组件别名(如 --td-asciinema-font-family)只承诺在该组件范围内有效,未在文档中记录的 --td-shell-* 一类变量是实现细节,随时可能改名或消失。
不该做的事:
- 不改主题目录里的任何文件(
hugo mod会覆盖); - 不单独
@import主题的内部 partial,它们不是公开的 Sass 接口,导入顺序可能变化; - 不为了改一个颜色去覆盖
baseof.html。有设计变量就用变量,没有再写作用域尽量小的选择器; - 不引用远程样式表或字体 CDN。
需要额外的第三方 CSS 时,用 layouts/_partials/hooks/head-end.html 钩子发布本地资源,不在 Markdown 里写 <link>。
验证
- 构建输出
Total in …,没有 ERROR / WARN; - 页面源码里
<html>上有data-td-typography="technical"(或所选的预设); - 浏览器中顶栏显示自己的 Logo 与站名,标签页图标是自己的 favicon;
- 切到深色模式再看一遍正文、表格、提示块、代码块与焦点框。配色改动容易只在一种模式下验证过;
- 换一种语言,确认站名随之切换。
字体是否已替换,用浏览器开发者工具查任意一段正文的 font-family:应当是自己声明的字面,而不是 Inter。
相关
- 配置总览 — 品牌相关参数的类型与默认值
- 导航与菜单 — 顶栏菜单、页面操作与页脚数据
- 布局与页面类型 — 外壳、侧栏与目录
- 图片 — 正文里的图片、深浅色双图与图注
- 首页与落地页 — Hero、分区与落地页数据