本说明文档面向两类使用者:

  • 使用者:只想通过配置项切换不同皮肤风格
  • 开发者:希望在保持 Butterfly 主题结构不变的前提下,新增或修改皮肤

本文只关注“皮肤层”的能力:即所有可以通过 Stylus/CSS 覆盖实现的视觉定制,包括但不限于:

  • 全局背景与纹理
  • 顶部 Banner 区域
  • 首页文章卡片
  • 右栏卡片
  • 页脚区域
  • 滚动条、按钮、右侧悬浮按钮
  • 文章版权卡片结构与样式(新增 Pug 定制)
  • 代码块主题配色(新增变量覆盖与样式强制)
  • Markdown 表格样式(新增局部覆盖)
  • 多页面统一背景逻辑(新增容器覆盖)
  • 其他能通过选择器选中并装饰的部分

皮肤生态整体设计

  • 不改主题结构,不动业务逻辑

    • 保持 Hexo + Butterfly 的模板结构和功能不变
    • 只在样式层(Stylus)做“换皮肤”
  • 通过配置切换皮肤

    • 使用 skin.preset 指定当前皮肤
    • 每个皮肤对应一份独立的 .styl 文件
  • 皮肤之间互相隔离

    • 每个皮肤文件只负责自己的配色和装饰
    • 切换 skin.preset ≈ 一键切换整站视觉方案
  • 深度定制与进阶能力

    • 超越纯 CSS:支持通过 Pug 模板分支实现结构级定制(如版权卡片)。
    • 模式隔离:支持为亮色/暗色模式定义完全不同的视觉逻辑。
    • 组件级接管:支持接管 Banner、背景、代码块配色、表格样式、标签样式等核心组件。

配置入口与目录结构

配置入口:skin.preset

文件:themes/butterfly/_config.yml

skin:
preset: YourSkinName

皮肤生态整体设计

  • 配置驱动,一键切换

    • 通过 skin.preset 配置项,一键切换整站视觉方案(配色、背景、组件样式、交互动画)。
    • 每个皮肤对应一份独立的 .styl 文件,互相隔离,互不干扰。
  • 不改主题结构,不动业务逻辑

    • 保持 Hexo + Butterfly 的模板结构和功能不变,只在样式层(Stylus)做“换皮肤”。
    • 即使是 Pug 结构的修改,也是通过配置项开关控制的,确保原主题逻辑的纯净。
  • 深度定制与进阶能力

    • 超越纯 CSS:支持通过 Pug 模板分支实现结构级定制(如版权卡片)。
    • 模式隔离:支持为亮色/暗色模式定义完全不同的视觉逻辑。
    • 组件级接管:支持接管 Banner、背景、代码块配色、标签样式等核心组件。

配置入口与目录结构

配置入口:skin.preset

文件:themes/butterfly/_config.yml

skin:
preset: YourSkinName

说明:

  • skin.preset 是当前启用皮肤的名字(自定义字符串,大小写敏感)
  • 推荐命名规则:
    • 英文:red, Spring_festival, Dark_ink
    • 或者中文:锦绣, 墨色 等,只要和 Stylus 中的判断一致即可

样式入口:index.styl

文件:themes/butterfly/source/css/index.styl

示意:

$skinPreset = hexo-config('skin.preset') ? hexo-config('skin.preset') : ''

if $skinPreset == 'red'
@import 'skins/red'

if $skinPreset == 'Spring_festival'
@import 'skins/spring_festival'

// ...

说明:

  • 使用 hexo-config('skin.preset') 读取 _config.yml 中的配置值
  • 根据不同 preset 名称,@import 不同的皮肤文件
  • 你可以按需增加 if $skinPreset == 'XXX' 分支,每个分支对应一个皮肤

皮肤文件目录

文件目录:themes/butterfly/source/css/skins/

每个皮肤是一份 Stylus 文件,例如:

skins/
red.styl
spring_festival.styl
dark_ink.styl
...

约定:

  • 一个皮肤 = 一个 .styl 文件
  • 每个文件内部按模块组织:背景、Banner、卡片、右栏、页脚、滚动条等

皮肤能定制的能力清单

本节总结这套生态在不改 Pug 模板前提下,能通过 Stylus 直接定制的所有重要部分,并说明对应的选择器和修改方式。

3.1 全局背景与纹理(包括图片叠加)

目标:控制页面整体氛围:纸张颜色、光晕、纹理图片等。

推荐修改位置:皮肤文件中的 body 选择器。

示例(简化):

body
background-color rgba(255, 255, 255, .98)
background-image:
radial-gradient(...), // 底部或侧边光晕
radial-gradient(...),
linear-gradient(rgba(255, 255, 255, .5), rgba(255, 255, 255, .5)), // 半透明白蒙版
url('/img/your_texture.png') // 纹理图片
background-repeat no-repeat
background-size cover
background-position center center

可做的事:

  • background-color 控制整体基底色(冷暖调)
  • 用多层 radial-gradientlinear-gradient 制作光晕、阴影、纸面质感
  • 在最后叠加一张或多张图片(城市、纹理、插画等)
  • 通过半透明白色渐变模拟“再淡一点”的蒙版效果

与 Butterfly 自带的 theme.background 的关系:

  • 如果你只在皮肤文件中控制 body 背景:
    • 可以不使用 theme.background
  • 如果你需要保留 theme.background
    • 可以在皮肤中只画渐变或纹理,不强制覆盖 #web_bg 背景图片

顶部 Banner(覆盖 default_top_img 限制)

目标:让每个皮肤拥有独立的 Banner 图与光效,而不是所有皮肤共用一张配置里的图片。

相关结构:

  • Banner 容器:#page-header
  • 由 Butterfly 在 Pug 中注入默认背景图(default_top_imgindex_img 等)

在皮肤文件中,你可以通过以下方式接管 Banner 背景:

#page-header
position relative
overflow hidden
background-image url('/img/your_banner.png') !important
background-position center center
background-size cover
background-color transparent

#page-header::before
content ''
position absolute
inset 0
background:
radial-gradient(...),
radial-gradient(...)
pointer-events none
opacity .9

可做的事:

  • 使用 background-image url(...) !important 为当前皮肤指定自己的 Banner 图
  • 使用 ::before 叠加光效(白光、云雾、色块等)
  • 在不同皮肤中使用不同的 Banner 图片和光效组合,实现“换皮肤 = 换 Banner”

注意:

  • !important 用于覆盖 Butterfly 在行内样式中设置的背景图片
  • 如果你想继续尊重主题配置里的 default_top_img,可以不写 background-image,只在 ::before 上做装饰

首页文章卡片(纸张、挑染、边框、印章等)

目标:在不增加额外 DOM 的前提下,为首页文章列表增加质感和装饰。

典型结构:

  • 卡片容器:.recent-posts .recent-post-item
  • 卡片标题:.recent-posts .article-title

你可以在皮肤中定义:

.recent-posts .recent-post-item
position relative
border 1px solid rgba(0, 0, 0, .08)
background #fffdf8
overflow hidden
transition: transform .2s ease-out, box-shadow .2s ease-out, border-color .2s ease-out

.recent-posts .recent-post-item__pattern
position absolute
inset 0
background:
radial-gradient(...),
radial-gradient(...)
pointer-events none

.recent-posts .recent-post-item::before
// 顶部短装饰条

.recent-posts .recent-post-item::after
// 四角装饰线 / 折线边框

.recent-posts .article-title
color #3d1b1b

.recent-posts .article-title:hover
color #主色

可做的事:

  • background 控制卡片的纸张基底色
  • __pattern 内的渐变做卡片内部挑染
  • ::before::after 画金线、角落折线、印章、纹章等
  • article-title 控制标题颜色与悬停色

说明:

  • __pattern 这个类名只要和模板结构对应,即可在皮肤文件中用来承载纹理与光点
  • 所有装饰都通过伪元素绘制,无需增加额外 HTML 标签

右栏卡片(顶部线条、卡片底色、标题风格)

目标:让侧栏卡片与首页卡片共享同一套视觉语言。

相关结构:

  • 右栏卡片容器:.card-widget
  • 右栏卡片标题:.card-widget .item-headline

示例:

.card-widget
position relative
border 1px solid rgba(0, 0, 0, .08)
background rgba(255, 255, 255, .96)
box-shadow 0 6px 18px rgba(0, 0, 0, .08)
overflow hidden

.card-widget::before
content ''
position absolute
left 12px
right 12px
top 0
height 2px
background linear-gradient(90deg, #金色1, #金色2, #金色1)
background-size 200% 100%
animation your-border-animation 12s linear infinite
opacity .95
pointer-events none

.card-widget .item-headline
position relative
color #标题色
letter-spacing .06em

可做的事:

  • 为每个右栏卡片顶部增加一条渐变横线(可做成流动金线)
  • 调整右栏卡片的底色、边框、阴影,使之与首页卡片统一
  • 调整右栏标题颜色、字距,打造一致的文字风格

页脚区域(底色、挑染、链接高亮)

目标:让页脚看上去是整套设计的一部分,而不是单独的条款信息。

相关结构:

  • 页脚容器:#footer
  • 页脚其他信息区:#footer .footer-other
  • 页脚链接:#footer .footer-other a

示例:

#footer
position relative
background #fff4ea
border-top 1px solid rgba(0, 0, 0, .08)
overflow hidden

#footer::before
content ''
position absolute
inset 0
background:
radial-gradient(...),
radial-gradient(...)
pointer-events none

#footer .footer-other a
color #链接默认色

#footer .footer-other a:hover
color #金色高亮

可做的事:

  • 统一调整页脚底色和挑染,保证与首页卡片风格相连
  • 设置页脚链接 hover 时的颜色(如统一金色)
  • 若你在 Pug 中调整了页脚文案结构,也可以通过这里补充装饰(背景、分割线等)

滚动条、按钮、右侧悬浮按钮

目标:让细节部分也跟随皮肤风格变化。

相关结构示例:

::-webkit-scrollbar
width 3px

::-webkit-scrollbar-thumb
background:
linear-gradient(to bottom,
transparent 0,
transparent 25%,
rgba(主色, .8) 25%,
rgba(主色, .8) 75%,
transparent 75%,
transparent 100%)
border-radius 999px

::-webkit-scrollbar-thumb:hover
background:
linear-gradient(to bottom,
transparent 0,
transparent 25%,
rgba(主色_hover, .9) 25%,
rgba(主色_hover, .9) 75%,
transparent 75%,
transparent 100%)

#rightside > div > button,
#rightside > div > a
background-color #按钮底色
color #按钮文字色

#rightside > div > button:hover,
#rightside > div > a:hover
background-color #按钮hover底色
color #按钮hover文字色

可做的事:

  • 控制滚动条粗细、颜色、圆角,让其更轻、更符合整体配色
  • 控制右下角按钮的底色和 hover 色
  • 为不同皮肤设置不同按钮风格

暗色模式适配

目标:确保皮肤在暗色模式下不仅可用,还能自动切换为专属的夜间视觉。

相关结构:

  • Butterfly 使用 [data-theme="dark"] 属性标记暗色模式。
  • 皮肤文件中可以通过该属性嵌套样式,覆盖默认的背景图或颜色。

示例:

// 暗色模式背景设置
[data-theme="dark"]
body
background-image url('/img/beijingdark.png') !important

#page-header
background-image url('/img/headbannerdark.png') !important
// 可选:加一层遮罩,防止文字看不清
&::before
background-color rgba(0, 0, 0, 0.5)

// 进阶:黑金风格卡片配色(示例)
.card-widget, #post
background: linear-gradient(145deg, #181818, #202020) !important
border: 1px solid rgba(212, 175, 55, 0.2) !important
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.8) !important

可做的事:

  • 为暗色模式准备一套独立的“夜间背景图”(如 beijingdark.png
  • 调整遮罩透明度,保证文字在深色背景上的对比度
  • 覆盖特定组件的颜色(如果默认反色效果不理想)

交互细节优化

目标:提升用户体验,增加精致感。

相关结构:

  • CSS 伪类 :hover 用于悬停效果。
  • transition 属性用于平滑过渡。
  • 强制样式覆盖(!important)用于修正主题默认行为。

示例:

// 强制右下角按钮始终显示
#rightside
opacity: 1 !important
transform: translate(-58px, 0) !important

// 社交图标悬停效果(渐变金)
.card-info-social-icons .social-icon:hover
background linear-gradient(135deg, #f8d583 0%, #d4af37 100%) // 增加质感
transform translateY(-4px) scale(1.1)

可做的事:

  • 修复亮色模式下某些图标颜色不明显的问题
  • 为重要按钮添加细腻的悬停动画(如缩放、阴影、渐变背景)
  • 强制覆盖某些交互组件的显示逻辑(如始终显示右下角工具栏)

文章底部标签(标签云与分享区)

目标:让文章末尾的标签展示区与皮肤风格融合,支持磨砂、光晕等高级质感。

相关结构:

  • 标签容器:#post .tag_share .post-meta__tags
  • 标签文字:.post-meta__tags(也是容器本身)

在皮肤文件中,我们可以利用 !important 覆盖默认的边框和背景,甚至添加 backdrop-filter 实现毛玻璃效果。

示例(亮色与暗色模式区分):

// 亮色模式:柔和色调 + 磨砂
#post .tag_share .post-meta__tags
background-color rgba(255, 255, 255, 0.8) !important
color #333 !important
border 1px solid #淡主色 !important
backdrop-filter blur(5px) // 关键:磨砂效果
-webkit-backdrop-filter blur(5px)
transition all .3s ease-in-out
border-radius 8px

&:hover
background-color rgba(主色, 0.1) !important
border-color #主色 !important
box-shadow 0 2px 8px rgba(主色, 0.2)

// 暗色模式:发光边框 + 透明底
[data-theme="dark"] #post .tag_share .post-meta__tags
background-color transparent !important
color var(--font-color) !important
border 1px solid #666 !important
box-shadow none !important

&:hover
background-color rgba(主色, 0.1) !important
border-color #主色 !important
box-shadow 0 0 8px rgba(主色, 0.6) !important // 发光效果

可做的事:

  • 磨砂质感:通过 backdrop-filter: blur() 让标签背景模糊背后的元素(如纸张纹理)。
  • 光晕交互:在 hover 状态下添加带颜色的 box-shadow,模拟发光。
  • 模式隔离:利用 [data-theme="dark"] 为夜间模式设计完全不同的交互逻辑(如夜间发光,白天变色)。

代码块风格(全局展开与局部配色)

目标:控制代码块的默认交互状态(折叠/展开)以及与皮肤主题一致的配色。

1. 全局交互配置

themes/butterfly/_config.yml 中控制代码块是否默认折叠:

code_blocks:
shrink: false # false: 默认展开 | true: 默认折叠 | none: 展开且隐藏按钮

2. 皮肤局部配色(CSS 变量覆盖)

Butterfly 使用 --hl-* 系列 CSS 变量定义代码块颜色。你可以在皮肤文件中覆盖这些变量,使其完美适配亮色/暗色模式。

示例:

// 亮色模式:自定义高亮配色
:root
--hl-color: #5c3d2e !important
--hl-bg: #f2e6ce !important
--hltools-bg: #e6dcc0 !important
--hltools-color: #5c3d2e !important
--hlnumber-bg: #f2e6ce !important
--hlnumber-color: rgba(92, 61, 46, 0.4) !important
--hlscrollbar-bg: #d4af37 !important
--hlexpand-bg: linear-gradient(180deg, rgba(242, 230, 206, .6), rgba(242, 230, 206, .9)) !important

// 暗色模式:自定义高亮配色
[data-theme="dark"]
--hl-color: #d4af37 !important
--hl-bg: #1f1f1f !important
// ... 其他变量

3. 进阶:强制覆盖 highlight.js 语法颜色

如果 CSS 变量无法满足需求(例如:浅色背景下默认的高亮颜色太淡,看不清),可以直接通过 CSS 选择器强制修改 highlight.js 的类名颜色。

示例:

// 强制覆盖 highlight.js 注释颜色为传统绿色,去除斜体
.highlight .comment
color: #388e3c !important
font-style: normal !important

// 强制覆盖关键字、字符串等颜色
.highlight
.keyword, .function .keyword
color: #7b1fa2 !important // 深紫
.string
color: #c62828 !important // 深红
.title
color: #1565c0 !important // 深蓝

Markdown 表格样式定制

目标:自定义文章内 Markdown 表格的边框颜色,使其适应不同的背景色(如浅色纸张背景需要深色边框)。

注意: Butterfly 的代码块内部也使用了 table 标签。为了避免误伤代码块,必须将选择器限定在 .table-wrap 容器内。

示例:

// 亮色模式:深色边框
#post .table-wrap table th,
#post .table-wrap table td
border-color: #5c3d2e !important
border-bottom: 1px solid #5c3d2e !important
border-left: 1px solid #5c3d2e !important

#post .table-wrap table
border: 1px solid #5c3d2e !important

// 暗色模式:恢复默认半透明白边框(防止被亮色模式影响)
[data-theme="dark"]
#post .table-wrap table th,
#post .table-wrap table td
border-color: rgba(255, 255, 255, 0.1) !important
// ...

多页面统一背景逻辑

目标:将文章页(Post)的特殊背景(如纸张纹理、阴影)应用到其他独立页面(如归档、标签、分类、友链等),保持视觉统一。

Butterfly 的页面容器 ID 各不相同,常见的有:

  • 文章页:#post
  • 归档页:#archive
  • 标签/分类/独立页:#page, #tag, #category

在皮肤文件中,可以将这些选择器组合起来,统一应用样式:

// 统一应用背景与磨砂效果
#post,
#page,
#archive,
#tag,
#category
position relative
background rgba(255, 252, 245, 0.6) !important
backdrop-filter blur(25px) !important
border 1px solid rgba(255, 255, 255, 0.4) !important

// 统一应用伪元素纹理
#post::before,
#page::before,
#archive::before,
#tag::before,
#category::before
content ''
position absolute
// ... 纹理样式

通过这种方式,只需写一次样式,即可让整站所有页面(除首页外)拥有一致的“纸张”体验。


超出纯 CSS 的进阶定制(Pug 修改)

有时仅靠 CSS 无法满足复杂的结构需求(例如:想把版权信息做成三列卡片,或者去掉硬编码的括号符号)。此时,我们需要通过“配置驱动”的方式修改 Pug 模板。

原则

  • 配置驱动:不在 Pug 中写死逻辑,而是通过 _config.yml 中的配置项开关来控制。
  • 动态类名:将 theme.skin.preset 注入到 HTML 的 class 中,让 CSS 能针对不同皮肤应用不同样式。
  • 数据纯净:HTML 结构只负责输出数据(如作者名),不包含装饰符号(如 [ ]),将装饰权交给 CSS。

案例:文章版权卡片(post-copyright)

目标:实现一个“亚克力悬浮卡片”样式的版权栏,且不带原有的 [ ] 符号。

1. 配置项

_config.yml 中新增 style 字段:

post_copyright:
enable: true
style: acrylic # 指定使用 acrylic 结构

2. Pug 模板改造

文件:themes/butterfly/layout/includes/post/post-copyright.pug

我们增加了一个 if theme.post_copyright.style === 'acrylic' 的分支,并注入了 theme.skin.preset 作为类名:

if theme.post_copyright.enable && page.copyright !== false
// 新增的亚克力结构分支
if theme.post_copyright.style === 'acrylic'
- const preset = theme.skin && theme.skin.preset ? theme.skin.preset : ''
// 注入当前皮肤名作为 class,例如 .post-copyright.acrylic.red
.post-copyright.acrylic(class=preset)
.copyright-title= page.title
.copyright-link
a(href=url_for(url))= theme.post_copyright.decode ? decodeURI(url) : url
.copyright-grid
.grid-item.author
.label 作者
.value
// 纯净数据,不带 [ ]
a(href="...") Caelum
// ... 其他项
else
// 原有的默认结构
.post-copyright
// ...

3. 皮肤文件适配

在皮肤文件(如 red.styl)中,针对该结构编写样式:

// 针对 acrylic 结构 + _red 皮肤的特定样式
.post-copyright.acrylic.red
background rgba(255, 251, 240, 0.6) // 亚克力半透明
backdrop-filter blur(10px) // 毛玻璃
border-radius 12px

.copyright-grid
display flex
gap 2rem

.grid-item
.label
color #8b6f5c
.value
a
// 如果需要加括号,可以在这里用 ::before { content: '[' }
// 当前设计不需要括号,直接显示文字
color #7a1a18

通过这种方式,我们实现了:

  1. 结构可配:通过 style: acrylic 开启新结构。
  2. 样式隔离:只有 red 皮肤会应用上述 CSS,其他皮肤可以定义完全不同的外观。
  3. 符号控制:Pug 中不写括号,皮肤 CSS 决定是否加括号,实现了真正的样式与内容分离。

如何新增一个皮肤

以新增皮肤 My_new_skin 为例。

步骤 1:创建 Stylus 文件

themes/butterfly/source/css/skins/ 下新建:

my_new_skin.styl

建议在文件内部按模块组织:

// 全局背景与纹理
body
...

// 顶部 header / banner
#page-header
...
#page-header::before
...

// 首页文章卡片
.recent-posts .recent-post-item
...
.recent-posts .recent-post-item__pattern
...
.recent-posts .article-title
...

// 右栏卡片
.card-widget
...
.card-widget::before
...
.card-widget .item-headline
...

// 页脚
#footer
...
#footer::before
...
#footer .footer-other a
...

// 滚动条 / 右侧按钮等
::-webkit-scrollbar
...
#rightside > div > button
...

步骤 2:在 index.styl 中引入

编辑 themes/butterfly/source/css/index.styl

$skinPreset = hexo-config('skin.preset') ? hexo-config('skin.preset') : ''

if $skinPreset == 'My_new_skin'
@import 'skins/my_new_skin'

步骤 3:在配置中启用

编辑 themes/butterfly/_config.yml

skin:
preset: My_new_skin

步骤 4:重新生成博客

hexo clean
hexo g

刷新浏览器,即可看到新皮肤生效。


在现有皮肤上进行修改

如果你已经有一个皮肤文件,并且想在其基础上进行调整:

  1. 找到对应 .styl 文件(例如 skins/red.styl 或其他)
  2. 根据上文的能力清单,定位你要改的模块:
    • 背景 → body
    • Banner → #page-header#page-header::before
    • 首页卡片 → .recent-posts .recent-post-item
    • 右栏卡片 → .card-widget
    • 页脚 → #footer
    • 滚动条 / 按钮 → 相关选择器
    • 版权卡片.post-copyright.acrylic.YourSkinName
  3. 在皮肤文件里直接调整颜色、渐变、图片路径等
  4. 执行 hexo clean && hexo g 重新生成

注意事项与建议

  • 命名一致性

    • _config.yml 中的 preset 字符串必须与 index.styl 中的判断相同
    • 文件名不一定必须相同,但建议保持一致,便于维护
  • 样式隔离

    • 尽量把视觉逻辑写在皮肤文件中,不要散落到其他通用 Stylus 文件
    • 避免使用过于泛化的选择器(例如直接 a { ... }),以免影响第三方组件
  • 与主题配置的关系

    • 如果皮肤已经接管了某块区域(例如 Banner 背景图),可以适当简化主题配置,减少冲突来源
    • 若要兼容旧配置,可以只在皮肤中做“装饰层”(如 ::before),不去改行内背景图
  • 回退方式

    • 如遇某个皮肤出现样式问题,可以在 _config.yml 中暂时改回其他稳定皮肤
    • 或者临时注释掉 index.styl 中对应 @import 分支,恢复默认主题样式

进阶示例:让皮肤“动起来”的关键部位

本节不依赖任何特定皮肤,只说明“生态层面”允许你修改的关键区域,以及推荐的做法。你可以自由组合这些能力,设计完全不同的视觉方案。

文章正文纸张背景(独立于全局背景)

典型需求:只想让“文章正文区域”看起来像铺在宣纸上,而不改变首页 / 侧栏 / 页脚的背景。

通用思路:

  • 找到文章正文的外层容器(常见选择器:#post#article-container.post-block 等)
  • 在皮肤文件中,只对这个容器设置多层背景和纹理
  • 用伪元素 ::before::after 叠加宣纸噪点、网格等效果
  • z-index 确保文字和图片浮在纹理之上

示例(以 #post 为例):

#post
position relative
background:
radial-gradient(circle at 20% 50%, rgba(212, 175, 55, .15) 0, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(198, 134, 111, .2) 0, transparent 50%),
linear-gradient(135deg, #faf6f1 0, #f0e6d8 100%)
overflow hidden

#post::before
content ''
position absolute
inset 0
background-image url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' /%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E")
pointer-events none

#post::after
content ''
position absolute
inset 0
background-image:
linear-gradient(rgba(212, 175, 55, .03) 1px, transparent 1px),
linear-gradient(90deg, rgba(212, 175, 55, .03) 1px, transparent 1px)
background-size 50px 50px
pointer-events none

#post > *
position relative
z-index 1

你可以把上面的颜色、渐变位置、纹理强度全部替换掉,只保留“结构”:

  • 外层容器:负责纸张底色和整体渐变
  • ::before:负责噪点 / 纸纹
  • ::after:负责网格 / 装饰线
  • 子元素提高 z-index:保证内容清晰可读

右侧卡片交互(网站信息 / 分类 / 归档 / 最新文章)

目标:在不改 Pug 结构的前提下,为右侧卡片的每一行加上:

  • 悬停时的背景渐变(例如左侧金色光晕向右扩散)
  • 左侧竖线(类似书页边侧的装饰线或书签)
  • 细微的缩进或扩展动画(hover 动画幅度可控)

典型结构(以 Butterfly 为例,实际以主题为准):

  • 网站信息项:.card-widget.card-webinfo .webinfo-item
  • 最新文章项:.card-widget.card-recent-post .aside-list .aside-list-item
  • 分类项:.card-widget.card-categories .card-category-list-item > a
  • 归档项:.card-widget.card-archives .card-archive-list-item > a

可以在皮肤文件中为这些“行”统一定义悬停效果,例如:

// 行内左侧装饰竖线
.card-widget.card-webinfo .webinfo-item::before
content ''
position absolute
left -10px // 控制竖线距离文本的距离,可微调
top 50%
transform translateY(-50%)
width 3px
height 60%
background linear-gradient(180deg, rgba(212, 175, 55, .8), transparent)

// 悬停时背景渐变 + 轻微横向扩展
.card-widget.card-webinfo .webinfo-item:hover
background linear-gradient(90deg, rgba(212, 175, 55, .05), transparent)
margin 0 -6px // 控制“伸出卡片”的幅度
padding-left 10px
padding-right 10px
border-radius 4px

对于“分类 / 归档 / 最新文章”模块,只要换成对应选择器即可,实现统一或差异化的交互风格。

建议:

  • 保持 hover 动画的位移值适中(如 6px 以内),避免内容感觉“弹出过头”
  • 竖线的 left 位置与卡片 padding 配合,确保不会被卡片裁剪掉

目录(TOC)当前章节高亮与悬停样式

目标:在文章页右侧“目录”卡片中:

  • 高亮当前阅读的小节(active 状态)
  • 调整鼠标悬停时的文字颜色、背景、是否放大等

典型结构:

  • 目录容器:#card-toc.card-widget
  • 每一项链接:.toc-link
  • 当前激活项:.toc-link.active(或主题定义的当前项类)

示例:

// 当前阅读章节的高亮
#aside-content #card-toc.card-widget .toc-link.active
color #d4af37
background rgba(212, 175, 55, .08)
border-left 3px solid #d4af37

// 悬停样式:只改颜色,不做缩放
#aside-content #card-toc.card-widget .toc-link:hover
color #d4af37
background transparent
transform none
box-shadow none

这样,皮肤可以独立决定:

  • active 项用什么颜色和背景突出当前章节
  • hover 时是否带背景、是否带缩放动画

全局文本 hover 背景与文字颜色

很多主题会在根节点(如 :rootbody)上定义一些 CSS 变量,用于控制链接 / 文本 hover 时的背景色等。皮肤可以通过覆盖这些变量,统一全站交互风格。

示例(假设存在 --text-bg-hover 变量):

:root
--text-bg-hover: rgba(212, 175, 55, .08)

此时,所有使用该变量的组件(包括正文链接、某些按钮等)都会在 hover 时的文字颜色,可以在皮肤文件中写更具体的选择器,例如:

// 分类 / 归档列表内的文字在 hover 时变为某主色
#aside-content .card-widget.card-categories .card-category-list-item > a:hover,
#aside-content .card-widget.card-archives .card-archive-list-item > a:hover
color #c65d3b

// 内部 span 也随之改变
#aside-content .card-widget.card-categories .card-category-list-item > a:hover span,
#aside-content .card-widget.card-archives .card-archive-list-item > a:hover span
color inherit

通过变量 + 局部覆盖的方式,你可以在“全局统一”与“局部差异化”之间取得平衡。


通过以上机制,这套皮肤生态可以:

  • 在不改动 Butterfly 模板结构的前提下(除特殊功能分支外),
  • 为任意视觉元素增加丰富的装饰、纹理和动画,
  • 并通过一个简单的配置项 skin.preset 实现整站换肤。