上一篇:导航、首页与文章页配置 · 系列总目录 · 下一篇:使用 Inject 添加自定义组件
前言
Butterfly 默认把页首、正文区域和页脚看成三个不同层次。分别设置图片和遮罩很方便,但当我们希望整页呈现为一张连续画面时,三个区域之间就容易出现明显色彩分层。
一图流的核心并不是把同一张图片贴三遍,而是建立一个全局背景层,让所有半透明内容卡片覆盖在它上面。渐变只负责保证文字可读,不能把背景在某个固定高度切断。
一、先设计背景资源
至少准备四张图片:
1 2 3 4
| background-light-desktop.webp background-dark-desktop.webp background-light-mobile.webp background-dark-mobile.webp
|
桌面背景可以使用 2560×1440 或更高分辨率,手机背景应使用竖屏构图。仅靠 background-size: cover 把横图裁成手机尺寸,通常会丢失人物或视觉中心。
图片选择还要考虑:
- 标题所在区域不能过亮或过于复杂。
- 正文背后应保留较平静的色块。
- 暗色背景不能只有纯黑,需要保留层次。
- 文件大小应控制在合理范围。
- 优先使用 WebP 或 AVIF。
二、关闭容易造成分层的原生遮罩
在 _config.butterfly.yml 中:
1 2 3
| mask: header: false footer: false
|
同时明确设置背景:
1 2 3
| default_top_img: /img/background-light-desktop.webp footer_img: /img/background-light-desktop.webp background: /img/background-light-desktop.webp
|
这一步只能关闭原生遮罩。如果自定义 CSS 中还存在覆盖下半区的伪元素或线性渐变,也需要一起检查。
常见分层来源包括:
1 2 3 4
| #page-header::before #footer::before #web_bg::after body::before
|
以及从某个固定百分比突然改变透明度的渐变。
三、建立独立的全局背景层
Butterfly 页面中存在 #web_bg,可以把它作为固定背景:
1 2 3 4 5 6 7 8 9 10 11 12
| #web_bg { position: fixed; inset: 0; z-index: -10; width: 100%; height: 100%; background-image: url('/img/background-light-desktop.webp'); background-position: center top; background-size: cover; background-repeat: no-repeat; transition: opacity 0.45s ease, filter 0.45s ease; }
|
关键点是:
- 使用
fixed,滚动时背景不会在正文开始处重新贴一次。
- 使用
inset: 0 覆盖整个视口。
- 背景层保持在内容之后。
- 正文、页脚本身不要再各自绘制不一致的背景图。
正文卡片可以保留轻微半透明:
1 2 3 4 5 6 7
| #recent-posts > .recent-post-item, #aside-content .card-widget, .layout > div:first-child:not(.recent-posts), #post { background: rgba(255, 255, 255, 0.82); backdrop-filter: blur(10px); }
|
透明度越低,画面越明显,但文字可读性也越差。不要为了“一图流”把正文卡片做成完全透明。
四、连续淡化应该怎样实现
错误的做法通常是:
1 2 3
| background: linear-gradient(transparent 40%, white 50%), url(...);
|
当渐变在很短的区间完成变化时,会形成明显横线;如果把白色透明度推到 100%,页面底部又会完全看不到背景。
更自然的方式,是在全局背景上加入范围更长、强度更低的光照层:
1 2 3 4 5 6 7 8 9 10 11 12 13
| body::before { position: fixed; inset: 0; z-index: -9; content: ''; pointer-events: none; background: linear-gradient( to bottom, rgba(255, 255, 255, 0.02) 0%, rgba(255, 255, 255, 0.10) 48%, rgba(255, 255, 255, 0.18) 100% ); }
|
它不会把背景覆盖成白色,只会随着页面向下增加少量柔和亮度。
也可以根据滚动位置动态调整一个 CSS 变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function updateBackgroundFade() { var max = Math.max( document.documentElement.scrollHeight - window.innerHeight, 1 ); var progress = Math.min(window.scrollY / max, 1); document.documentElement.style.setProperty( '--page-scroll-progress', progress.toFixed(3) ); }
window.addEventListener('scroll', updateBackgroundFade, { passive: true }); updateBackgroundFade();
|
CSS 中使用:
1 2 3 4 5
| #web_bg { filter: brightness(calc(1 - var(--page-scroll-progress, 0) * 0.08)) saturate(calc(1 - var(--page-scroll-progress, 0) * 0.06)); }
|
变化幅度应保持很小。目标是让背景安静下来,而不是滚到底时完全消失。
五、亮色和暗色背景切换
Butterfly 会在根元素上设置:
1
| <html data-theme="dark">
|
因此可以通过属性选择器切换背景:
1 2 3 4 5 6 7
| #web_bg { background-image: url('/img/background-light-desktop.webp'); }
[data-theme='dark'] #web_bg { background-image: url('/img/background-dark-desktop.webp'); }
|
不过 background-image 本身不能像透明度一样自然插值。直接替换图片时仍可能闪烁。更平滑的方案是准备两个固定层,通过透明度交叉淡入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| body::before, body::after { position: fixed; inset: 0; z-index: -10; content: ''; background-position: center top; background-size: cover; transition: opacity 0.55s ease; }
body::before { background-image: url('/img/background-light-desktop.webp'); opacity: 1; }
body::after { background-image: url('/img/background-dark-desktop.webp'); opacity: 0; }
[data-theme='dark'] body::before { opacity: 0; }
[data-theme='dark'] body::after { opacity: 1; }
|
实际项目中要注意伪元素是否已经被其他组件占用。本站将背景切换和氛围动画集中在独立样式及脚本中,避免多个文件同时操作同一伪元素。
六、手机端使用独立图片
1 2 3 4 5 6 7 8 9 10 11
| @media (max-width: 768px) { body::before { background-image: url('/img/background-light-mobile.webp'); background-position: center top; }
body::after { background-image: url('/img/background-dark-mobile.webp'); background-position: center top; } }
|
手机端还应该:
- 减少模糊半径,降低 GPU 压力。
- 减少大面积粒子数量。
- 关闭跟随鼠标的效果。
- 确保卡片与屏幕边缘留有间距。
- 避免背景人物被侧栏或标题完全遮挡。
Chrome 开发者工具中的手机预览只能做初步检查,最后仍应在真实手机上测试。
七、加入克制的氛围动画
亮色主题可以使用:
- 缓慢移动的柔光。
- 非循环突变的海面反射。
- 很低透明度的漂浮光点。
暗色主题可以使用:
- 星点闪烁。
- 偶尔出现的流星。
- 标题和个人信息的轻微霓虹。
动画出现跳跃通常是因为 @keyframes 的首尾状态不一致:
1 2 3 4 5 6 7 8 9 10 11
| @keyframes glow-drift { 0%, 100% { transform: translate3d(-2%, 0, 0); opacity: 0.25; } 50% { transform: translate3d(2%, -1%, 0); opacity: 0.42; } }
|
首尾使用相同状态,循环连接才不会突然跳回。
还应尊重系统设置:
1 2 3 4 5 6 7 8 9
| @media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior: auto !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; } }
|
不要让动态效果成为阅读的前景。背景动画应该在停止观察时几乎感觉不到,在主动留意时又能发现细节。
八、保持页脚内容清晰
一图流经常会误把整个 footer 设置透明度:
1 2 3
| #footer { opacity: 0.5; }
|
这会连带降低文字、链接和图标透明度。正确做法是只调整背景层:
1 2 3 4 5 6 7 8 9 10 11 12
| #footer { position: relative; background: transparent; }
#footer::before { position: absolute; inset: 0; z-index: -1; content: ''; background: rgba(10, 20, 35, 0.14); }
|
页脚内容本身保持 opacity: 1。
九、本篇检查清单
- 从页首滚动到正文时没有横向色带
- 页面底部仍能看到背景
- 页脚文字没有随背景一起淡化
- 明暗主题切换没有明显白闪或黑闪
- 手机使用竖屏背景
- 背景不会盖住正文
- 动画首尾连续
- 减少动态效果设置生效
下一篇将不再停留在外观配置,而是建立一套可以反复复用的 Butterfly 自定义组件加载方式。
参考资料与声明
本文结合本站一图流背景的多轮调整过程整理。部分结构与文字由 AI 协助完成。
上一篇:导航、首页与文章页配置 · 返回系列总目录 · 下一篇:使用 Inject 添加自定义组件