Bilibili-Evolved 强制固定动态侧栏组件(fixed-sidebars)源码解析与实战指南
2026/9/19 23:43:33 网站建设 项目流程

Bilibili-Evolved 强制固定动态侧栏组件(fixed-sidebars)源码解析与实战指南

【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved

本文围绕 Bilibili-Evolved 动态首页增强组件“强制固定动态侧栏”(组件标识fixedFeedsSidebars,内部样式 IDfixed-sidebars-style)展开。它解决的是动态主页(https://t.bilibili.com/)顶栏与左右侧栏随页面滚动而消失、阅读动态时需要反复滚动回顶的问题:组件通过sticky/fixed定位将顶栏和全部侧栏钉在视口内,同时精细重排三栏宽度与边距。读完本文,你将掌握该组件的功能边界、样式实现原理、响应式断点取值,以及它与“禁止跳转动态详情”“动态过滤”等相邻组件的协作方式。

一、组件定位:只作用于动态主页的“布局钉住”功能

组件的元数据定义位于 registry/lib/components/feeds/fixed-sidebars/index.ts,核心声明如下:

const id = 'fixed-sidebars-style' const entry = async () => { const { disableProfilePopup } = await import('@/components/feeds/disable-profile-popup') disableProfilePopup() } export const component = defineComponentMetadata({ name: 'fixedFeedsSidebars', instantStyles: [ { name: id, style: () => import('./fixed-sidebars.scss'), important: true, }, ], displayName: '强制固定动态侧栏', tags: [componentsTags.feeds], entry, urlInclude: [/^https:\/\/t\.bilibili\.com\/$/], })

由此可以得到几个关键事实:

  • 生效范围urlInclude使用正则/^https:\/\/t\.bilibili\.com\/$/精确匹配动态主页,其他页面(包括动态内嵌子路由)不会加载该组件;
  • 样式注入方式:样式通过instantStyles在组件启用时立即注入,且important: true,即所有规则都会被提升为!important,足以覆盖站点自身的样式表优先级;
  • 附带行为:组件入口(entry)会动态导入并调用disableProfilePopup,关闭“正在直播”列表鼠标悬停弹出的用户 profile 小窗——这与固定侧栏的布局目标一致:弹窗属浮层,固定布局后浮层会出现遮挡问题,因此一并禁用。

二、样式核心:三栏布局如何被“钉”在视口中

组件全部样式位于 registry/lib/components/feeds/fixed-sidebars/fixed-sidebars.scss,可以按职责拆成四个层次理解。

2.1 顶层容器与顶栏(sticky 方案)

#app { z-index: 0; } .z-top-container, .international-header { position: sticky !important; top: 0 !important; z-index: 1; }
  • 将动态页应用根节点#app的层叠上下文压到z-index: 0,避免顶栏之外的元素浮到顶栏之上;
  • 顶栏容器(新版.z-top-container)与国际化顶部条(.international-header)改为position: sticky并固定在top: 0,实现“随滚动吸附在视口顶部”;
  • 顶栏z-index: 1,高于#app,保证吸附后始终可见。

2.2 浮层类弹窗全部改为 fixed

.van-popper-avatar, .van-popper-vip, .van-popper-favorite, .van-popper-history, .van-popper-upload, .popover-channe, .popover-game, .popover-live, .custom-navbar { position: fixed !important; }

头像、大会员、收藏、历史、投稿等van-popper-*下拉浮层,以及频道/游戏/直播popover-*弹出层和自定义导航条(custom-navbar),一律转为position: fixed。这样它们在 sticky 顶栏被钉住后,仍能正确基于视口定位弹出,不会随文档流错位。

2.3 侧栏固定与三栏重排

.sticky-bar { display: none !important; } .left-panel, .right-panel { position: fixed !important; } .home-container { --left-width: 244px; --center-width: 632px; @media screen and (min-width: 1921px) { --left-width: 12.71vw; --center-width: 32.92vw; } @media screen and (min-width: 2497px) { --left-width: 317px; --center-width: 822px; } } .center-panel { margin-left: calc(var(--left-width) + 8px) !important; } .right-panel { margin-left: calc(var(--left-width) + 16px + var(--center-width)) !important; }

这是整个组件最核心的布局逻辑:

  1. 原版自带的吸顶占位条.sticky-bar被直接隐藏(因为左右面板已改为fixed,不再需要占位);
  2. 左右面板.left-panel/.right-panel改为position: fixed,从文档流中脱离;
  3. 为了让脱离文档流的中栏不被左栏遮挡,组件通过 CSS 变量统一管理三栏宽度:默认左栏 244px、中栏 632px,中栏margin-left为左栏宽度 + 8px 间距,右栏margin-left为左栏 + 16px + 中栏宽度;
  4. 响应式断点通过媒体查询覆盖变量值,具体取值如下表:
视口宽度--left-width--center-width对应形态
默认(< 1921px)244px632px固定像素宽度
≥ 1921px12.71vw32.92vw随视口等比例缩放
≥ 2497px317px822px超大屏固定像素宽度

2.4 新版动态布局(.bili-dyn-home--member)的适配

针对 B 站新版动态主页容器,样式单独处理:

.bili-dyn-home--member { --center-width: 632px; --gap: 8px; --fixed-offset: calc(var(--center-width) + (100% - var(--center-width)) / 2 + var(--gap)); section.sticky { position: static !important; } aside { position: fixed !important; margin: 0 !important; &.left { right: var(--fixed-offset); } &.right { left: var(--fixed-offset); } } main { width: var(--center-width); margin: 0 var(--gap); } @media screen and (min-width: 1921px) { --center-width: 32.92vw; } @media screen and (min-width: 2497px) { --center-width: 822px; } }

可见新版布局采用了与旧版不同的“居中对称”策略:左右aside--fixed-offset(中栏宽度 + 两侧余量一半 + 间距)分别从右/左吸附定位,main固定为中栏宽度并留出--gap: 8px间距;同时把容器内原版section.sticky还原为static,避免与固定的 aside 冲突。媒体查询断点同样沿用 1921px / 2497px 两档。

三、配套逻辑:为何固定侧栏时要禁用 profile 弹窗

组件入口调用的disableProfilePopup位于 src/components/feeds/disable-profile-popup.ts,其实现要点:

export const DisableProfilePopupClass = 'disable-profile-popup' export const disableProfilePopup = async () => { if (document.URL.replace(window.location.search, '') !== 'https://t.bilibili.com/') { return } const list = (await select('.live-up-list, .bili-dyn-live-users__body')) as HTMLElement ... list.addEventListener('mouseenter', e => { if (counter > 0) { e.stopImmediatePropagation() } }, { capture: true }) }
  • 函数内部同样校验当前 URL 必须精确等于https://t.bilibili.com/,与组件的urlInclude形成双重保险;
  • 通过select('.live-up-list, .bili-dyn-live-users__body')等待“正在直播”列表渲染完成后,在捕获阶段监听mouseenter并调用stopImmediatePropagation(),从事件源头阻止原版“悬停显示 profile 弹窗”的行为;
  • 代码中使用counter计数并暴露了对应的enableProfilePopupcounter--),供其他组件的生命周期(启用/禁用)配合,避免多次注册监听器导致计数错乱。

四、与相邻组件的协作与约束

固定侧栏并非孤立功能,它在样式上还与动态页其他组件共享一套侧栏规则:

  • 共享侧栏样式fixed-sidebars.scss末尾@import '../feeds-panel-shared',引入了 registry/lib/components/feeds/_feeds-panel-shared.scss 中的公共规则,例如“正在直播”列表(.live-up-list.bili-dyn-live-users__body)在默认状态、开启动态过滤(body.enable-feeds-filter)、禁用 profile(body.feeds-filter-side-block-profile)三种场景下分别限制最大高度(如100vh - 315px/100vh - 370px/100vh - 180px),并统一隐藏滚动条。也就是说,过滤组件与固定侧栏共用同一套侧栏高度预算
  • 直播列表滚动fixed-sidebars.scss.live-panel .live-up-list { overflow: auto; @include no-scrollbar(); }保证固定后的直播列表内部可独立滚动且不出现滚动条;
  • 滚动容器复位.adaptive-scrollmin-height被取消、.scroll-content改回static,避免原版的“自适应滚动”机制与fixed定位冲突,防止出现双重滚动或滚动高度计算错误。

此外,该组件与“禁止跳转动态详情”(registry/lib/components/feeds/disable-details/index.ts)、“按类型或关键词过滤动态首页”(registry/lib/components/feeds/filter/index.md)等同属componentsTags.feeds分类,可在动态页相关功能中一起开启。

五、安装与使用

Bilibili-Evolved 的用户界面中,该组件显示名为“强制固定动态侧栏”,位于动态(feeds)分类下:

  1. 打开脚本的设置面板,进入“组件”或“动态”分类;
  2. 找到“强制固定动态侧栏”,打开开关即启用;
  3. 由于urlInclude限定,只有访问https://t.bilibili.com/时组件才会注入样式与逻辑,其他页面不受影响;
  4. 关闭组件时,通过instantStyles注入的样式会随组件生命周期移除(样式 ID 为fixed-sidebars-style),页面恢复原版布局。

需要留意的前提与限制:

  • 该组件以 B 站动态页当前 DOM 结构与类名为依赖(.z-top-container.left-panel.right-panel.bili-dyn-home--member等),若站点改版导致类名变化,需要同步更新 fixed-sidebars.scss 中的选择器;
  • 固定侧栏占用的宽度按 244px / 632px(及两档媒体查询覆盖值)计算,若与“自定义导航栏”等同样修改布局的组件同时开启,需注意边距与弹窗定位的叠加效果。

六、小结

“强制固定动态侧栏”是一个典型的“样式为主、逻辑为辅”的布局增强组件:样式层通过sticky顶栏 +fixed侧栏 + CSS 变量统一三栏宽度,并针对新版容器与三档响应式断点分别适配;逻辑层则调用disableProfilePopup禁用悬停 profile 弹窗,避免浮层与固定布局冲突。理解它的实现(index.ts、fixed-sidebars.scss、_feeds-panel-shared.scss、disable-profile-popup.ts),对于二次开发同类“钉住布局”类组件或排查动态页样式冲突,都有直接的参考价值。

【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询