Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions docs/WEBGL-WALLPAPER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# WebGL 壁纸

在显示设置的「壁纸模式」中选择 **WebGL 动态壁纸**,或把 [`backgroundWallpaper.mode`](../src/config/backgroundWallpaper.ts) 设为 `"webgl"`。默认加载 `cloud-train`(云海、蒸汽列车与桥梁)。WebGL 2 不可用、场景加载失败或着色器报错时,原图片壁纸会保留为回退;切走该模式时会释放画布和场景资源。

## 配置 Cloud Train

```ts
webgl: {
scene: "cloud-train",
options: {
speed: 1, resolution: 0.75, feedback: 0.3,
zoom: 1, offset: 0, amplitude: 1, detail: 8,
exposure: 1, saturation: 1, hue: 0, temperature: 0,
skyTint: "#ffffff", smokeTint: "#ffffff", trainTint: "#ffffff",
introEnabled: true, introDuration: 3, introFeather: 0.22,
paused: false,
},
},
```

`speed` 范围 0–5;`resolution` 范围 0.25–1;`feedback` 范围 0–0.85。场景会限制其余参数范围,避免无效配置直接进入着色器。窗口隐藏时停止渲染;系统开启减少动态效果时保持静态画面。

## 使用自己的片元着色器

把 WebGL 2 片元着色器放在 `public` 下。例如已提供的 [`example-wallpaper.frag`](../public/assets/shaders/example-wallpaper.frag):

```ts
webgl: {
scene: "fragment",
options: {
url: "/assets/shaders/example-wallpaper.frag",
speed: 1,
resolution: 1,
},
},
```

着色器须以 `#version 300 es` 开头,声明 `uniform vec3 iResolution`、`uniform float iTime`、`out vec4 color`,并提供 `void main()`。渲染宿主自动更新分辨率和时间。`url` 也可指向允许跨域读取的地址。

## 编写完整场景模块

多通道、反馈纹理或自行管理参数的场景,可在 [`src/utils/webgl-wallpaper/scenes/`](../src/utils/webgl-wallpaper/scenes/) 新增 `my-scene.ts`。模块默认导出一个接收 `WebGLWallpaperSceneContext` 的工厂函数,返回含 `dispose()` 的对象;把配置 `scene` 改为 `"my-scene"` 即可。宿主通过 `import.meta.glob` 按需加载,不用修改模式切换代码。工厂应在画出第一帧后调用 `onFirstFrame()`,并在 `dispose()` 中取消动画帧、监听器及 GPU 资源;可使用 `signal` 取消异步资产加载。

```ts
import type { WebGLWallpaperSceneContext } from "../types";

export default function createScene({ canvas, onFirstFrame }: WebGLWallpaperSceneContext) {
const gl = canvas.getContext("webgl2");
if (!gl) throw new Error("WebGL 2 is unavailable");
// 在此编译着色器并启动渲染;第一帧成功后调用 onFirstFrame()。
return { dispose() { /* 释放场景的 WebGL 资源与监听器 */ } };
}
```

Cloud Train 的完整多通道实现见 [`cloud-train.ts`](../src/utils/webgl-wallpaper/scenes/cloud-train.ts),宿主生命周期见 [`host.ts`](../src/utils/webgl-wallpaper/host.ts)。
Binary file added docs/screenshots/webgl-cloud-train-desktop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions public/assets/shaders/example-wallpaper.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#version 300 es
precision highp float;
uniform vec3 iResolution;
uniform float iTime;
out vec4 color;

void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
float wave = 0.5 + 0.5 * sin(uv.x * 8.0 + iTime * 0.4);
vec3 sky = mix(vec3(0.02, 0.08, 0.16), vec3(0.08, 0.32, 0.48), uv.y);
color = vec4(sky + vec3(0.03, 0.07, 0.09) * wave, 1.0);
}
49 changes: 37 additions & 12 deletions src/components/controls/DisplaySettingsIntegrated.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
WALLPAPER_FULLSCREEN,
WALLPAPER_NONE,
WALLPAPER_OVERLAY,
WALLPAPER_WEBGL,
} from "@constants/constants";
import I18nKey from "@i18n/i18nKey";
import { i18n } from "@i18n/translation";
Expand Down Expand Up @@ -118,7 +119,8 @@ const defaultCardFollowThemeEnabled = getDefaultCardFollowThemeEnabled();
const isWallpaperSwitchable = displaySettingsConfig.wallpaperModeSwitchable;
const isFullscreenLayoutSwitchable = $derived(
displaySettingsConfig.fullscreenLayoutSwitchable &&
wallpaperMode === WALLPAPER_FULLSCREEN,
(wallpaperMode === WALLPAPER_FULLSCREEN ||
wallpaperMode === WALLPAPER_WEBGL),
);
const allowLayoutSwitch = displaySettingsConfig.layoutSwitchable;
let effectiveDefaultLayout = $derived(
Expand Down Expand Up @@ -213,10 +215,12 @@ const hasWallpaperTab = $derived(
isWallpaperSwitchable ||
isFullscreenLayoutSwitchable ||
((wallpaperMode === WALLPAPER_OVERLAY ||
wallpaperMode === WALLPAPER_WEBGL ||
wallpaperMode === WALLPAPER_FULLSCREEN) &&
hasOverlaySettings) ||
((wallpaperMode === WALLPAPER_BANNER ||
wallpaperMode === WALLPAPER_FULLSCREEN) &&
wallpaperMode === WALLPAPER_FULLSCREEN ||
wallpaperMode === WALLPAPER_WEBGL) &&
hasBannerSettings),
);
const hasEffectsTab = $derived(isSakuraSwitchable);
Expand Down Expand Up @@ -258,6 +262,7 @@ $effect(() => {
$effect(() => {
if (
(wallpaperMode === WALLPAPER_OVERLAY ||
wallpaperMode === WALLPAPER_WEBGL ||
wallpaperMode === WALLPAPER_FULLSCREEN) &&
hasOverlaySettings
) {
Expand All @@ -270,7 +275,9 @@ let overlaySliderItems = $derived<OverlaySliderItem[]>([
key: "opacity",
// 全屏壁纸模式不需要背景透明度,隐藏该滑块(仍显示模糊与卡片透明度)
enabled:
isOverlayOpacitySwitchable && wallpaperMode !== WALLPAPER_FULLSCREEN,
isOverlayOpacitySwitchable &&
wallpaperMode !== WALLPAPER_FULLSCREEN &&
wallpaperMode !== WALLPAPER_WEBGL,
label: i18n(I18nKey.overlayOpacity),
displayValue: `${Math.round(overlayOpacity * 100)}%`,
ariaLabel: i18n(I18nKey.overlayOpacity),
Expand All @@ -287,6 +294,7 @@ let overlaySliderItems = $derived<OverlaySliderItem[]>([
// 全屏壁纸模式关闭模糊渐变时隐藏模糊滑块(overlay 模式不受影响)
enabled:
isOverlayBlurSwitchable &&
wallpaperMode !== WALLPAPER_WEBGL &&
!(wallpaperMode === WALLPAPER_FULLSCREEN && !isFullscreenBlurRampEnabled),
label: i18n(I18nKey.overlayBlur),
displayValue: `${overlayBlur.toFixed(1)}px`,
Expand Down Expand Up @@ -463,7 +471,11 @@ function switchWallpaperMode(newMode: WALLPAPER_MODE) {
setWallpaperMode(newMode);
window.scrollTo({ top: 0 });

if (newMode === WALLPAPER_OVERLAY || newMode === WALLPAPER_FULLSCREEN) {
if (
newMode === WALLPAPER_OVERLAY ||
newMode === WALLPAPER_FULLSCREEN ||
newMode === WALLPAPER_WEBGL
) {
requestAnimationFrame(refreshAllRangeProgress);
}
}
Expand Down Expand Up @@ -642,6 +654,10 @@ $effect(() => {
if (isOverlayCardOpacitySwitchable) {
setOverlayCardOpacity(overlayCardOpacity);
}
} else if (wallpaperMode === WALLPAPER_WEBGL) {
// WebGL 由场景直接渲染;仅沿用内容卡片透明度。
if (isOverlayCardOpacitySwitchable)
setOverlayCardOpacity(overlayCardOpacity);
} else if (wallpaperMode === WALLPAPER_FULLSCREEN) {
// 全屏壁纸不透明,只应用模糊与卡片透明度
if (isOverlayBlurSwitchable) {
Expand Down Expand Up @@ -858,11 +874,20 @@ $effect(() => {
<Icon icon="material-symbols:hide-image-outline" class="text-[1.25rem] shrink-0"></Icon>
<span class="text-xs font-medium">{i18n(I18nKey.wallpaperNoneMode)}</span>
</button>
<button
class="btn-regular rounded-md py-2 px-3 flex items-center justify-center gap-2 active:scale-95 transition-all relative overflow-hidden"
class:opacity-60={wallpaperMode !== WALLPAPER_WEBGL}
class:bg-(--btn-regular-bg-hover)={wallpaperMode === WALLPAPER_WEBGL}
onclick={() => switchWallpaperMode(WALLPAPER_WEBGL)}
>
<Icon icon="material-symbols:deployed-code-outline" class="text-[1.25rem] shrink-0"></Icon>
<span class="text-xs font-medium">{i18n(I18nKey.wallpaperWebglMode)}</span>
</button>
</div>
</div>
{/if}

<!-- Fullscreen Layout Section -->
<!-- 全屏图片与 WebGL 共用经典/Hero 布局设置。 -->
{#if isFullscreenLayoutSwitchable}
<div>
<div class="section-title">
Expand Down Expand Up @@ -898,8 +923,8 @@ $effect(() => {
</div>
{/if}

<!-- Overlay Settings Section(全屏壁纸模式也复用 overlay 的透明/模糊/卡片透明度设置) -->
{#if (wallpaperMode === WALLPAPER_OVERLAY || (wallpaperMode === WALLPAPER_FULLSCREEN && fullscreenLayout === "hero")) && hasOverlaySettings && hasVisibleOverlaySlider}
<!-- Overlay 设置仅在覆盖模式或全屏 Hero 布局显示;经典布局保留原有卡片样式。 -->
{#if (wallpaperMode === WALLPAPER_OVERLAY || ((wallpaperMode === WALLPAPER_FULLSCREEN || wallpaperMode === WALLPAPER_WEBGL) && fullscreenLayout === "hero")) && hasOverlaySettings && hasVisibleOverlaySlider}
<div class="">
<div class="section-title">
{i18n(I18nKey.overlaySettings)}
Expand Down Expand Up @@ -937,7 +962,7 @@ $effect(() => {
{/if}

<!-- Banner Settings Section -->
{#if (wallpaperMode === WALLPAPER_BANNER || wallpaperMode === WALLPAPER_FULLSCREEN) && hasBannerSettings}
{#if (wallpaperMode === WALLPAPER_BANNER || wallpaperMode === WALLPAPER_FULLSCREEN || wallpaperMode === WALLPAPER_WEBGL) && hasBannerSettings}
<div class="">
<div class="section-title">
{i18n(I18nKey.wallpaperSettings)}
Expand Down Expand Up @@ -986,8 +1011,8 @@ $effect(() => {
</div>
</button>
{/if}
<!-- Waves Animation Switch(横幅模式和 classic 全屏模式) -->
{#if isWavesSwitchable && (wallpaperMode === WALLPAPER_BANNER || (wallpaperMode === WALLPAPER_FULLSCREEN && fullscreenLayout === "classic"))}
<!-- Waves Animation Switch(横幅模式和 classic 全屏图片/WebGL 模式) -->
{#if isWavesSwitchable && (wallpaperMode === WALLPAPER_BANNER || ((wallpaperMode === WALLPAPER_FULLSCREEN || wallpaperMode === WALLPAPER_WEBGL) && fullscreenLayout === "classic"))}
<button
class="w-full btn-regular rounded-md py-2 px-3 flex items-center gap-3 text-left active:scale-95 transition-all relative overflow-hidden"
class:bg-(--btn-regular-bg-hover)={wavesEnabled}
Expand All @@ -1004,8 +1029,8 @@ $effect(() => {
</div>
</button>
{/if}
<!-- Gradient Transition Switch(横幅模式和 classic 全屏模式) -->
{#if isGradientSwitchable && (wallpaperMode === WALLPAPER_BANNER || (wallpaperMode === WALLPAPER_FULLSCREEN && fullscreenLayout === "classic"))}
<!-- Gradient Transition Switch(横幅模式和 classic 全屏图片/WebGL 模式) -->
{#if isGradientSwitchable && (wallpaperMode === WALLPAPER_BANNER || ((wallpaperMode === WALLPAPER_FULLSCREEN || wallpaperMode === WALLPAPER_WEBGL) && fullscreenLayout === "classic"))}
<button
class="w-full btn-regular rounded-md py-2 px-3 flex items-center gap-3 text-left active:scale-95 transition-all relative overflow-hidden"
class:bg-(--btn-regular-bg-hover)={gradientEnabled}
Expand Down
5 changes: 3 additions & 2 deletions src/components/layout/Navbar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const navbarTransparentMode =
const t = backgroundWallpaper.banner?.navbar?.transparentMode || "semi";
return t === "semifull" && !isHomePageCheck ? "semi" : t;
})()
: backgroundWallpaper.mode === "fullscreen"
: backgroundWallpaper.mode === "fullscreen" ||
backgroundWallpaper.mode === "webgl"
? (() => {
const fs =
backgroundWallpaper.fullscreen?.navbar?.transparentMode ||
Expand Down Expand Up @@ -140,7 +141,7 @@ const logoVariants = await Promise.all(
const isHome = navbar.getAttribute("data-is-home") === "true";
let mode;
let blur;
if (wm === "fullscreen") {
if (wm === "fullscreen" || wm === "webgl") {
mode = fsTMode === "semifull" && isHome ? "semifull" : "semi";
blur = fsBlur;
} else if (wm === "banner") {
Expand Down
6 changes: 4 additions & 2 deletions src/components/layout/WallpaperSection.astro
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ const wallpaperPosition = state.isFullscreenMode
---

<!-- Wallpaper - 如果允许切换则始终渲染,否则只渲染当前模式 -->
{(state.isWallpaperSwitchable || state.isBannerMode || state.isFullscreenMode || state.isOverlayMode) && (
{(state.isWallpaperSwitchable || state.isBannerMode || state.isFullscreenMode || state.isOverlayMode || state.isWebglMode) && (
<div id="wallpaper-wrapper" class="absolute z-10 w-full overflow-hidden" style="--overlay-opacity: ${backgroundWallpaper.overlay?.opacity ?? 0.8}; --overlay-z-index: ${backgroundWallpaper.overlay?.zIndex ?? -1}; --overlay-blur: ${backgroundWallpaper.overlay?.blur ?? 0}px;">
{/* 场景宿主始终存在,只有 WebGL 模式才动态加载模块;图片保留为图形不可用时的回退。 */}
<div id="webgl-wallpaper-host" aria-hidden="true"></div>
<!-- 背景图片显示 -->
{state.hasMultipleImages ? (
/* 轮播模式:渲染所有图片为 slide-item */
Expand Down Expand Up @@ -627,7 +629,7 @@ const wallpaperPosition = state.isFullscreenMode
)}

{/* 当壁纸未渲染时,添加空的 Swup 占位容器,避免 Swup 找不到容器而回退为整页加载 */}
{!(state.isWallpaperSwitchable || state.isBannerMode || state.isFullscreenMode || state.isOverlayMode) && (
{!(state.isWallpaperSwitchable || state.isBannerMode || state.isFullscreenMode || state.isOverlayMode || state.isWebglMode) && (
<>
<div id="banner-overlay-container" class="hidden"></div>
<div id="banner-dim-container" class="hidden"></div>
Expand Down
14 changes: 10 additions & 4 deletions src/config/backgroundWallpaper.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import type { BackgroundWallpaperConfig } from "@/types/backgroundWallpaper";

export const backgroundWallpaper: BackgroundWallpaperConfig = {
// 壁纸模式:"banner" 横幅壁纸,"fullscreen" 全屏壁纸,"overlay" 覆盖透明,"none" 纯色背景无壁纸
// 壁纸模式:"banner" 横幅壁纸,"fullscreen" 全屏壁纸,"overlay" 覆盖透明,"webgl" 动态场景,"none" 纯色背景无壁纸
mode: "banner",
// 将 mode 设为 "webgl",或在设置面板选择 WebGL,即可显示此场景。
// 自定义壁纸:在 src/utils/webgl-wallpaper/scenes/ 添加同名 .ts 模块并修改 scene。
webgl: {
scene: "cloud-train",
options: { speed: 0.75, resolution: 0.75, detail: 6, feedback: 0.3 },
},
// 是否启用背景视频播放,配置后将在导航栏显示视频播放按钮
playerEnable: true,
/**
Expand Down Expand Up @@ -62,7 +68,7 @@ export const backgroundWallpaper: BackgroundWallpaperConfig = {
// playerUrl: "/assets/videos/firefly.mp4",
playerUrl: "https://bed.twoleaf.cn/file/1785658612716_firefly.mp4",
},
// 横幅壁纸和全屏壁纸共享配置
// 横幅、全屏图片和 WebGL 壁纸共享标题、波纹等配置
common: {
// 壁纸遮罩暗度,让横幅文字显示更清晰,0-1之间,值越大越暗
dimOpacity: 0.2,
Expand Down Expand Up @@ -187,11 +193,11 @@ export const backgroundWallpaper: BackgroundWallpaperConfig = {
// 卡片透明度,0-1之间,值越小越透明
cardOpacity: 0.6,
},
// 全屏壁纸模式特有配置
// 全屏图片与 WebGL 共用的布局和导航配置
// 壁纸模糊度(blur)、卡片透明度(cardOpacity)、层级(zIndex) 复用上方 overlay 模式的配置;
// 背景透明度(opacity)不适用(全屏壁纸不透明);导航栏透明模式由 fullscreen.navbar.transparentMode 控制,脱离 banner 的 navbar 配置
fullscreen: {
// 布局模式:"classic" 经典文档流全屏壁纸,"hero" 固定全屏首屏壁纸
// 布局模式:"classic" 经典文档流壁纸,"hero" 固定全屏首屏壁纸(WebGL 同样适用)
layout: "classic",
// 图片位置
position: "center",
Expand Down
2 changes: 1 addition & 1 deletion src/config/displaySettingsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const displaySettingsConfig: DisplaySettingsConfig =
// 壁纸模式切换开关
wallpaperModeSwitchable: true,

// 全屏壁纸布局切换开关(classic / hero)
// 全屏图片与 WebGL 壁纸布局切换开关(classic / hero)
fullscreenLayoutSwitchable: true,

// 水波纹动画开关
Expand Down
1 change: 1 addition & 0 deletions src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const DEFAULT_THEME: typeof LIGHT_MODE = LIGHT_MODE; // 仅作为向后
export const WALLPAPER_BANNER = "banner",
WALLPAPER_FULLSCREEN = "fullscreen",
WALLPAPER_OVERLAY = "overlay",
WALLPAPER_WEBGL = "webgl",
WALLPAPER_NONE = "none";

// Banner height unit: vh
Expand Down
1 change: 1 addition & 0 deletions src/i18n/i18nKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ enum I18nKey {
fullscreenClassicLayout = "fullscreenClassicLayout",
fullscreenHeroLayout = "fullscreenHeroLayout",
wallpaperOverlayMode = "wallpaperOverlayMode",
wallpaperWebglMode = "wallpaperWebglMode",
wallpaperNoneMode = "wallpaperNoneMode",

// 壁纸设置
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ export const en: Translation = {
[Key.fullscreenClassicLayout]: "Classic",
[Key.fullscreenHeroLayout]: "Hero",
[Key.wallpaperOverlayMode]: "Overlay Wallpaper",
[Key.wallpaperWebglMode]: "WebGL",
[Key.wallpaperNoneMode]: "None Wallpaper",

// Wallpaper Settings
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ export const ja: Translation = {
[Key.fullscreenClassicLayout]: "クラシック",
[Key.fullscreenHeroLayout]: "ヒーロー",
[Key.wallpaperOverlayMode]: "透明",
[Key.wallpaperWebglMode]: "WebGL",
[Key.wallpaperNoneMode]: "単色背景",

// 壁紙設定
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ export const ko: Translation = {
[Key.fullscreenClassicLayout]: "클래식",
[Key.fullscreenHeroLayout]: "히어로",
[Key.wallpaperOverlayMode]: "오버레이 배경화면",
[Key.wallpaperWebglMode]: "WebGL",
[Key.wallpaperNoneMode]: "배경화면 없음",

// Wallpaper Settings
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ export const ru: Translation = {
[Key.fullscreenClassicLayout]: "Классический",
[Key.fullscreenHeroLayout]: "Hero",
[Key.wallpaperOverlayMode]: "Прозрачный",
[Key.wallpaperWebglMode]: "WebGL",
[Key.wallpaperNoneMode]: "Однотонный фон",

// Настройки обоев
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/zh_CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ export const zh_CN: Translation = {
[Key.fullscreenClassicLayout]: "经典模式",
[Key.fullscreenHeroLayout]: "Hero 模式",
[Key.wallpaperOverlayMode]: "覆盖透明",
[Key.wallpaperWebglMode]: "WebGL",
[Key.wallpaperNoneMode]: "纯色背景",

// 壁纸设置
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/zh_TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ export const zh_TW: Translation = {
[Key.fullscreenClassicLayout]: "經典模式",
[Key.fullscreenHeroLayout]: "Hero 模式",
[Key.wallpaperOverlayMode]: "覆蓋透明",
[Key.wallpaperWebglMode]: "WebGL",
[Key.wallpaperNoneMode]: "純色背景",

// 壁紙設置
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ const ogImageAlt = propsOgImageAlt ?? pageTitle;
document.body.classList.toggle(
"wallpaper-transparent",
wm === "overlay" ||
(wm === "fullscreen" &&
((wm === "fullscreen" || wm === "webgl") &&
document.documentElement.getAttribute("data-fullscreen-layout") === "hero"),
);
})();
Expand Down
8 changes: 4 additions & 4 deletions src/styles/layout-base.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,14 @@
--content-top: 5.5rem;
}
}
/* overlay / none / fullscreen 非首页:内容从导航栏下方开始 */
/* overlay / none / 全屏 Hero 非首页:内容从导航栏下方开始 */
html[data-wallpaper-mode="overlay"] .content-panel,
html[data-wallpaper-mode="none"] .content-panel,
html[data-wallpaper-mode="fullscreen"] body:not(.is-home) .content-panel {
html:is([data-wallpaper-mode="fullscreen"], [data-wallpaper-mode="webgl"]) body:not(.is-home) .content-panel {
--content-top: 5.5rem;
}
/* fullscreen 首页 hero:内容推到首屏之下 */
html[data-wallpaper-mode="fullscreen"] body.is-home .content-panel {
/* 全屏图片/WebGL 首页 Hero:内容推到首屏之下;classic 仍由文档流承接。 */
html:is([data-wallpaper-mode="fullscreen"], [data-wallpaper-mode="webgl"]) body.is-home .content-panel {
--content-top: 100vh;
}

Expand Down
Loading