容器都不用逐个点名。
配套两点小修:
· cursor: default —— 不再是"手型",视觉上不像链接;
· text-decoration: none —— 去掉链接下划线(若有)。
⚠ 刻意不改 color:标题/简介的颜色保持站内原样,只改交互不改外观。
⚠ 文字选中不受影响:pointer-events:none 只拦指针事件,
长按拖选仍会命中父容器并在 DOM 上选中这段文字。
选择器用 [class*=] 前缀匹配 —— tailwind 式哈希后缀(__Zyiqh)
会随版本变,前缀匹配才不会被站内更新打断。---- */
body.bili-bangumi-page [class*="mediainfo_mediaTitle"],
body.bili-bangumi-page [class*="mediainfo_media_desc_section"],
body.bili-video-page [class*="mediainfo_mediaTitle"],
body.bili-video-page [class*="mediainfo_media_desc_section"] {
pointer-events: none !important;
cursor: default !important;
text-decoration: none !important;
}
/* 子节点显式再压一层:防站内给
单独写了 pointer-events:auto */
body.bili-bangumi-page [class*="mediainfo_media_desc_section"] *,
body.bili-video-page [class*="mediainfo_media_desc_section"] * {
pointer-events: none !important;
}
body.bili-bangumi-page #bilibili-player-wrap {
position: relative !important;
width: 100% !important;
max-width: 100% !important;
height: calc((100vw - 22px) * 9 / 16 + 6px) !important;
max-height: calc((100vw - 22px) * 9 / 16 + 6px) !important;
padding: 0 !important;
border: 3px solid #00aeec !important;
border-radius: 12px !important;
box-shadow: 0 4px 16px rgba(0, 174, 236, 0.25) !important;
overflow: hidden !important;
box-sizing: border-box !important;
margin: 0 auto !important;
}
body.bili-bangumi-page #bilibili-player-wrap .video_playerInner__ox52b,
body.bili-bangumi-page #bilibili-player-wrap #bilibili-player,
body.bili-bangumi-page #bilibili-player-wrap .big-nano-player,
body.bili-bangumi-page #bilibili-player-wrap .bpx-docker,
body.bili-bangumi-page #bilibili-player-wrap .bpx-player-container,
body.bili-bangumi-page #bilibili-player-wrap .bpx-player-primary-area,
body.bili-bangumi-page #bilibili-player-wrap .bpx-player-video-area,
body.bili-bangumi-page #bilibili-player-wrap .bpx-player-video-wrap {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
max-width: 100% !important;
max-height: 100% !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
transform: none !important;
border-radius: 0 !important;
}
body.bili-bangumi-page #bilibili-player-wrap video {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
object-fit: contain !important;
background-color: #000 !important;
}
body.bili-bangumi-page .bpx-player-sending-area {
display: none !important;
}
/* ★ 修复简介完全展开后叠加到评论区的问题 ★
根因:plp-l.sticky 原始为 position: sticky,
简介展开后高度溢出,sticky 定位导致内容叠在评论区上方。
同时 plp-left-wrap / plp-l 需高度自适应,
player-left-components 为 display: contents 已不占位。 */
body.bili-bangumi-page .plp-left-wrap {
padding: 0 8px !important;
display: block !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
position: static !important;
}
body.bili-bangumi-page .plp-l,
body.bili-bangumi-page .plp-l.sticky {
padding: 0 !important;
display: block !important;
position: static !important;
top: auto !important;
bottom: auto !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
}
body.bili-bangumi-page .player-left-components {
padding: 0 !important;
display: contents !important;
}
body.bili-bangumi-page .toolbar,
body.bili-bangumi-page #like_info,
body.bili-bangumi-page #ogv_weslie_tool_coin_info,
body.bili-bangumi-page #ogv_weslie_tool_favorite_info,
body.bili-bangumi-page #share-container-id,
body.bili-bangumi-page #watch_together_tab,
body.bili-bangumi-page #tool-bar-more,
body.bili-bangumi-page .toolbar-right {
display: none !important;
visibility: hidden !important;
height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
body.bili-bangumi-page .mediainfo_mediaToolbar__8Q7bn {
display: none !important;
visibility: hidden !important;
height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
body.bili-bangumi-page .mediainfo_bottomBar__uBfeO {
display: none !important;
visibility: hidden !important;
height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
body.bili-bangumi-page [class*="navTools_floatNavExp"],
body.bili-bangumi-page [class*="navTools_navMenu"] {
display: none !important;
visibility: hidden !important;
height: 0 !important;
width: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
body.bili-bangumi-page [class*="mediainfo_mediaInfoWrap"] {
display: flex !important;
flex-direction: column !important;
align-items: stretch !important;
justify-content: flex-start !important;
flex-wrap: nowrap !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 10px 12px !important;
margin: 0 !important;
box-sizing: border-box !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
}
/* 确保 mediaInfoWrap 的 flex 子元素正常排列,不被压缩 */
body.bili-bangumi-page [class*="mediainfo_mediaInfoWrap"] > * {
flex: 0 0 auto !important;
min-height: auto !important;
max-height: none !important;
}
body.bili-bangumi-page [class*="mediainfo_mediaInfoWrap"] [class*="mediainfo_display_area"] {
flex: 1 1 auto !important;
}
/* ★★★ 番剧页:隐藏封面图区域(图中红框部分) ★★★
仅作用于 mediainfo_mediaCover 内部,避免误伤侧边栏推荐/选集封面 */
body.bili-bangumi-page [class*="mediainfo_mediaCover"],
body.bili-bangumi-page a[class*="mediainfo_mediaCover"],
body.bili-bangumi-page [class*="mediainfo_mediaCover"] picture,
body.bili-bangumi-page [class*="mediainfo_mediaCover"] img,
body.bili-bangumi-page [class*="mediainfo_mediaCover"] svg {
display: none !important;
visibility: hidden !important;
width: 0 !important;
max-width: 0 !important;
min-width: 0 !important;
height: 0 !important;
max-height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: 0 !important;
opacity: 0 !important;
overflow: hidden !important;
position: absolute !important;
left: -9999px !important;
top: -9999px !important;
pointer-events: none !important;
flex: 0 0 0 !important;
}
body.bili-bangumi-page [class*="mediainfo_mediaRight"] {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: flex-start !important;
text-align: center !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
float: none !important;
position: static !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
}
body.bili-bangumi-page [class*="mediainfo_mediaTitle"] {
font-size: 16px !important;
font-weight: bold !important;
margin: 0 0 6px 0 !important;
padding: 0 !important;
text-align: center !important;
width: 100% !important;
display: block !important;
height: auto !important;
max-height: none !important;
overflow: visible !important;
-webkit-line-clamp: unset !important;
word-break: break-word !important;
}
/* ★ 番剧简介:始终完全展开,隐藏"展开/收起"按钮 ★
B站原生机制:收起态 display_area 用 -webkit-line-clamp 限高,
ellipsis 是末行渐变遮罩+"展开"按钮;展开态切换为纯 p 标签。
实测无论多少字,展开后也只多显示约一行,按钮意义不明。
方案:强制解除所有高度/行数限制,隐藏 ellipsis/placeholder/按钮,
让简介始终完整显示(纯 CSS,无 JS)。
两套 DOM 结构:
收起态 a[class*="mediainfo_media_desc_section"]
-> div.display_area > div.placeholder(hidden) + p.content + div.ellipsis("展开")
-> p.content_placeholder(hidden)
展开态 a[class*="mediainfo_media_desc"] -> p > span("简介:") + i("收起") */
body.bili-bangumi-page [class*="mediainfo_media_desc"] p,
body.bili-bangumi-page [class*="mediainfo_media_desc"] p *,
body.bili-bangumi-page [class*="mediainfo_display_area"],
body.bili-bangumi-page [class*="mediainfo_display_area"] *,
body.bili-bangumi-page [class*="mediainfo_content"],
body.bili-bangumi-page [class*="mediainfo_content"] * {
color: #61666d !important;
font-size: 13px !important;
font-weight: 400 !important;
line-height: 1.6 !important;
letter-spacing: normal !important;
font-style: normal !important;
text-transform: none !important;
text-align: center !important;
}
body.bili-bangumi-page [class*="mediainfo_media_desc"] {
width: 100% !important;
max-width: 100% !important;
display: block !important;
padding: 6px 0 0 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
-webkit-line-clamp: unset !important;
-webkit-box-orient: unset !important;
text-overflow: clip !important;
white-space: normal !important;
word-break: break-word !important;
}
body.bili-bangumi-page [class*="mediainfo_media_desc"] p {
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
-webkit-line-clamp: unset !important;
-webkit-box-orient: unset !important;
text-overflow: clip !important;
white-space: pre-wrap !important;
word-break: break-word !important;
}
/* ★ 关键:解除 display_area 的高度与行数限制,让收起态也能完整展开 ★
同时强制 position: static,防止 B站原始 absolute 定位导致
简介脱离文档流、叠加到评论区上方 */
body.bili-bangumi-page [class*="mediainfo_display_area"] {
position: static !important;
top: auto !important;
left: auto !important;
right: auto !important;
bottom: auto !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
display: block !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
-webkit-line-clamp: unset !important;
-webkit-box-orient: unset !important;
text-overflow: clip !important;
white-space: normal !important;
word-break: break-word !important;
float: none !important;
z-index: auto !important;
}
body.bili-bangumi-page [class*="mediainfo_content"] {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
display: block !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
-webkit-line-clamp: unset !important;
-webkit-box-orient: unset !important;
text-overflow: clip !important;
white-space: pre-wrap !important;
word-break: break-word !important;
}
/* ★ 隐藏"展开/收起"按钮、渐变遮罩、占位测量元素 ★ */
body.bili-bangumi-page [class*="mediainfo_ellipsis"],
body.bili-bangumi-page [class*="mediainfo_placeholder"],
body.bili-bangumi-page [class*="mediainfo_expand"],
body.bili-bangumi-page [class*="mediainfo_expandBtn"],
body.bili-bangumi-page [class*="mediainfo_moreBtn"],
body.bili-bangumi-page [class*="mediainfo_toggleBtn"],
body.bili-bangumi-page [class*="mediainfo_content_placeholder"] {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* ★ 隐藏展开态 p 里的
收起 按钮文字 ★ */
body.bili-bangumi-page [class*="mediainfo_media_desc"] p > i,
body.bili-bangumi-page [class*="mediainfo_content"] i {
display: none !important;
visibility: hidden !important;
}
body.bili-bangumi-page [class*="mediainfo_mediaRating"] {
display: inline-flex !important;
justify-content: center !important;
align-items: center !important;
margin: 0 auto !important;
}
body.bili-bangumi-page [class*="upinfo_upInfoCard"] {
display: inline-flex !important;
justify-content: center !important;
align-items: center !important;
margin: 0 auto !important;
}
body.bili-bangumi-page #comment-module {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 12px 0 0 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
display: block !important;
position: static !important;
clear: both !important;
}
body.bili-bangumi-page #comment-module * {
max-width: 100% !important;
box-sizing: border-box !important;
}
body.bili-bangumi-page #comment-body {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 0 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
display: block !important;
}
body.bili-bangumi-page #comment-body bili-comments {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
position: static !important;
}
/* ============================================================
========== 番剧页播放器控制栏 ==========
============================================================ */
body.bili-bangumi-page .bpx-player-ctrl-pip,
body.bili-bangumi-page .bpx-player-ctrl-wide,
body.bili-bangumi-page .bpx-player-ctrl-time,
body.bili-bangumi-page .bpx-player-ctrl-eplist { display: none !important; }
@media screen and (orientation: landscape) {
body.bili-bangumi-page .bpx-player-ctrl-time { display: block !important; }
}
@media screen and (width >= 750px) {
body.bili-bangumi-page .bpx-player-container[data-screen=full] .bpx-player-ctrl-quality-result {
height: unset !important;
font-size: 16px !important;
}
body.bili-bangumi-page .bpx-player-container[data-screen=full] .bpx-player-control-wrap { height: 43px !important; }
body.bili-bangumi-page .bpx-player-container[data-screen=full] .bpx-player-control-top { bottom: 43px !important; }
}
body.bili-bangumi-page div.bpx-player-control-bottom {
height: 29px !important;
margin-top: 7px !important;
padding: 0 7px !important;
}
body.bili-bangumi-page div.bpx-player-control-top {
transition: none;
bottom: 36px;
}
body.bili-bangumi-page .bpx-player-pbp .bpx-player-pbp-pin-tip { display: none !important; }
body.bili-bangumi-page .bpx-player-control-bottom-left,
body.bili-bangumi-page .bpx-player-control-bottom-right { flex: unset !important; }
body.bili-bangumi-page .bpx-player-container .bpx-player-control-bottom-left,
body.bili-bangumi-page .bpx-player-container .bpx-player-control-bottom-right { min-width: 0 !important; }
body.bili-bangumi-page .bpx-player-ctrl-quality {
min-width: 0;
flex: auto !important;
margin-right: 0 !important;
}
body.bili-bangumi-page .bpx-player-ctrl-quality-result,
body.bili-bangumi-page .bpx-player-ctrl-playbackrate { font-size: 12px !important; }
body.bili-bangumi-page .bpx-player-ctrl-quality-result { height: 22px; overflow: hidden; }
body.bili-bangumi-page .bpx-player-ctrl-playbackrate { text-wrap: nowrap; }
body.bili-bangumi-page .bpx-player-progress-wrap {
height: 7px !important;
padding-bottom: 3px !important;
}
body.bili-bangumi-page .bpx-player-control-mask {
background: linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,0.5) 100%) !important;
}
body.bili-bangumi-page .bpx-player-ctrl-quality-menu-wrap { bottom: 22px !important; }
body.bili-bangumi-page .bpx-player-ctrl-quality-menu-item {
max-width: 95px;
max-height: 36px;
height: 7.7vw !important;
padding: 0 8px 0 12px !important;
}
body.bili-bangumi-page .bpx-player-ctrl-quality-badge-bigvip {
color: #fff;
background-color: #f25d8e;
width: 16px;
overflow: hidden;
right: 8px !important;
}
body.bili-bangumi-page .bpx-player-ctrl-quality-badge-bigvip:before {
color: #fff;
content: "V";
background-color: #f25d8e;
padding: 0 4px;
position: absolute;
left: 0;
}
body.bili-bangumi-page .bpx-player-ctrl-playbackrate-menu { bottom: 22px !important; }
body.bili-bangumi-page .bpx-player-ctrl-playbackrate-menu-item {
justify-content: center;
align-items: center;
max-height: 36px;
display: flex;
height: 7.7vw !important;
}
body.bili-bangumi-page div.bpx-player-ctrl-subtitle-box {
bottom: 0;
right: 0;
transform: scale(.8);
}
body.bili-bangumi-page .bpx-player-ctrl-setting-box {
bottom: 0 !important;
right: 0 !important;
}
body.bili-bangumi-page .bpx-player-ctrl-setting-menu-right { padding: 5px !important; }
body.bili-bangumi-page .bpx-player-ctrl-setting-menu-right > div {
justify-content: center;
align-items: center;
max-height: 40px;
display: flex;
height: 10vw !important;
}
body.bili-bangumi-page .bpx-player-ctrl-setting-menu-right .bui-radio {
width: 77%;
margin: 0 0 8px 7px;
}
body.bili-bangumi-page .bpx-player-ctrl-setting-others-content {
margin-left: 7px;
width: 77% !important;
}
body.bili-bangumi-page .bpx-player-ctrl-setting-highenergy .bui-checkbox-name {
white-space: nowrap;
width: 48px;
overflow: hidden;
}
body.bili-bangumi-page .bpx-player-dm-setting-wrap {
top: 0;
left: 50%;
transform: translate(-50%);
bottom: unset !important;
position: fixed !important;
}
body.bili-bangumi-page .bpx-player-control-bottom-center .bpx-player-sending-bar {
height: 24px !important;
padding-right: 6px !important;
}
body.bili-bangumi-page .bpx-player-ctrl-viewpoint {
flex-shrink: 1 !important;
width: 45px !important;
min-width: 0 !important;
margin: 0 !important;
}
body.bili-bangumi-page .bpx-player-ctrl-viewpoint-text {
flex: none;
font-size: 12px;
width: 24px !important;
text-overflow: unset !important;
}
body.bili-bangumi-page .bpx-player-control-wrap:not(.new) { display: none; }
body.bili-bangumi-page .bpx-player-control-entity,
body.bili-bangumi-page .bpx-player-control-mask { display: block !important; }
body.bili-bangumi-page .bpx-player-container[data-ctrl-hidden=true] .bpx-player-control-bottom { display: none; }
body.bili-bangumi-page .bpx-player-container[ctrl-shown=false] .bpx-player-control-wrap .bpx-player-control-mask {
opacity: 0;
transition: opacity .2s ease-in;
}
body.bili-bangumi-page .bpx-player-container[ctrl-shown=true] .bpx-player-control-wrap .bpx-player-control-mask { opacity: 1; }
body.bili-bangumi-page .bpx-player-container[ctrl-shown=true] .bpx-player-control-entity .bpx-player-control-bottom {
opacity: 1;
display: flex;
}
body.bili-bangumi-page .bpx-player-container[ctrl-shown=false] .bpx-player-control-entity .bpx-player-control-bottom { display: none; }
body.bili-bangumi-page .bpx-player-container[ctrl-shown=true] .bpx-player-control-entity .bpx-player-control-top,
body.bili-bangumi-page .bpx-player-container[ctrl-shown=false] .bpx-player-control-entity .bpx-player-shadow-progress-area {
opacity: 1;
visibility: visible;
}
body.bili-bangumi-page .bpx-player-container[ctrl-shown=false] .bpx-player-control-entity .bpx-player-control-top,
body.bili-bangumi-page .bpx-player-container[ctrl-shown=true] .bpx-player-control-entity .bpx-player-shadow-progress-area {
opacity: 0;
visibility: hidden;
}
body.bili-bangumi-page .bpx-player-container[ctrl-shown=true] .bpx-player-control-entity .bpx-player-pbp {
opacity: 1;
width: 100%;
bottom: calc(100% + 6px);
left: 0;
}
body.bili-bangumi-page div.bpx-player-control-entity .bpx-player-pbp {
opacity: 0;
width: calc(100% + 24px);
bottom: 1px;
left: -12px;
}
body.bili-bangumi-page div.bpx-player-control-entity .bpx-player-pbp.pin { opacity: 1; }
body.bili-bangumi-page .bpx-player-pbp-pin { display: none; opacity: 1 !important; }
body.bili-bangumi-page .bpx-player-container[ctrl-shown=true] .bpx-player-control-entity .bpx-player-pbp-pin { display: block; }
body.bili-bangumi-page .bpx-player-video-perch { max-height: 0; }
body.bili-bangumi-page .bpx-player-top-wrap,
body.bili-bangumi-page .bpx-player-state-wrap { display: none !important; }
body.bili-bangumi-page .bpx-player-container,
body.bili-bangumi-page #bilibili-player-placeholder { box-shadow: none !important; }
/* ===== 动态页 ===== */
body.bili-dynamic-page { background: #f4f5f7 !important; }
body.bili-dynamic-page .bili-header,
body.bili-dynamic-page .international-header,
body.bili-dynamic-page .mini-header,
body.bili-dynamic-page .bili-header__bar,
body.bili-dynamic-page .bili-header__menu,
body.bili-dynamic-page #bili-header-container {
display: none !important;
visibility: hidden !important;
height: 0 !important;
overflow: hidden !important;
}
body.bili-dynamic-page .bgc,
body.bili-dynamic-page .bg { display: none !important; }
body.bili-dynamic-page .bili-dyn-home--member > .left,
body.bili-dynamic-page .bili-dyn-home--member > aside.left,
body.bili-dynamic-page .bili-dyn-home--member > .right,
body.bili-dynamic-page .bili-dyn-home--member > aside.right,
body.bili-dynamic-page .bili-dyn-sidebar,
body.bili-dynamic-page .bili-dyn-sidebar__btn {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
overflow: hidden !important;
}
body.bili-dynamic-page #app,
body.bili-dynamic-page #app > div,
body.bili-dynamic-page .bili-dyn-home--member,
body.bili-dynamic-page .bili-dyn-home--member > main,
body.bili-dynamic-page .bili-dyn-list,
body.bili-dynamic-page .bili-dyn-list__item,
body.bili-dynamic-page .bili-dyn-item {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
}
body.bili-dynamic-page .bili-dyn-list__items {
padding: 8px 0 8px 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-list__item {
padding: 0 8px 8px 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-item {
position: relative !important;
background: #ffffff !important;
border: 1px solid #e3e5e7 !important;
border-radius: 8px !important;
padding: 12px 8px 0 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
display: block !important;
float: none !important;
}
body.bili-dynamic-page .bili-dyn-item * {
max-width: 100% !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-item img,
body.bili-dynamic-page .bili-dyn-item video,
body.bili-dynamic-page .bili-dyn-item picture {
max-width: 100% !important;
height: auto !important;
}
body.bili-dynamic-page .bili-dyn-item__main {
position: relative !important;
padding-left: 0 !important;
padding-right: 0 !important;
box-sizing: border-box !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
float: none !important;
}
body.bili-dynamic-page .bili-dyn-item__avatar {
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 56px !important;
max-width: 56px !important;
min-width: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-item__avatar .bili-dyn-avatar,
body.bili-dynamic-page .bili-dyn-item__avatar .b-avatar,
body.bili-dynamic-page .bili-dyn-item__avatar img {
width: 48px !important;
height: 48px !important;
max-width: 100% !important;
border-radius: 50% !important;
}
body.bili-dynamic-page .bili-dyn-item__header {
margin-left: 0 !important;
margin-right: 0 !important;
padding-left: 64px !important;
padding-right: 8px !important;
width: auto !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-item__more,
body.bili-dynamic-page .bili-dyn-more,
body.bili-dynamic-page .bili-dyn-more__btn,
body.bili-dynamic-page .bili-dyn-more__cascader {
display: none !important;
visibility: hidden !important;
}
body.bili-dynamic-page .bili-dyn-content,
body.bili-dynamic-page .bili-dyn-content__orig,
body.bili-dynamic-page .bili-dyn-content__orig__major {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-card-video {
display: flex !important;
flex-direction: column !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-card-video__header {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
flex: 0 0 auto !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-card-video__cover {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
aspect-ratio: 16 / 9 !important;
box-sizing: border-box !important;
}
body.bili-dynamic-page .bili-dyn-card-video__cover .b-img,
body.bili-dynamic-page .bili-dyn-card-video__cover .b-img__inner,
body.bili-dynamic-page .bili-dyn-card-video__cover img,
body.bili-dynamic-page .bili-dyn-card-video__cover picture {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
aspect-ratio: 16 / 9 !important;
object-fit: cover !important;
display: block !important;
}
body.bili-dynamic-page .bili-dyn-card-video__body {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
flex: 1 1 auto !important;
padding: 8px 0 0 0 !important;
box-sizing: border-box !important;
}
/* 投稿了视频:隐藏视频封面下方「框住标题/简介文字」的那条左侧半开口边框 */
body.bili-dynamic-page .bili-dyn-card-video__body,
body.bili-dynamic-page .bili-dyn-card-video__title,
body.bili-dynamic-page .bili-dyn-card-video__desc {
border: none !important;
border-top: none !important;
border-right: none !important;
border-bottom: none !important;
border-left: none !important;
border-width: 0 !important;
border-style: none !important;
box-shadow: none !important;
outline: none !important;
}
/* 该边框也可能是 ::before / ::after 画的竖条,一并清掉 */
body.bili-dynamic-page .bili-dyn-card-video__body::before,
body.bili-dynamic-page .bili-dyn-card-video__body::after,
body.bili-dynamic-page .bili-dyn-card-video__desc::before,
body.bili-dynamic-page .bili-dyn-card-video__desc::after {
content: none !important;
display: none !important;
border: none !important;
background: none !important;
box-shadow: none !important;
}
body.bili-dynamic-page .bili-dyn-card-video__title,
body.bili-dynamic-page .bili-dyn-card-video__desc,
body.bili-dynamic-page .bili-dyn-card-video__title .bili-ellipsis,
body.bili-dynamic-page .bili-dyn-card-video__desc .bili-ellipsis { text-align: center !important; }
body.bili-dynamic-page .bili-dyn-card-video__stat,
body.bili-dynamic-page .bili-dyn-card-video__stat__item,
body.bili-dynamic-page .bili-dyn-card-video__stat__item.danmaku {
display: none !important;
visibility: hidden !important;
height: 0 !important;
overflow: hidden !important;
margin: 0 !important;
padding: 0 !important;
}
body.bili-dynamic-page .bili-dyn-item,
body.bili-dynamic-page .bili-dyn-item * {
text-align: center !important;
}
/* 正文容器:只做内边距约束,绝不能隐藏(正文 .bili-dyn-content 就在它里面) */
body.bili-dynamic-page .bili-dyn-item__body {
margin-left: 0 !important;
margin-right: 0 !important;
padding-left: 8px !important;
padding-right: 8px !important;
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
}
/* 去掉卡片内的「转发 / 评论 / 点赞」数量行(整行隐藏) */
body.bili-dynamic-page .bili-dyn-item__footer,
body.bili-dynamic-page .bili-dyn-item__action,
body.bili-dynamic-page .bili-dyn-action,
body.bili-dynamic-page .bili-dyn-action.forward,
body.bili-dynamic-page .bili-dyn-action.comment,
body.bili-dynamic-page .bili-dyn-action.like {
display: none !important;
visibility: hidden !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* 隐藏该行后,卡片底部补回一点留白,避免内容紧贴卡片下边缘 */
body.bili-dynamic-page .bili-dyn-item {
padding-bottom: 12px !important;
}
body.bili-dynamic-page .bili-dyn-content__orig__major img,
body.bili-dynamic-page .bili-dyn-content__orig__major picture,
body.bili-dynamic-page .bili-dyn-content__orig__major .b-img {
margin-left: auto !important;
margin-right: auto !important;
display: block !important;
}
body.bili-dynamic-page .bili-dyn-content__orig__major [class*="grid"],
body.bili-dynamic-page .bili-dyn-content__orig__major [class*="pics"],
body.bili-dynamic-page .bili-dyn-content__orig__major [class*="gallery"],
body.bili-dynamic-page .bili-dyn-content__orig__major [class*="goods"],
body.bili-dynamic-page .bili-dyn-content__orig__major [class*="commodity"],
body.bili-dynamic-page .bili-dyn-content__orig__major [class*="card"] {
margin-left: auto !important;
margin-right: auto !important;
justify-content: center !important;
}
body.bili-dynamic-page .bili-dyn-item__action {
flex: 1 1 0 !important;
width: auto !important;
max-width: none !important;
min-width: 0 !important;
box-sizing: border-box !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
}
body.bili-dynamic-page .bili-dyn-action {
display: flex !important;
align-items: center !important;
justify-content: center !important;
width: 100% !important;
gap: 4px !important;
}
body.bili-dynamic-page .bili-dyn-list-tabs,
body.bili-dynamic-page .bili-dyn-list-tabs__list,
body.bili-dynamic-page .bili-dyn-list-tabs__item {
display: none !important;
visibility: hidden !important;
height: 0 !important;
overflow: hidden !important;
}
body.bili-dynamic-page .bili-dyn-home--member > main > section:nth-of-type(1),
body.bili-dynamic-page .bili-dyn-home--member > main > section:nth-of-type(2) {
display: none !important;
visibility: hidden !important;
height: 0 !important;
overflow: hidden !important;
}
body.bili-dynamic-page .bili-dyn-search-trendings,
body.bili-dynamic-page .trending-list,
body.bili-dynamic-page .sticky { display: none !important; }
/* ============================================================
动态详情页(t.bilibili.com/xxx 单条动态展开):评论区与视频页一致
结构:#app > .content > .card > .bili-tabs.dyn-tabs
> .bili-tabs__content > .bili-tab-pane > .comment-wrap
> .bili-comment-container > bili-comments(shadow DOM)
实测:bili-comments 仅 312 宽(360 屏),左右各 24px;视频页为 8px。
这里按视频页 #commentapp 的同一套外框规则拉齐,
shadow 内部(输入框/点赞/回复按钮等)由 installShadowRootPatch 统一处理。
============================================================ */
body.bili-dynamic-page .bili-tabs.dyn-tabs,
body.bili-dynamic-page .bili-tabs__content,
body.bili-dynamic-page .bili-tab-pane,
body.bili-dynamic-page .comment-wrap,
body.bili-dynamic-page .bili-comment-container {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
padding-left: 8px !important;
padding-right: 8px !important;
margin-left: 0 !important;
margin-right: 0 !important;
overflow: hidden !important;
float: none !important;
position: static !important;
}
body.bili-dynamic-page bili-comments,
body.bili-dynamic-page .bili-comment-container bili-comments {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
display: block !important;
}
/* 与视频页一致:外部的输入框/编辑器容器一并隐藏(shadow 内由 patch 处理) */
body.bili-dynamic-page .bili-comment-box,
body.bili-dynamic-page .bili-comment-input-wrap,
body.bili-dynamic-page .comment-send-box,
body.bili-dynamic-page .bili-comment-editor,
body.bili-dynamic-page .bili-comment-editor-wrap {
display: none !important;
visibility: hidden !important;
height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* 「评论 N」下面的那条分割线:恢复显示(v131.10)
不再清空 tabs 头部/导航的下边框与伪元素,
并显式补一条 1px 灰线,原生无边框时也能保证有线。 */
body.bili-dynamic-page .bili-tabs.dyn-tabs > .bili-tabs__header,
body.bili-dynamic-page .bili-tabs.dyn-tabs .bili-tabs__header {
border-top: 0 !important;
border-left: 0 !important;
border-right: 0 !important;
border-bottom: 1px solid #e3e5e7 !important;
box-shadow: none !important;
background-image: none !important;
}
/* 若出现两条线(原生伪元素 + 上面补的边框),
把下面这段的 border-bottom 改回 none 即可 */
body.bili-dynamic-page .bili-tabs__nav,
body.bili-dynamic-page .bili-tabs__nav__items,
body.bili-dynamic-page .bili-tabs__nav__item {
box-shadow: none !important;
background-image: none !important;
}
/* 只隐藏「赞与转发」这一个 tab 项,保留「评论 N」——
视频页评论区本来就有「评论 N」(shadow 内 #title),两边才一致。
探针:nav__items 中 nth-of-type(2) 为「评论 N」(.is-active),
nth-of-type(3) 为「赞与转发」。 */
body.bili-dynamic-page .bili-tabs__nav__item:nth-of-type(3),
body.bili-dynamic-page .bili-tabs__nav__items > .bili-tabs__nav__item:nth-of-type(3) {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* 右侧悬浮工具栏(417 / 0 / 7 / 顶部):视频页没有,隐藏 */
body.bili-dynamic-page .sidebar-wrap,
body.bili-dynamic-page .side-toolbar,
body.bili-dynamic-page .side-toolbar__box,
body.bili-dynamic-page .side-toolbar__bottom {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* ============================================================
===== 话题页(点标签/话题进来:/v/topic/detail/?topic_id=)=====
卡片 DOM 与动态页同源:.list__topic-card > .bili-dyn-item,
内部同样是 __avatar / __header / __body / a.bili-dyn-card-video,
所以版式照抄动态页:
白底圆角卡 + 头像左浮 48px + 封面拉全宽 16:9 + 正文居中
+ 隐藏「关注 / 更多 / 热评 / 转发评论点赞 / 播放弹幕数」。
作用域全走 body:has(.topic-detail):纯 CSS,不新增 JS、不加页面 class。
⚠ 踩过的坑一(v131.64 修复):本页列表是 B站 list-view 虚拟滚动,
首屏数据由底部哨兵 .list-view__shim 进视口触发加载。
上一版把 shim 给 display:none 了 → 永远不触发 → 一条都不显示
(实测 .topic-list 只剩 switch-tab 的 40px,flow-list 不在 DOM)。
所以:虚拟列表内部节点(shim / state / flow-list > div)一律不碰,
并显式保 shim 可见,防止被别处规则误伤。
⚠ 踩过的坑二(v131.66 修复):「热门/最新」行的间距不是它自己给的。
上间距来自 .topic-detail__header 的 margin-bottom,
而中间夹了一张 .active-card(margin-bottom 16px)把它顶成 16px,
所以必须把活动卡隐藏,上间距才会回到 8px。
⚠ 踩过的坑三(v131.65 修复):absolute 定位的 .bili-dyn-item__avatar
包含块是 .bili-dyn-item__main,不是 .bili-dyn-item。__main 已经是
item 的内容盒(padding 已算进去),所以只能 left/top = 0,
照抄动态页参数即可,不要再加 8/12 的内边距补偿。
============================================================ */
body:has(.topic-detail) {
padding: 8px 0 0 0 !important;
background: #f4f5f7 !important;
}
/* 只收横向溢出,放在 .topic-detail 上;不动 html/body 的 overflow,
避免改变滚动容器让虚拟列表的滚动监听失效 */
body:has(.topic-detail) .topic-detail {
overflow-x: hidden !important;
background: #f4f5f7 !important;
}
/* ---- 1. 把 PC 定宽 632 / left:-140 的容器链拉回满宽 ----
注意:不包含 .topic-list__flow-list 及其子级,避免误伤虚拟列表 */
body:has(.topic-detail) #app,
body:has(.topic-detail) .topic-detail,
body:has(.topic-detail) .topic-nav__main,
body:has(.topic-detail) .topic-detail__header,
body:has(.topic-detail) .topic-detail__content,
body:has(.topic-detail) .topic-detail__header > .main-part,
body:has(.topic-detail) .topic-detail__content > .main-part,
body:has(.topic-detail) .topic-list,
body:has(.topic-detail) .topic-list__flow-list,
body:has(.topic-detail) .list__topic-card,
body:has(.topic-detail) .bili-dyn-item,
body:has(.topic-detail) .bili-dyn-item__main {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
}
/* 整页左右各留 8px:与动态页 .bili-dyn-list__item 的 8px 边距一致 */
body:has(.topic-detail) .topic-detail {
padding: 0 8px 8px 8px !important;
box-sizing: border-box !important;
}
/* ---- 1b. flow-list 原生带 80px margin-top(PC 留白)。
不归零的话会与 switch-tab 的下间距 margin-collapse 成 80px ---- */
body:has(.topic-detail) .topic-list__flow-list {
margin-top: 0 !important;
margin-bottom: 0 !important;
}
/* ---- 1c. 保命:虚拟滚动的底部哨兵必须可见可布局 ---- */
body:has(.topic-detail) .list-view__shim,
body:has(.topic-detail) .topic-list__flow-list > .list-view__shim {
display: block !important;
visibility: visible !important;
width: 100% !important;
min-height: 1px !important;
height: auto !important;
opacity: 0 !important;
}
/* ---- 2. 只隐藏纯装饰:顶部 PC 导航条(实测 0 高,含重复「参与话题」)
与分享弹层。发布面板 / list-view 内部节点一律不碰。 ---- */
body:has(.topic-detail) .topic-nav,
body:has(.topic-detail) .share-popover,
/* 活动运营卡(「崩坏星穹铁道4.6创作者激励计划 … 立即参与」):
实测 344x59、margin-bottom 16px,正是它把「热门/最新」行顶下去的元凶 */
body:has(.topic-detail) .active-card,
body:has(.topic-detail) .active-content,
body:has(.topic-detail) .active-button,
/* 「参与话题 / 点赞 / 收藏 / 分享」整行:动态页没有,隐藏 */
body:has(.topic-detail) .interaction-container {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* ---- 3. 话题头部(发起者 / 标题 / 简介 / 参与话题):白卡 + 居中 ---- */
body:has(.topic-detail) .topic-detail__header {
height: auto !important;
background: #ffffff !important;
border: 1px solid #e3e5e7 !important;
border-radius: 8px !important;
margin: 0 0 8px 0 !important;
padding: 12px !important;
box-sizing: border-box !important;
text-align: center !important;
}
/* 原生 main-part 带 28px margin-top(给被隐藏的 topic-nav 留位),归零 */
body:has(.topic-detail) .topic-detail__header > .main-part {
margin-top: 0 !important;
padding-top: 0 !important;
}
body:has(.topic-detail) .topic-detail__header * { text-align: center !important; }
/* 头里那个 88x93 的大电视图标:PC 装饰,隐藏 */
body:has(.topic-detail) .topic-tv-icon {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
body:has(.topic-detail) .launch-user,
body:has(.topic-detail) .topic-title,
body:has(.topic-detail) .topic-desc {
width: 100% !important;
max-width: 100% !important;
margin-left: auto !important;
margin-right: auto !important;
justify-content: center !important;
box-sizing: border-box !important;
}
body:has(.topic-detail) .topic-title h1 {
font-size: 17px !important;
line-height: 24px !important;
}
body:has(.topic-detail) .topic-desc__text,
body:has(.topic-detail) .topic-desc {
font-size: 13px !important;
line-height: 20px !important;
}
/* ---- 4. 热门 / 最新 切换条:保留并居中(话题页排序靠它) ---- */
body:has(.topic-detail) .switch-tab {
display: flex !important;
align-items: center !important;
justify-content: center !important;
width: 100% !important;
max-width: 100% !important;
height: auto !important;
min-height: 48px !important;
gap: 24px !important;
/* 实测:上方 header 自带 8px 下边距,这里再补 8px 下边距,
上下就都等于卡片之间的 8px 间距(.list__topic-card 的下留白)。
上一版把高度压成 40px,而里面的 tab 文字是 48px 高,
结果文字溢出 8px 直接压在下方卡片上。 */
margin: 0 0 8px 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
background: transparent !important;
}
/* 上间距 = header 的 margin-bottom 8px(下面这条),
下间距 = switch-tab 自己的 margin-bottom 8px,
两边都与卡片之间的 8px 一致。
⚠ content 原生自带 margin-top 8px,会与 header 的 8px
margin-collapse 成 8px(取大值),实测正常,显式写死防回归。
⚠ topic-list 自身 margin 必须归零,否则会再叠一层。 */
body:has(.topic-detail) .topic-detail__header { margin-bottom: 8px !important; }
body:has(.topic-detail) .topic-detail__content { margin-top: 8px !important; }
body:has(.topic-detail) .topic-list {
margin-top: 0 !important;
margin-bottom: 0 !important;
}
body:has(.topic-detail) .switch-tab__tab {
width: auto !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
}
/* 原生那条 56x2 的下划线指示器是绝对定位的,隐藏后改用选中色区分 */
body:has(.topic-detail) .switch-tab__line {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
}
body:has(.topic-detail) .switch-tab__tab-text {
font-size: 15px !important;
color: #61666d !important;
}
body:has(.topic-detail) .switch-tab__tab-text.selected {
color: #00aeec !important;
font-weight: 600 !important;
}
/* ---- 5. 卡片:与动态页 .bili-dyn-item 同一张皮 ---- */
body:has(.topic-detail) .list__topic-card {
padding: 0 0 8px 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body:has(.topic-detail) .bili-dyn-item {
position: relative !important;
display: block !important;
background: #ffffff !important;
border: 1px solid #e3e5e7 !important;
border-radius: 8px !important;
padding: 12px 8px 12px 8px !important;
margin: 0 !important;
overflow: hidden !important;
box-sizing: border-box !important;
float: none !important;
}
body:has(.topic-detail) .bili-dyn-item * {
max-width: 100% !important;
box-sizing: border-box !important;
}
body:has(.topic-detail) .bili-dyn-item img,
body:has(.topic-detail) .bili-dyn-item video,
body:has(.topic-detail) .bili-dyn-item picture {
max-width: 100% !important;
height: auto !important;
}
body:has(.topic-detail) .bili-dyn-item,
body:has(.topic-detail) .bili-dyn-item * { text-align: center !important; }
/* ---- 6. 头像左浮 + 头部让位 64px(与动态页同参数) ---- */
/* ⚠ 与动态页同参数。absolute 的包含块是 .bili-dyn-item__main,
而 __main 本身就是 item 的内容盒(左边 +9、上边 +13 的 padding 已经
算进去了),所以这里必须 left/top = 0。
上一版写成 8/12 等于把内边距又叠了一遍 → 头像整体下移 12px 压住正文。
实测(修复前):头像 top=293,用户名 top=279,差 14px;
动态页是头像 56 / 用户名 54,只差 2px。 */
body:has(.topic-detail) .bili-dyn-item__avatar {
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 56px !important;
max-width: 56px !important;
min-width: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body:has(.topic-detail) .bili-dyn-item__avatar .bili-dyn-avatar,
body:has(.topic-detail) .bili-dyn-item__avatar .b-avatar,
body:has(.topic-detail) .bili-dyn-item__avatar img {
width: 48px !important;
height: 48px !important;
max-width: 100% !important;
border-radius: 50% !important;
}
body:has(.topic-detail) .bili-dyn-item__header {
width: auto !important;
max-width: 100% !important;
min-width: 0 !important;
/* 8px:与动态页 header→body 的间隔一致。话题页原生这里是 0,
而头像在容器内偏下 19px、高 48px,底部会压住正文第一行。 */
margin: 0 0 8px 0 !important;
padding-left: 64px !important;
padding-right: 8px !important;
box-sizing: border-box !important;
}
body:has(.topic-detail) .bili-dyn-item__body {
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
padding: 0 8px 0 8px !important;
box-sizing: border-box !important;
}
/* ---- 7. 动态页没有的行:关注按钮 / 三点更多 / 热评 / 底部互动栏 / 播放弹幕数 ---- */
body:has(.topic-detail) .bili-dyn-item__following,
body:has(.topic-detail) .bili-dyn-follow-btn,
body:has(.topic-detail) .bili-dyn-item__more,
body:has(.topic-detail) .bili-dyn-more,
body:has(.topic-detail) .bili-dyn-more__btn,
body:has(.topic-detail) .bili-dyn-item__interaction,
body:has(.topic-detail) .bili-dyn-interaction,
body:has(.topic-detail) .bili-dyn-item__footer,
body:has(.topic-detail) .bili-dyn-item__action,
body:has(.topic-detail) .bili-dyn-action,
body:has(.topic-detail) .bili-dyn-card-video__stat {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* ---- 8. 视频卡:PC 是「左封面 236 + 右文字 288」横排,
改成动态页那种「上封面(全宽 16:9)+ 下标题」竖排 ---- */
body:has(.topic-detail) .bili-dyn-content,
body:has(.topic-detail) .bili-dyn-content__orig,
body:has(.topic-detail) .bili-dyn-content__orig__major {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
body:has(.topic-detail) .bili-dyn-card-video {
display: flex !important;
flex-direction: column !important;
width: 100% !important;
max-width: 100% !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body:has(.topic-detail) .bili-dyn-card-video__header {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
flex: 0 0 auto !important;
}
body:has(.topic-detail) .bili-dyn-card-video__cover {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
aspect-ratio: 16 / 9 !important;
box-sizing: border-box !important;
}
body:has(.topic-detail) .bili-dyn-card-video__cover .b-img,
body:has(.topic-detail) .bili-dyn-card-video__cover .b-img__inner,
body:has(.topic-detail) .bili-dyn-card-video__cover img,
body:has(.topic-detail) .bili-dyn-card-video__cover picture {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
aspect-ratio: 16 / 9 !important;
object-fit: cover !important;
display: block !important;
}
body:has(.topic-detail) .bili-dyn-card-video__body {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
flex: 1 1 auto !important;
padding: 8px 0 0 0 !important;
border: none !important;
border-width: 0 !important;
border-style: none !important;
box-shadow: none !important;
outline: none !important;
}
/* 封面右侧那条半开口边框(原生可能是 ::before/::after 画的竖条)一并清掉 */
body:has(.topic-detail) .bili-dyn-card-video__body::before,
body:has(.topic-detail) .bili-dyn-card-video__body::after,
body:has(.topic-detail) .bili-dyn-card-video__desc::before,
body:has(.topic-detail) .bili-dyn-card-video__desc::after {
content: none !important;
display: none !important;
border: none !important;
background: none !important;
box-shadow: none !important;
}
body:has(.topic-detail) .bili-dyn-card-video__title {
font-size: 14px !important;
line-height: 20px !important;
}
body:has(.topic-detail) .bili-dyn-card-video__desc {
font-size: 12px !important;
line-height: 18px !important;
color: #9499a0 !important;
}
/* 封面/图册居中 */
body:has(.topic-detail) .bili-dyn-content__orig__major .b-img,
body:has(.topic-detail) .bili-dyn-content__orig__major picture {
margin-left: auto !important;
margin-right: auto !important;
}
/* ============================================================
opus 详情页(www.bilibili.com/opus/xxx)评论区:同样对齐视频页
实测链路:opus-detail 344 -> .bili-tabs.opus-tabs 328
-> .bili-tabs__content 312 -> .comment-wrap 296
-> .bili-comment-container 280 -> bili-comments 264
每层各吃 16px,层层嵌套后只剩 264,比视频页的 328 窄了 64。
目标:344 - 8(容器) - 8(容器) = 328,与视频页 bili-comments 完全一致。
做法:中间各层水平内边距归零,只由 .bili-comment-container 提供 8px,
bili-comments 满宽且自身不留白。
(下面选择器比既有 opus 规则更具体,确保覆盖生效)
============================================================ */
body.bili-opus-page .bili-tabs.opus-tabs,
body.bili-opus-page .bili-tabs.opus-tabs > .bili-tabs__content,
body.bili-opus-page .bili-tabs.opus-tabs > .bili-tabs__content > .bili-tab-pane,
body.bili-opus-page .bili-tabs.opus-tabs .comment-wrap {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
position: static !important;
}
body.bili-opus-page .bili-tabs.opus-tabs .comment-wrap > .bili-comment-container {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 8px !important;
padding-right: 8px !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
}
body.bili-opus-page .bili-comment-container bili-comments,
body.bili-opus-page .comment-wrap bili-comments {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
box-sizing: border-box !important;
}
/* 与视频页一致:外部输入框/编辑器容器隐藏(shadow 内由 patch 处理) */
body.bili-opus-page .bili-comment-box,
body.bili-opus-page .bili-comment-input-wrap,
body.bili-opus-page .comment-send-box,
body.bili-opus-page .bili-comment-editor,
body.bili-opus-page .bili-comment-editor-wrap {
display: none !important;
visibility: hidden !important;
height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* 只隐藏「赞与转发」tab,保留「评论 177」 */
body.bili-opus-page .bili-tabs__nav__item:nth-of-type(3),
body.bili-opus-page .bili-tabs__nav__items > .bili-tabs__nav__item:nth-of-type(3) {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* 右侧悬浮工具栏(417 / 2 / 0 / 8 / 177 / 顶部) */
body.bili-opus-page .sidebar-wrap,
body.bili-opus-page .side-toolbar,
body.bili-opus-page .side-toolbar__box,
body.bili-opus-page .side-toolbar__bottom {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* ===== opus 详情页 ===== */
body.bili-opus-page {
background: #f4f5f7 !important;
overflow-x: hidden !important;
padding-top: 8px !important;
}
body.bili-opus-page .opus-module-content,
body.bili-opus-page .opus-module-content p,
body.bili-opus-page .opus-module-content span,
body.bili-opus-page .opus-module-title {
text-align: center !important;
}
body.bili-opus-page .opus-para-pic,
body.bili-opus-page .bili-album,
body.bili-opus-page .bili-album__preview.grid2,
body.bili-opus-page .opus-para-link-card,
body.bili-opus-page .bili-dyn-card-goods,
body.bili-opus-page .bili-dyn-card-goods__wrap,
body.bili-opus-page .bili-dyn-card-goods__one {
margin-left: auto !important;
margin-right: auto !important;
text-align: center !important;
}
body.bili-opus-page #bili-header-container,
body.bili-opus-page .bili-header,
body.bili-opus-page .bili-header--mini,
body.bili-opus-page .bili-header--fixed,
body.bili-opus-page .bili-header__bar,
body.bili-opus-page .bili-header__menu,
body.bili-opus-page .international-header,
body.bili-opus-page .mini-header {
display: none !important;
visibility: hidden !important;
height: 0 !important;
overflow: hidden !important;
}
body.bili-opus-page .bgc,
body.bili-opus-page .bg { display: none !important; }
body.bili-opus-page .right-sidebar-wrap,
body.bili-opus-page .side-toolbar,
body.bili-opus-page .go-top,
body.bili-opus-page [class*="back-top"],
body.bili-opus-page [class*="to-top"] {
display: none !important;
visibility: hidden !important;
}
body.bili-opus-page #app,
body.bili-opus-page #opus-detail-app,
body.bili-opus-page .opus-detail,
body.bili-opus-page .bili-opus-view,
body.bili-opus-page .opus-module-top,
body.bili-opus-page .opus-module-title,
body.bili-opus-page .opus-module-author,
body.bili-opus-page .opus-module-content,
body.bili-opus-page .opus-module-copyright,
body.bili-opus-page .opus-module-bottom,
body.bili-opus-page .bili-tabs.opus-tabs,
body.bili-opus-page .bili-tabs__header,
body.bili-opus-page .bili-tabs__content,
body.bili-opus-page .comment-wrap,
body.bili-opus-page .bili-comment-container {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 8px !important;
padding-right: 8px !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
position: static !important;
left: auto !important;
right: auto !important;
}
body.bili-opus-page img,
body.bili-opus-page video,
body.bili-opus-page picture,
body.bili-opus-page .b-img,
body.bili-opus-page .b-img__inner {
max-width: 100% !important;
height: auto !important;
display: block !important;
}
body.bili-opus-page .opus-module-top__album__cover,
body.bili-opus-page .opus-module-top__display,
body.bili-opus-page .opus-module-top__album {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
box-sizing: border-box !important;
}
/* ===== opus 详情页:隐藏三处模块 =====
实测:.opus-module-top [312x187](标题上方的封面图)
.opus-module-copyright [312x54](cv53172768)
.opus-module-bottom [312x96](分享至 / 投诉或建议)
注意:上面已有的宽度规则里包含了这三个选择器,但只设了宽高/内边距,
这里单独用 display:none 隐藏;选择器更具体,优先级覆盖无冲突。 */
body.bili-opus-page .bili-opus-view > .opus-module-top,
body.bili-opus-page .opus-detail .opus-module-top,
body.bili-opus-page .opus-module-top {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
body.bili-opus-page .bili-opus-view > .opus-module-copyright,
body.bili-opus-page .opus-detail .opus-module-copyright,
body.bili-opus-page .opus-module-copyright {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
body.bili-opus-page .bili-opus-view > .opus-module-bottom,
body.bili-opus-page .opus-detail .opus-module-bottom,
body.bili-opus-page .opus-module-bottom,
body.bili-opus-page .opus-module-bottom__share,
body.bili-opus-page .opus-module-bottom__share__list {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* ===== opus 详情页:UP 主行右侧竖排「⋯」更多按钮 =====
探针 09-29_11-17-15 实测(视口 360):
.opus-module-author[312x90] left=24 pt=12 pb=12
> .__left[66x66] left=32 (头像 66 + 挂件)
> .__center[88x62] left=98 (昵称 / 发布时间)
> .__right[142x48] left=186
> .opus-module-author__more[24x24] **left=304** ← 目标
> .opus-more > .opus-more__container.opus-more__btn > svg[24x24]
> .opus-module-author__decorate[110x33] left=186(装扮卡片,保留)
竖排三个点就是 .opus-module-author__more —— 整块 24x24,
点开是举报/关注之类的浮层,手机端这一列本来就挤(昵称只有 72 宽),
收掉它还能让 .__right 少占 24px。
只隐藏 __more,**不动 __decorate**(装扮卡片是 UP 主的展示信息)。
------------------------------------------------------------ */
body.bili-opus-page .opus-module-author__more,
body.bili-opus-page .opus-module-author__more > .opus-more,
body.bili-opus-page .opus-module-author__more .opus-more__container,
body.bili-opus-page .opus-module-author__more .opus-more__btn,
body.bili-opus-page .opus-module-author__right > .opus-more {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-width: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* 高特异性兜底(v131.36 套路):完整链路压过去 */
body.bili-opus-page .bili-opus-view > .opus-module-author
> .opus-module-author__right > .opus-module-author__more {
display: none !important;
width: 0 !important;
height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
body.bili-opus-page .opus-para-pic,
body.bili-opus-page .opus-pic-view,
body.bili-opus-page .bili-dyn-pic,
body.bili-opus-page .bili-dyn-pic__img {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
margin-left: auto !important;
margin-right: auto !important;
box-sizing: border-box !important;
}
body.bili-opus-page * {
max-width: 100% !important;
box-sizing: border-box !important;
}
/* ============================================================
v131.28 长按头像弹出的「UP 主信息卡片」固定在屏幕内显示
探针实测(三份都已抓到,挂在 body 直下):
空间搜索页 body > div.bili-user-profile:nth-of-type(5) [360x261]
空间动态页 body > div.bili-user-profile:nth-of-type(5) [360x261]
动态详情页 body > div.bili-user-profile:nth-of-type(10) [360x266]
卡片本身已经是满宽 360,问题出在定位:站内 JS 按 PC 布局算出的
left/top(或 transform)把它推到了视口之外。探针只记录尺寸不记录坐标,
无法确定是被横向推出还是纵向推出,所以这里采用"强制钉在视口内"的
做法,两种情形一并覆盖:
· position: fixed —— 相对视口定位,不再受文档坐标影响
· left/right 双写 0 + width 100% —— 横向必定铺满视口
· top: auto + bottom: 0 —— 纵向必定贴底(手机上的 bottom-sheet)
· transform: none —— 压掉站内用 translate 做的偏移
!important 的作者样式优先级高于站内写在 style 属性里的普通声明。
注意:不写 display / visibility,显示与隐藏仍交给站内 JS 控制。
============================================================ */
body .bili-user-profile {
position: fixed !important;
left: 0 !important;
right: 0 !important;
/* v131.29:改为距屏幕顶部 36px(原来是贴底 bottom:0) */
top: 36px !important;
bottom: auto !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
max-height: 90vh !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
transform: none !important;
translate: none !important;
scale: none !important;
overflow-x: hidden !important;
overflow-y: auto !important;
-webkit-overflow-scrolling: touch !important;
border-radius: 12px 12px 0 0 !important;
box-shadow: 0 -2px 12px rgba(0,0,0,0.12) !important;
z-index: 2147483647 !important;
}
/* 内部两层:满宽 + 裁掉溢出(背景图原生 366 宽,比视口宽 6px) */
body .bili-user-profile__content,
body .bili-user-profile-view,
body .bili-user-profile-view__background,
body .bili-user-profile-view__info {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
transform: none !important;
}
/* v131.29 隐藏「发消息」按键(保留「关注/已关注」)。
只写 display:none:footer 是 flex,移除后关注按钮会自动铺满,不留空隙。 */
body .bili-user-profile-view__info__button.chat {
display: none !important;
visibility: hidden !important;
width: 0 !important;
min-width: 0 !important;
height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* ============================================================
========== UP 主空间页 ==========
============================================================ */
html:has(body.bili-space-page),
body.bili-space-page {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
/* v131.33:hidden 会让 body 变成滚动容器,导致内部 sticky 全部失效
(胶囊栏吸不住、一滚就钻到搜索框底下 -> 间距看起来是 0)。
clip 同样能裁掉横向溢出,但不会创建滚动容器,sticky 正常工作。
两条都写:老浏览器吃 hidden,新版吃 clip。 */
overflow-x: hidden !important;
overflow-x: clip !important;
margin: 0 !important;
padding: 0 !important;
background: #f1f2f3 !important;
}
/* v131.37 顶部 52px 占位改为「唯一来源」。
原写法只给 body 加 padding-top: 52px,一旦它被站内样式或其它规则
覆盖,整个空间页内容就会顶到 y=0:
胶囊栏(pill) 8..42 完全落进固定搜索栏 0..52 里 -> 胶囊栏看不见
第一行卡片顶 50,被搜索栏压掉 2px -> 顶部裁剪显示不全
正好对应你反馈的两个现象。
改法:body 的 padding 归零,改由 #app 提供这 52px。
两者效果等价(都是把 #app 内容整体下移 52),但来源唯一、
不再依赖 body 那条容易被盖掉的规则。
放在 #app 上也同时保证 nav-bar(投稿页)初始位置就是 52,
与它自己的 sticky top:52 一致,不会先被搜索栏盖住再跳下来。 */
body.bili-space-page { padding-top: 0 !important; }
body.bili-space-page > #app,
body.bili-space-page > div#app {
padding-top: 52px !important;
box-sizing: border-box !important;
/* v131.39 真凶(探针 14-15-15 实证):#app 带站内原生的
margin-top: -64px,而且它与 body 的 margin 发生了外边距合并,
把 body 本身也顶到了 top=-64:
html top=0 / body top=-64 / #app top=-64 (pt=52 mt=-64)
→ main top=-12 → 胶囊栏 top=-4 → 卡片顶 38
于是胶囊栏 8..50 整体落进固定搜索栏 0..52 里被完全盖住,
第一行卡片顶 38 也被切掉 —— 正好是你看到的两个现象。
这个 -64 原本是站内给 PC 头部留的负补偿,脚本已隐藏 PC 头部,
它就必须归零。 */
margin-top: 0 !important;
}
/* 顺带断掉 body 与 #app 的外边距合并,避免再被负边距带偏 */
body.bili-space-page > #app::before {
content: '' !important;
display: block !important;
height: 0 !important;
overflow: hidden !important;
}
/* v131.38 加固:.space-theme-bg 是站内绝对定位的背景层(360x800),
脚本从未处理过它。若它层级高于普通流内容,就会把 main 顶部
(含胶囊栏)整块盖住 —— 表现就是"胶囊栏凭空消失"。
这里把它压到最底层并禁用命中,彻底排除遮挡可能。 */
body.bili-space-page .space-theme-bg,
body.bili-space-page #app > .space-theme-bg {
position: absolute !important;
top: 0 !important;
left: 0 !important;
z-index: 0 !important;
pointer-events: none !important;
}
/* main 与胶囊栏显式抬到背景层之上 */
body.bili-space-page #app > main.space-main {
position: relative !important;
z-index: 2 !important;
}
body.bili-space-page .search-sidebar,
body.bili-space-page .upload-sidenav {
z-index: 3 !important;
}
body.bili-space-page .bili-header,
body.bili-space-page .international-header,
body.bili-space-page .mini-header,
body.bili-space-page #biliMainHeader,
body.bili-space-page #bili-header-container,
body.bili-space-page .bili-header--mini,
body.bili-space-page .bili-header--fixed,
body.bili-space-page .bili-header__bar,
body.bili-space-page .bili-header__menu,
body.bili-space-page .footer,
body.bili-space-page .bili-footer,
body.bili-space-page .international-footer,
body.bili-space-page .mini-footer,
body.bili-space-page .space-footer,
body.bili-space-page .go-top,
body.bili-space-page .bili-go-top,
body.bili-space-page [class*="back-top"],
body.bili-space-page [class*="goto-top"],
body.bili-space-page [class*="to-top"],
body.bili-space-page .fixed-sidebar,
body.bili-space-page .bili-fixed-sidebar,
body.bili-space-page .side-toolbar,
body.bili-space-page .right-sidebar-wrap,
body.bili-space-page .space-float {
display: none !important;
visibility: hidden !important;
height: 0 !important;
overflow: hidden !important;
}
body.bili-space-page .toutu.header-toutu {
display: none !important;
visibility: hidden !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
body.bili-space-page .header.space-header {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
body.bili-space-page .upinfo-detail__top .level,
body.bili-space-page .upinfo-detail__top a.level,
body.bili-space-page .upinfo-detail__top .vip,
body.bili-space-page .upinfo-detail__top .img-label,
body.bili-space-page .upinfo-detail__bottom,
body.bili-space-page .upinfo-sign,
body.bili-space-page .upinfo-sign__text,
body.bili-space-page .interactions > a.message-btn,
body.bili-space-page .interactions > .more-actions,
body.bili-space-page .interactions > .menu-popover.message,
body.bili-space-page .interactions > .v-popover-wrap.message-entry {
display: none !important;
visibility: hidden !important;
}
body.bili-space-page .nav-search.nav-bar-search,
body.bili-space-page label.nav-search,
body.bili-space-page input.nav-search-input,
body.bili-space-page .nav-bar__main-right,
body.bili-space-page .nav-statistics {
display: none !important;
visibility: hidden !important;
}
/* v131.26 导航条高度 64 → 52,与顶部自建搜索栏 #my-bili-searchbar 等高。
实测:#my-bili-searchbar 360x52;.nav-bar.space-navbar 360x64
(内部 .nav-bar__main / .nav-tab / a.nav-tab__item 都是 64,被 flex 拉伸)。
只压外层 + 内层容器的 height,icon(20x21) 与文字本身没变,
所以视觉上只是上下留白收紧 12px(各 6px),图标文字不受影响。 */
body.bili-space-page .nav-bar.space-navbar {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 52px !important;
max-height: 52px !important;
overflow: hidden !important;
box-sizing: border-box !important;
margin-left: 0 !important;
margin-right: 0 !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
padding: 0 8px !important;
/* v131.33:吸顶位置定死在自建搜索栏正下方(搜索栏高 52),
否则站内 PC 的 top 值会让它在手机上错位、把胶囊栏顶到搜索框底下。 */
position: sticky !important;
top: 52px !important;
z-index: 1000 !important;
background: #ffffff !important;
}
/* ------------------------------------------------------------
v131.25 UP主空间页→搜索页:隐藏「主页 动态 投稿 合集和系列」这一行
结构:#app > div.nav-bar.space-navbar[360x64](main 的前置兄弟节点)
#app > main.space-main.route_search
CSS 没有"选前面的兄弟"的选择器,所以用 :has() 从父级反查:
#app:has(> main.route_search) > .nav-bar.space-navbar
nav-bar 原生是 sticky,这里只写 display:none(不动 position),
收掉后它不再占位,下方内容自然顶上来,不留 64px 空隙。
------------------------------------------------------------ */
body.bili-space-page #app:has(> main.space-main.route_search) > .nav-bar.space-navbar,
body.bili-space-page #app:has(> main.space-main.route_search) > .header.space-header ~ .nav-bar.space-navbar,
body.bili-space-page:has(main.space-main.route_search) .nav-bar.space-navbar {
display: none !important;
visibility: hidden !important;
width: 0 !important;
max-width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* v131.36 UP主空间页→搜索页:隐藏 .header.space-header。
探针里它是 360x56(原为头像+昵称+关注),但脚本早已把内部内容
(头像/昵称/等级/签名/按钮等)逐个隐藏,只剩一个 56px 的空壳 —— 用户
截图确认"这一部分就是不存在"。
它的存在把胶囊栏整体推高了 56px:
搜索框底 52 → 空壳 52..108 → 胶囊栏 108..158
于是无论把间距放在胶囊栏的 padding 还是 margin 上,
白色胶囊 pill 的位置都是 116,肉眼看起来始终"紧贴搜索框"。
收掉空壳后:搜索框底 52 → 胶囊栏 60..110 → pill 顶 60,间距正好 8。
v131.40 这行改为「全部 UP主空间页都隐藏」(原先只对搜索页生效)。
原因是 v131.39 修掉了 #app 的 margin-top:-64px 之后,这行才第一次
真正露出来 —— 之前它被那 -64 顶到 top=-12..44,几乎整块压在固定
搜索栏(0..52)底下,所以你一直"看不到它"(v131.36 时你说得没错)。
现在归位到 52..108 就完整显示了,而里面的头像 .space-avatar 是
68x68、top=35,会往上戳进搜索栏区域被切掉一截 —— 正是你看到的
"被搜索栏遮挡了一部分"。
用户要求:这一行整体隐藏。于是直接收掉,不做显示。 */
body.bili-space-page .header.space-header,
body.bili-space-page #app > .header.space-header,
body.bili-space-page #app:has(> main.space-main.route_search) > .header.space-header,
body.bili-space-page:has(main.space-main.route_search) .header.space-header {
display: none !important;
visibility: hidden !important;
width: 0 !important;
max-width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
body.bili-space-page .nav-bar__main {
display: flex !important;
align-items: center !important;
justify-content: center !important;
flex-wrap: nowrap !important;
gap: 0 !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 52px !important;
max-height: 52px !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
/* .nav-tab / .nav-bar__main-left / 各 tab 项同压到 52(v131.26) */
body.bili-space-page .nav-bar__main-left,
body.bili-space-page .nav-tab {
height: 52px !important;
max-height: 52px !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
/* v131.27 按键组占满一整行,且「按键间距 = 左右距屏幕边缘」
实测(09-04-40 探针):.nav-bar__main[344] > .nav-bar__main-left[274]
> .nav-tab[274] ← 只到 274,右侧空 70
原因是 main-left 为 flex:0 1 auto / width:auto、nav-tab 也是 width:auto,
两者都只按内容宽度收缩,于是整组按键缩在中间。
改法:main-left 与 nav-tab 全部撑满 100%,tab 项改 flex:1 1 auto 均分余量。
算下来:内容区 344(nav-bar 左右各 8)− gap 8×3 = 24 − 按键自然宽
(52+52+52+94=250) = 70,4 个按键各增 17.5 → 69.5/69.5/69.5/111.5,
合计 320 + 24 = 344 正好满行;左右各留 8、按键间距 8,三者相等。 */
body.bili-space-page .nav-tab > a.nav-tab__item {
height: 52px !important;
max-height: 52px !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
flex: 1 1 auto !important;
width: auto !important;
min-width: 0 !important;
max-width: none !important;
}
body.bili-space-page .nav-bar__main-left {
display: flex !important;
align-items: center !important;
justify-content: center !important;
flex: 1 1 auto !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
}
body.bili-space-page .nav-tab {
display: flex !important;
align-items: center !important;
justify-content: flex-start !important;
gap: 8px !important;
white-space: nowrap !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .radio-filter {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
overflow: hidden !important;
padding: 0 !important;
margin: 0 !important;
}
body.bili-space-page button.playall-btn,
body.bili-space-page .vui_button.playall-btn,
body.bili-space-page .action-btn.playall-btn,
body.bili-space-page [class*="playall"] {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
overflow: hidden !important;
padding: 0 !important;
margin: 0 !important;
}
body.bili-space-page #app,
body.bili-space-page main.space-main,
body.bili-space-page .space-home {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
display: block !important;
}
body.bili-space-page .space-home > .aside,
body.bili-space-page .space-home > aside.aside,
body.bili-space-page main.space-main .aside {
display: none !important;
visibility: hidden !important;
width: 0 !important;
max-width: 0 !important;
min-width: 0 !important;
height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
flex: 0 0 0 !important;
position: absolute !important;
left: -9999px !important;
}
body.bili-space-page .space-home > .content {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
flex: 1 1 100% !important;
/* v131.41:底部 padding 16 -> 0(原为给页脚留的,页脚已隐藏) */
padding: 0 8px 0 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
}
/* ------------------------------------------------------------
v131.45 首页「视频 ·N 查看更多」标题行:上间距改为与下间距一致
探针(14-37-19)实测坐标:
上一区块(代表作)bottom = -6624
.section-wrap__header top = -6600 ← 上间距 = 24
.section-wrap__header bottom = -6566
.section-wrap__content top = -6550 ← 下间距 = 16(卡片顶)
即:上 24 / 下 16,不一致。
上间距 24 来自区块之间的 margin-bottom(24);
下间距 16 来自 header 与 content 之间的原生留白。
改法:给整个 video-section 区块加 margin-top: -8px,
把整块上提 8px(header 与 content 的相对位置不变,仍是 16),
于是上间距 24-8 = 16 = 下间距 16,两边一致。
用 :has() 定位而不写 nth-of-type,区块顺序变了也不会错位。
------------------------------------------------------------ */
body.bili-space-page .route_home .home-section:has(> .section-wrap.video-section) {
margin-top: -8px !important;
}
/* ------------------------------------------------------------
v131.41 首页滑到最底部:去掉那条没用的分割线及其下方的空白
探针(14-37-19,已滚到底)实测:
最后一张专栏卡 bottom = 735
最后一个 section-wrap bottom = 760 ← 分割线在这一带
.content bottom = 800 ← 文档底
即分割线下方还有 40px 空白,构成为:
最后一个 home-section 的 margin-bottom 24(区块间距,底部不需要)
+ .content 的 padding-bottom 16(页脚占位,页脚已隐藏)
用户要求:分割线去掉、分割线下方的高度去掉、分割线上方的高度保留。
故这里只清「分割线本身 + 下方 40px」,
section-wrap 内部那 25px(分割线上方)原样保留。
------------------------------------------------------------ */
body.bili-space-page .route_home .home-section:last-of-type,
body.bili-space-page .route_home .content > .home-section:last-child {
margin-bottom: 0 !important;
border-bottom: none !important;
}
body.bili-space-page .route_home .home-section:last-of-type .section-wrap,
body.bili-space-page .route_home .content > .home-section:last-child .section-wrap {
margin-bottom: 0 !important;
border-bottom: none !important;
box-shadow: none !important;
}
/* 分割线本身:清掉最后一个区块的伪元素与背景线 */
body.bili-space-page .route_home .home-section:last-of-type .section-wrap::after,
body.bili-space-page .route_home .home-section:last-of-type .section-wrap::before,
body.bili-space-page .route_home .content > .home-section:last-child .section-wrap::after,
body.bili-space-page .route_home .content > .home-section:last-child .section-wrap::before {
content: none !important;
display: none !important;
border: none !important;
background: none !important;
box-shadow: none !important;
}
/* .content / .space-home 底部若还挂着一条线,一并清掉 */
body.bili-space-page .route_home .content,
body.bili-space-page .route_home .space-home {
border-bottom: none !important;
box-shadow: none !important;
background-image: none !important;
}
body.bili-space-page .route_home .content::after,
body.bili-space-page .route_home .space-home::after,
body.bili-space-page .route_home .content::before,
body.bili-space-page .route_home .space-home::before {
content: none !important;
display: none !important;
border: none !important;
background: none !important;
box-shadow: none !important;
}
body.bili-space-page img,
body.bili-space-page video,
body.bili-space-page picture {
max-width: 100% !important;
height: auto !important;
}
body.bili-space-page .masterpiece-block,
body.bili-space-page .items,
body.bili-space-page .video-list__content,
body.bili-space-page .article-list {
display: grid !important;
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
grid-gap: 8px !important;
gap: 8px !important;
row-gap: 8px !important;
column-gap: 8px !important;
padding: 0 !important;
margin: 0 !important;
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
list-style: none !important;
align-items: start !important;
align-content: start !important;
background: transparent !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
overflow: visible !important;
grid-auto-rows: auto !important;
}
body.bili-space-page .items > .items__item,
body.bili-space-page .masterpiece-block > .masterpiece-block__item,
body.bili-space-page .video-list__content > .video-list__item,
body.bili-space-page .article-list > .article-list__item {
display: contents !important;
}
/* ------------------------------------------------------------
主页「合集·xxx / 系列·xxx」区块:标题行与视频卡片之间固定 20px
上面把 .video-list__content 的 margin/padding 全部归零,
刚进主页时站内那条原生顶部间距还没补上,文字就会紧贴卡片;
点一次「合集和系列」再切回来,站内样式补上了才恢复正常。
这里把间距统一交给 content 的 margin-top,
并清掉 header 的下边距与容器的 gap,避免两处叠加成双倍。
实测:修复前 .video-list 高 589(34+531+24),
正常态 609(多出的 20 就是这条间距)。
------------------------------------------------------------ */
body.bili-space-page .route_home .lists-section .video-list {
display: block !important;
gap: 0 !important;
row-gap: 0 !important;
column-gap: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
}
body.bili-space-page .route_home .lists-section .video-list__header {
margin-top: 0 !important;
margin-bottom: 0 !important;
padding-bottom: 0 !important;
}
body.bili-space-page .route_home .lists-section .video-list__content {
margin-top: 20px !important;
padding-top: 0 !important;
}
/* ------------------------------------------------------------
v131.20 UP主空间内搜索页(route_search,空间右上角搜索进来的结果页)
原结构:.space-search[360] 是 flex-row
> .search-sidebar[150 宽,纵向侧栏] > .side-nav > .side-nav__item[150x52]
> .search-content[736(PC 定宽)] > .video > .video-body
> .video-list.grid-mode[736] > .upload-video-card[364x282]
改法:sidebar 从左侧纵向栏改成顶部横向胶囊(同投稿页 .upload-sidenav /
动态页 .space-dynamic__left),content 满宽后卡片自然回到 168x172。
------------------------------------------------------------ */
body.bili-space-page .space-search {
display: flex !important;
flex-direction: column !important;
align-items: stretch !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
gap: 0 !important;
}
/* 「视频 328 / 动态 357」移到「主页 动态 投稿 合集和系列」下方,横向胶囊 */
body.bili-space-page .search-sidebar {
order: 1 !important;
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
max-height: none !important;
/* v131.35:同投稿页,间距改用容器外 margin-top 8,
padding-top 归零。搜索页紧贴胶囊栏上方的是 .header.space-header
(头像+昵称+已关注,56px),它底边 108 → 容器顶 116 → 胶囊顶 116,
容器间距与视觉间距都是 8。 */
padding: 0 8px 8px 8px !important;
margin: 8px 0 0 0 !important;
box-sizing: border-box !important;
/* v131.34:不吸顶,随页面滚走,不遮挡最上面的卡片
v131.37:改用 relative 并给低层级——
relative 不改变文档流位置(仍随页面滚动),
但能确保它参与正常的层叠顺序,不会被背景层压住。 */
position: relative !important;
top: auto !important;
left: auto !important;
right: auto !important;
bottom: auto !important;
z-index: 1 !important;
flex: 0 0 auto !important;
overflow: visible !important;
background: #f1f2f3 !important;
}
body.bili-space-page .search-sidebar .side-nav {
display: flex !important;
flex-direction: row !important;
justify-content: center !important;
align-items: center !important;
gap: 8px !important;
width: 100% !important;
max-width: 100% !important;
padding: 0 !important;
margin: 0 auto !important;
box-sizing: border-box !important;
flex-wrap: wrap !important;
position: static !important;
}
body.bili-space-page .search-sidebar .side-nav__item {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
flex: 0 0 auto !important;
width: auto !important;
min-width: 64px !important;
max-width: 100% !important;
height: 34px !important;
padding: 0 16px !important;
margin: 0 !important;
box-sizing: border-box !important;
border-radius: 17px !important;
background: #ffffff !important;
color: #18191c !important;
font-size: 13px !important;
white-space: nowrap !important;
position: static !important;
}
body.bili-space-page .search-sidebar .side-nav__item.active {
background: #00aeec !important;
color: #ffffff !important;
}
body.bili-space-page .search-sidebar .side-nav__item__main,
body.bili-space-page .search-sidebar .side-nav__item__sub {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 4px !important;
width: auto !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
background: transparent !important;
}
body.bili-space-page .search-sidebar .side-nav__item__main-text {
color: inherit !important;
font-size: 13px !important;
font-weight: 500 !important;
line-height: 34px !important;
}
body.bili-space-page .search-sidebar .side-nav__item__sub-text {
color: inherit !important;
font-size: 13px !important;
font-weight: 400 !important;
line-height: 34px !important;
opacity: 0.8 !important;
}
body.bili-space-page .search-content {
order: 2 !important;
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
flex: 1 1 100% !important;
padding: 0 8px 16px 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
position: static !important;
}
/* 视频结果:容器满宽 + 两列网格,卡片回到 168x172(同投稿页) */
body.bili-space-page .space-search .video,
body.bili-space-page .space-search .video-header,
body.bili-space-page .space-search .video-header__top,
body.bili-space-page .space-search .video-header .title,
body.bili-space-page .space-search .video-header .sub-title,
body.bili-space-page .space-search .video-body {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
}
/* v131.33 搜索页:整行移除「共找到关于"宝可梦"的 N 个视频 / 条动态」
(v131.31/32 只收了 .title,sub-title 保留;这版连 header 整块收掉)
实测:.video-header[344x20] / .dynamic-header[344x70]。
收掉后胶囊与卡片之间只剩 sidenav 自带的 padding-bottom 8 → 正好 8px。 */
body.bili-space-page .space-search .video-header,
body.bili-space-page .space-search .video-header__top,
body.bili-space-page .space-search .video-header .title,
body.bili-space-page .space-search .video-header .sub-title,
body.bili-space-page .space-search .dynamic-header,
body.bili-space-page .space-search .dynamic-header__top,
body.bili-space-page .space-search .dynamic-header .title,
body.bili-space-page .space-search .dynamic-header .sub-title {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* 胶囊底 → 卡片顶 = sidenav padding-bottom 8 + 0 = 8 */
body.bili-space-page .space-search .video-body,
body.bili-space-page .space-search .dynamic-content {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .space-search .video-list,
body.bili-space-page .space-search .video-list.grid-mode,
body.bili-space-page .space-search .video-list.hide-stat {
display: grid !important;
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
grid-gap: 8px !important;
gap: 8px !important;
row-gap: 8px !important;
column-gap: 8px !important;
align-items: start !important;
align-content: start !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
}
body.bili-space-page .space-search .upload-video-card,
body.bili-space-page .space-search .upload-video-card.grid-mode,
body.bili-space-page .space-search .upload-video-card__left,
body.bili-space-page .space-search .upload-video-card__main {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
/* 动态结果:与动态页一致(.search-content 已有 8px 边距,
这里把 item 的左右内边距归零,避免叠加成 16px)
v131.21 修正:搜索页动态用的是 .dynamic-list(不是动态页的 .bili-dyn-list),
而且是 PC 定宽 720(.dynamic-list[720] > .dynamic-list__item[720x670]),
在 360 屏上直接溢出。这里把整条链压回 100%。 */
body.bili-space-page .space-search .dynamic,
body.bili-space-page .space-search .dynamic-header,
body.bili-space-page .space-search .dynamic-content,
body.bili-space-page .space-search .dynamic-list,
body.bili-space-page .space-search .dynamic-list__item,
body.bili-space-page .space-search .bili-dyn-list,
body.bili-space-page .space-search .bili-dyn-list__items,
body.bili-space-page .space-search .bili-dyn-item,
body.bili-space-page .space-search .bili-dyn-item__main {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .space-search .dynamic-list__item,
body.bili-space-page .space-search .bili-dyn-list__item {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 0 0 8px 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
/* 720 定宽带来的横向滚动也要掐掉,否则 360 屏会被撑开 */
body.bili-space-page .space-search .dynamic-content,
body.bili-space-page .space-search .dynamic-list {
display: block !important;
overflow-x: hidden !important;
padding-left: 0 !important;
padding-right: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
}
body.bili-space-page .space-search .dynamic-list__item .bili-dyn-item,
body.bili-space-page .space-search .dynamic-list__item .bili-dyn-item__main,
body.bili-space-page .space-search .dynamic-list__item .bili-dyn-item__header,
body.bili-space-page .space-search .dynamic-list__item .bili-dyn-item__body,
body.bili-space-page .space-search .dynamic-list__item .bili-dyn-item__footer {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
margin-left: 0 !important;
margin-right: 0 !important;
}
/* ------------------------------------------------------------
v131.23 底部分页器(投稿→视频 / 空间搜索→视频)对齐主搜索页
两者对比(都在第 1 页):
主搜索页 .vui_pagenation[360x50] > .vui_pagenation--btns[360x34]
上一页 61x34 | 数字 32x34 | 下一页 61x34 | 无跳转区
空间页 .vui_pagenation--jump.video-pagination[736x34] ← PC 定宽溢出
> .vui_pagenation--btns[478x34]
数字 34x34 | 下一页 100x34
> .vui_pagenation-go[214x34] 「共 16 页 / 618 个,跳至 __ 页」
改法:容器压回 100% 并居中,按钮套用主搜索页同一组尺寸,
跳转区整块隐藏(.vui_pagenation-go)。
v131.24 补:上下间距对齐主搜索页。
主搜索页实测:外层 .flex_center.mt_x50.mb_x50[360x50],
脚本 870 行已把它的 margin 上下压成 8px;分页器 padding 8 0 + btns 34 = 50。
父容器 div[360x3854] = 列表 3788 + 50 + 8 + 8,正好相等
→ 父容器没有额外的 padding-bottom。
所以主搜索页的视觉间距是:卡片底 → 8+8 = 16 → 按钮 → 8+8 = 16 → 容器底。
空间页:.video-footer 原生 154 高(= 分页器 34 + 上下各 60),
且父容器 .upload-content / .search-content 自带 padding-bottom 16
(实测 .upload-content[360x3758] − .video[344x3742] = 16)。
若不抵消,底部会变成 8 + 8 + 16 = 24,比主搜索页多 8px。
故 .video-footer 取 margin: 8px 0 -8px(下边 -8 抵消父容器多出的 8),
分页器保持 padding: 8px 0 → 上下视觉间距各 16px,与主搜索页一致。
------------------------------------------------------------ */
/* 外层:上 8 / 下 -8(抵消父容器底部 padding 多出的 8) */
body.bili-space-page .video-footer {
display: flex !important;
flex-direction: row !important;
justify-content: center !important;
align-items: center !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
padding: 0 !important;
margin: 8px 0 -8px 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
background: transparent !important;
}
/* v131.49 「合集和系列」页底部分页器:上下间距与「投稿→视频」页完全一致
两份探针同批实测(09-28_17-45-47 = 投稿→视频,09-28_17-45-34 = 合集和系列):
投稿→视频(基准,已达标)
.video-body bottom=3736 ← 最后一张卡片底
.video-footer top=3744 h=50 pt=0 pb=0 mt=8 mb=-8
.video-pagination pt=8 pb=8
.vui_pagenation--btns 3752 → 3786
.upload-content pb=16 → main bottom=3802
⇒ 卡片底→按钮顶 = 3752-3736 = 16
⇒ 按钮底→页面底 = 3802-3786 = 16
合集和系列(改前)
.lists-content bottom=11891 ← 最后一张卡片底
.lists-footer top=11891 h=110 **pt=60** pb=0 mt=0 mb=0
.audio-list-paginaion pt=8 pb=8(已被上面 .vui_pagenation 通配规则压好)
.vui_pagenation--btns 11959 → 11993
.space-lists pb=16 → main bottom=12017
⇒ 卡片底→按钮顶 = 11959-11891 = 68(多 52,全来自 pt=60)
⇒ 按钮底→页面底 = 12017-11993 = 24(多 8,因为没有 mb=-8 抵消)
两页的分页器本体、父容器 padding-bottom 16 都已经相同,
差异 100% 出在 footer 这一层。所以直接照抄 .video-footer
那组已验证过的参数(padding 0 + margin 8px 0 -8px):
上 = mt 8 + pagination pt 8 = 16 ✓
下 = pagination pb 8 + mb(-8) + space-lists pb 16 = 16 ✓
------------------------------------------------------------ */
body.bili-space-page .lists-footer {
display: flex !important;
flex-direction: row !important;
justify-content: center !important;
align-items: center !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
padding: 0 !important;
margin: 8px 0 -8px 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
background: transparent !important;
}
/* 高特异性兜底(v131.36 套路),防站内晚加载的同权重 !important */
body.bili-space-page main.space-main.route_listsIndex
> .space-lists > .lists-footer {
padding: 0 !important;
margin: 8px 0 -8px 0 !important;
}
/* 分页器本体:与主搜索页同款 padding 8px 0 */
body.bili-space-page .vui_pagenation,
body.bili-space-page .vui_pagenation--jump,
body.bili-space-page .vui_pagenation--jump.video-pagination {
display: flex !important;
flex-direction: row !important;
justify-content: center !important;
align-items: center !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
padding: 8px 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
background: transparent !important;
}
/* 「共 N 页 / N 个,跳至 __ 页」整块隐藏 */
body.bili-space-page .vui_pagenation-go,
body.bili-space-page .vui_pagenation--jump .vui_pagenation-go,
body.bili-space-page .vui_pagenation .vui_input {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-width: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* 按钮行:与主搜索页同款(全宽、gap 4、可横向滚动、隐藏滚动条) */
body.bili-space-page .vui_pagenation--btns {
display: flex !important;
flex-direction: row !important;
flex-wrap: nowrap !important;
justify-content: flex-start !important;
align-items: center !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 0 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
gap: 4px !important;
overflow-x: auto !important;
overflow-y: hidden !important;
-webkit-overflow-scrolling: touch !important;
scrollbar-width: none !important;
-ms-overflow-style: none !important;
}
body.bili-space-page .vui_pagenation--btns::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
}
/* 单个按钮:数字 32x34、字号 13、圆角 4,与主搜索页一致 */
body.bili-space-page .vui_pagenation--btn {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
flex-shrink: 0 !important;
flex-grow: 0 !important;
width: auto !important;
min-width: 32px !important;
height: 34px !important;
line-height: 34px !important;
padding: 0 6px !important;
margin: 0 !important;
box-sizing: border-box !important;
white-space: nowrap !important;
font-size: 13px !important;
text-align: center !important;
border-radius: 4px !important;
}
/* 上一页 / 下一页:空间页原生 100x34,压回主搜索页的 61 宽 */
body.bili-space-page .vui_pagenation--btn-side {
min-width: 44px !important;
padding: 0 10px !important;
font-size: 13px !important;
}
body.bili-space-page .space-dynamic {
display: flex !important;
flex-direction: column !important;
align-items: stretch !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
gap: 0 !important;
}
body.bili-space-page .space-dynamic__left {
order: 1 !important;
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
max-height: none !important;
padding: 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
position: static !important;
top: auto !important;
left: auto !important;
bottom: auto !important;
right: auto !important;
background: #f1f2f3 !important;
flex: 0 0 auto !important;
overflow: visible !important;
}
body.bili-space-page .space-dynamic__left .side-nav {
display: flex !important;
flex-direction: row !important;
justify-content: center !important;
align-items: center !important;
gap: 8px !important;
width: 100% !important;
max-width: 100% !important;
padding: 0 !important;
margin: 0 auto !important;
box-sizing: border-box !important;
flex-wrap: wrap !important;
position: static !important;
}
body.bili-space-page .space-dynamic__left .side-nav__item {
display: flex !important;
align-items: center !important;
justify-content: center !important;
flex: 0 0 auto !important;
width: auto !important;
min-width: 64px !important;
max-width: 100% !important;
height: 34px !important;
padding: 0 16px !important;
margin: 0 !important;
box-sizing: border-box !important;
border-radius: 17px !important;
background: #ffffff !important;
color: #18191c !important;
font-size: 13px !important;
cursor: pointer !important;
user-select: none !important;
white-space: nowrap !important;
position: static !important;
}
body.bili-space-page .space-dynamic__left .side-nav__item.active {
background: #00aeec !important;
color: #ffffff !important;
}
body.bili-space-page .space-dynamic__left .side-nav__item__main {
display: flex !important;
align-items: center !important;
justify-content: center !important;
gap: 4px !important;
width: auto !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
background: transparent !important;
}
body.bili-space-page .space-dynamic__left .side-nav__item__main-text {
color: inherit !important;
font-size: 13px !important;
font-weight: 500 !important;
line-height: 34px !important;
}
body.bili-space-page .space-dynamic__content {
order: 2 !important;
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
flex: 1 1 100% !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
}
body.bili-space-page .space-dynamic__right {
display: none !important;
visibility: hidden !important;
width: 0 !important;
max-width: 0 !important;
height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
flex: 0 0 0 !important;
position: absolute !important;
left: -9999px !important;
}
body.bili-space-page .space-dynamic-inner,
body.bili-space-page .space-dynamic-inner > .content,
body.bili-space-page .bili-dyn-list,
body.bili-space-page .bili-dyn-list__items {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .bili-dyn-list__item {
padding: 0 8px 8px 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
float: none !important;
}
body.bili-space-page .bili-dyn-item {
position: relative !important;
background: #ffffff !important;
border: 1px solid #e3e5e7 !important;
border-radius: 8px !important;
padding: 12px 8px 0 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
display: block !important;
float: none !important;
}
body.bili-space-page .bili-dyn-item * {
max-width: 100% !important;
box-sizing: border-box !important;
}
body.bili-space-page .bili-dyn-item img,
body.bili-space-page .bili-dyn-item video,
body.bili-space-page .bili-dyn-item picture {
max-width: 100% !important;
height: auto !important;
}
body.bili-space-page .bili-dyn-item__main {
position: relative !important;
padding-left: 0 !important;
padding-right: 0 !important;
box-sizing: border-box !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
float: none !important;
}
body.bili-space-page .bili-dyn-item__avatar {
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 56px !important;
max-width: 56px !important;
min-width: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .bili-dyn-item__avatar .bili-dyn-avatar,
body.bili-space-page .bili-dyn-item__avatar .b-avatar,
body.bili-space-page .bili-dyn-item__avatar img {
width: 48px !important;
height: 48px !important;
max-width: 100% !important;
border-radius: 50% !important;
}
body.bili-space-page .bili-dyn-item__header {
margin-left: 0 !important;
margin-right: 0 !important;
padding-left: 64px !important;
padding-right: 8px !important;
width: auto !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .bili-dyn-item__more,
body.bili-space-page .bili-dyn-more,
body.bili-space-page .bili-dyn-more__btn,
body.bili-space-page .bili-dyn-more__cascader {
display: none !important;
visibility: hidden !important;
}
body.bili-space-page .bili-dyn-content,
body.bili-space-page .bili-dyn-content__orig,
body.bili-space-page .bili-dyn-content__orig__major {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .bili-dyn-card-video {
display: flex !important;
flex-direction: column !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
box-sizing: border-box !important;
}
body.bili-space-page .bili-dyn-card-video__header {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
flex: 0 0 auto !important;
box-sizing: border-box !important;
}
body.bili-space-page .bili-dyn-card-video__cover {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
aspect-ratio: 16 / 9 !important;
box-sizing: border-box !important;
}
body.bili-space-page .bili-dyn-card-video__cover .b-img,
body.bili-space-page .bili-dyn-card-video__cover .b-img__inner,
body.bili-space-page .bili-dyn-card-video__cover img,
body.bili-space-page .bili-dyn-card-video__cover picture {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
aspect-ratio: 16 / 9 !important;
object-fit: cover !important;
display: block !important;
}
body.bili-space-page .bili-dyn-card-video__body {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
flex: 1 1 auto !important;
padding: 8px 0 0 0 !important;
box-sizing: border-box !important;
}
/* 投稿了视频:隐藏视频封面下方「框住标题/简介文字」的那条左侧半开口边框 */
body.bili-space-page .bili-dyn-card-video__body,
body.bili-space-page .bili-dyn-card-video__title,
body.bili-space-page .bili-dyn-card-video__desc {
border: none !important;
border-top: none !important;
border-right: none !important;
border-bottom: none !important;
border-left: none !important;
border-width: 0 !important;
border-style: none !important;
box-shadow: none !important;
outline: none !important;
}
/* 该边框也可能是 ::before / ::after 画的竖条,一并清掉 */
body.bili-space-page .bili-dyn-card-video__body::before,
body.bili-space-page .bili-dyn-card-video__body::after,
body.bili-space-page .bili-dyn-card-video__desc::before,
body.bili-space-page .bili-dyn-card-video__desc::after {
content: none !important;
display: none !important;
border: none !important;
background: none !important;
box-shadow: none !important;
}
body.bili-space-page .bili-dyn-card-video__title,
body.bili-space-page .bili-dyn-card-video__desc,
body.bili-space-page .bili-dyn-card-video__title .bili-ellipsis,
body.bili-space-page .bili-dyn-card-video__desc .bili-ellipsis { text-align: center !important; }
body.bili-space-page .bili-dyn-card-video__stat,
body.bili-space-page .bili-dyn-card-video__stat__item,
body.bili-space-page .bili-dyn-card-video__stat__item.danmaku {
display: none !important;
visibility: hidden !important;
height: 0 !important;
overflow: hidden !important;
margin: 0 !important;
padding: 0 !important;
}
body.bili-space-page .bili-dyn-item,
body.bili-space-page .bili-dyn-item * {
text-align: center !important;
}
/* 正文容器:只做内边距约束,绝不能隐藏(正文 .bili-dyn-content 就在它里面) */
body.bili-space-page .bili-dyn-item__body {
margin-left: 0 !important;
margin-right: 0 !important;
padding-left: 8px !important;
padding-right: 8px !important;
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
}
/* 去掉卡片内的「转发 / 评论 / 点赞」数量行(整行隐藏,与动态一致) */
body.bili-space-page .bili-dyn-item__footer,
body.bili-space-page .bili-dyn-item__action,
body.bili-space-page .bili-dyn-action,
body.bili-space-page .bili-dyn-action.forward,
body.bili-space-page .bili-dyn-action.comment,
body.bili-space-page .bili-dyn-action.like {
display: none !important;
visibility: hidden !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* 隐藏该行后,卡片底部补回一点留白,避免内容紧贴卡片下边缘 */
body.bili-space-page .bili-dyn-item {
padding-bottom: 12px !important;
}
body.bili-space-page .bili-dyn-content__orig__major img,
body.bili-space-page .bili-dyn-content__orig__major picture,
body.bili-space-page .bili-dyn-content__orig__major .b-img {
margin-left: auto !important;
margin-right: auto !important;
display: block !important;
}
body.bili-space-page .bili-dyn-content__orig__major [class*="grid"],
body.bili-space-page .bili-dyn-content__orig__major [class*="pics"],
body.bili-space-page .bili-dyn-content__orig__major [class*="gallery"],
body.bili-space-page .bili-dyn-content__orig__major [class*="goods"],
body.bili-space-page .bili-dyn-content__orig__major [class*="commodity"],
body.bili-space-page .bili-dyn-content__orig__major [class*="card"] {
margin-left: auto !important;
margin-right: auto !important;
justify-content: center !important;
}
body.bili-space-page .bili-dyn-item__action {
flex: 1 1 0 !important;
width: auto !important;
max-width: none !important;
min-width: 0 !important;
box-sizing: border-box !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
}
body.bili-space-page .bili-dyn-action {
display: flex !important;
align-items: center !important;
justify-content: center !important;
width: 100% !important;
gap: 4px !important;
}
body.bili-space-page .space-upload {
display: flex !important;
flex-direction: column !important;
align-items: stretch !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
gap: 0 !important;
}
body.bili-space-page .upload-sidenav {
order: 1 !important;
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
max-height: none !important;
/* v131.35:间距必须在容器「外面」用 margin,不能靠内部 padding-top。
按内部 padding 算的话,容器顶 160 紧贴 nav-bar 底 160,容器间距是 0。
padding-top 归零 + margin-top 8 后:容器顶 168、胶囊顶 168,
容器间距与视觉间距都是 8。 */
padding: 0 8px 8px 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
position: static !important;
flex: 0 0 auto !important;
overflow: visible !important;
background: #f1f2f3 !important;
/* v131.34:按用户选择改回不吸顶,随页面一起滚走。
吸顶虽能保证间距,但会把最上面的卡片遮住一部分;
改为 static 后卡片完整显示,胶囊距导航条 8px(自身 padding-top)。 */
position: static !important;
top: auto !important;
z-index: auto !important;
}
body.bili-space-page .upload-sidenav .side-nav {
display: flex !important;
flex-direction: row !important;
justify-content: center !important;
align-items: center !important;
gap: 8px !important;
width: 100% !important;
max-width: 100% !important;
padding: 0 !important;
margin: 0 auto !important;
box-sizing: border-box !important;
flex-wrap: wrap !important;
position: static !important;
}
body.bili-space-page .upload-sidenav .side-nav__item {
display: flex !important;
align-items: center !important;
justify-content: center !important;
flex: 0 0 auto !important;
width: auto !important;
min-width: 64px !important;
max-width: 100% !important;
height: 34px !important;
padding: 0 16px !important;
margin: 0 !important;
box-sizing: border-box !important;
border-radius: 17px !important;
background: #ffffff !important;
color: #18191c !important;
font-size: 13px !important;
cursor: pointer !important;
user-select: none !important;
white-space: nowrap !important;
position: static !important;
}
body.bili-space-page .upload-sidenav .side-nav__item.active {
background: #00aeec !important;
color: #ffffff !important;
}
body.bili-space-page .upload-sidenav .side-nav__item__main {
display: flex !important;
align-items: center !important;
justify-content: center !important;
gap: 4px !important;
width: auto !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
background: transparent !important;
}
body.bili-space-page .upload-sidenav .side-nav__item__main-text {
color: inherit !important;
font-size: 13px !important;
font-weight: 500 !important;
line-height: 34px !important;
}
body.bili-space-page .upload-content {
order: 2 !important;
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
flex: 1 1 100% !important;
padding: 0 8px 16px 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
position: static !important;
}
/* ------------------------------------------------------------
v131.30 投稿页:移除「TA的视频」,并让筛选胶囊与卡片等距
实测(11-01-27 探针):
.upload-sidenav[360x50] = padding 8 + 胶囊 34 + padding 8
.upload-content[360x3742] → .video[344x3734]
> .video-header[344x64](.video-header__top > .title「TA的视频」)
> .video-body[344x3582](卡片网格)
> .video-footer(分页器)
1) 隐藏「TA的视频」:直接收掉整个 .video-header(64 高),
只隐藏 .title 会留下 64px 空白,间距仍然对不上。
2) 间距对齐分页器:v131.24 已把分页器按钮距底定为 16px
(pagenation padding-bottom 8 + video-footer margin -8
+ upload-content padding-bottom 16)。
胶囊底 → 卡片顶要同样为 16px:
sidenav 自带 padding-bottom 8 + .video-body margin-top 8 = 16
------------------------------------------------------------ */
body.bili-space-page .upload-content .video-header,
body.bili-space-page .upload-content .video-header__top,
body.bili-space-page .upload-content .video-header .title,
body.bili-space-page .upload-content .video-header .sub-title {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
}
body.bili-space-page .upload-content .video-body {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
/* v131.31:胶囊底 → 卡片顶 = sidenav padding-bottom 8 + 0 = 8
(与卡片间距一致。v131.30 的 8px 会让总间距变成 16) */
margin-top: 0 !important;
margin-bottom: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
/* v131.35:nav-bar 底 → 胶囊栏容器顶 = 8(容器外 margin)。
注意这条在后面,会覆盖前面的 margin: 0,必须写成 8。 */
body.bili-space-page .upload-sidenav {
margin-top: 8px !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
}
/* v131.36 兜底:用「父 > 子:nth-of-type(1)」把特异性提到最高,
确保 margin-top 8 / padding-top 0 不被任何同名规则盖回去。 */
body.bili-space-page .space-upload > div.upload-sidenav:nth-of-type(1) {
margin-top: 8px !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
}
body.bili-space-page .space-search > div.search-sidebar:nth-of-type(1) {
margin-top: 8px !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
}
body.bili-space-page .lists-view-mode,
body.bili-space-page .video-mode-switcher,
body.bili-space-page .lists-view-mode__action {
display: none !important;
visibility: hidden !important;
}
body.bili-space-page .upload-content .video-list,
body.bili-space-page .upload-content .video-list.grid-mode,
body.bili-space-page .upload-content .video-list.hide-stat,
body.bili-space-page .video-list.grid-mode,
body.bili-space-page .video-list.hide-stat {
display: grid !important;
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
grid-gap: 8px !important;
gap: 8px !important;
row-gap: 8px !important;
column-gap: 8px !important;
padding: 0 !important;
margin: 0 !important;
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
list-style: none !important;
align-items: start !important;
align-content: start !important;
background: transparent !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
overflow: visible !important;
grid-auto-rows: auto !important;
}
/* ------------------------------------------------------------
v131.16 「合集和系列」整页(route_listsIndex)左右边距对齐主页
结构:main.space-main.route_listsIndex
> .space-lists[360 满屏,无内边距]
> .lists-header[360] + .lists-content[360]
> .contet-list[360] > .video-list[360]
> .video-list__content[360,已是两列网格 gap8]
这一页此前没有命中任何边距规则,卡片 176 宽直接顶到屏幕边缘;
主页 .space-home > .content 是 padding: 0 8px 16px 8px,
这里给 .space-lists 同一组值,内容宽回到 344、卡片 168,与主页一致。
v131.17 修正:只补左右边距,不要动 position / padding-top。
.lists-header 是 sticky 定位(自带 top 偏移躲开吸顶的 navbar),
上一版给它写了 position: static,粘性失效后它就直接跑到
「主页 动态 投稿 合集和系列」那一排按键底下被压住了。
同理 padding-top 也不能清零。
------------------------------------------------------------ */
body.bili-space-page .space-lists {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 8px !important;
padding-right: 8px !important;
padding-bottom: 16px !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
overflow: visible !important;
}
body.bili-space-page .space-lists .lists-content,
body.bili-space-page .space-lists .contet-list,
body.bili-space-page .space-lists .video-list {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
}
/* 标题行同样只补左右,保留它自己的 sticky / top 偏移 */
body.bili-space-page .space-lists .lists-header {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
padding-bottom: 16px !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
}
/* v131.49 去掉「合集和系列」这一行大标题。
探针 09-28_17-45-34 实测:
main.route_listsIndex top=134(.space-lists mt=30)
> .space-lists
> .lists-header[344x50] top=134 bottom=184 pt=0 pb=16
> .title[120x34] top=134 bottom=168 text=合集和系列
> .lists-content[344x11707] top=184
.lists-header 里**只有 .title 一个子节点**,没有别的控件,
所以整块 display:none 即可,不需要单独去清 .title
(.title 是站内通用类名,单独选中反而容易误伤别的页面)。
隐藏后 .lists-content 直接顶到 main 的 134,
与 navbar 底部(104)之间保留 .space-lists 自带的 mt=30。
上面 v131.17 那条「不要动 .lists-header 的 position / padding-top」
的告诫在这里不适用了——整块都不显示了,sticky 也就无从谈起。 */
body.bili-space-page .space-lists > .lists-header {
display: none !important;
}
body.bili-space-page main.space-main.route_listsIndex
> .space-lists > .lists-header {
display: none !important;
}
body.bili-space-page .space-lists .lists-header .title {
display: none !important;
}
/* 标题行与卡片之间,沿用主页「合集·/系列·」的 20px */
body.bili-space-page .space-lists .video-list__content {
margin-top: 20px !important;
}
/* ------------------------------------------------------------
v131.18 合集详情页(route_listDetails,点进某个「合集·xxx」后)
结构:main.space-main.route_listDetails
> .space-list-details[360]
> .list-header[360x110](.title + .subtitle)
> .list-content[360x170]
> .list-video-item[59x110,桌面版一排放 5 个]
问题:整页无边距、卡片被压成 59 宽(封面只剩 33 高)。
改法:外层补 8px 左右边距(同主页 .space-home > .content),
.list-content 改两列网格,卡片回到 168x172(封面 95 + 信息区 77)。
注意:.list-header 同样是 sticky,这里不写 position / padding-top。
------------------------------------------------------------ */
body.bili-space-page .space-list-details {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 8px !important;
padding-right: 8px !important;
padding-bottom: 16px !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
overflow: visible !important;
}
body.bili-space-page .space-list-details .list-header {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
}
/* 标题「合集·xxx」与卡片之间 20px,和主页一致 */
body.bili-space-page .space-list-details .list-header .subtitle,
body.bili-space-page .space-list-details .list-header .meta {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin-bottom: 20px !important;
box-sizing: border-box !important;
}
/* v131.50 合集详情页:「合集 6个视频 9月14日更新」整行居中
探针 09-28_18-03-48 实测(route_listDetails):
.list-header[344x144] top=134 bottom=278 mb=22
> .title[344x68] (.back[20x20] + .name[316x68])mb=20
> .subtitle[344x20] top=222 **pos=relative** mb=20
> .meta[344x20] mb=20
> .stats[344x20] text=合集 6个视频 9月14日更新
三层盒子都已经是满宽 344,文字靠左只是因为默认 text-align。
所以这里**不改 display**(.subtitle 是 relative、.meta/.stats
可能是 flex,贸然改成 block 会把站内的行内排布打散),
只同时给两条居中通路:
text-align:center -> 命中普通块级 / 行内文本
justify-content:center -> 命中 flex 容器
两条互不干扰,谁生效取决于站内实际用的是哪种布局。 */
body.bili-space-page .space-list-details .list-header .subtitle,
body.bili-space-page .space-list-details .list-header .subtitle .meta,
body.bili-space-page .space-list-details .list-header .subtitle .meta .stats,
body.bili-space-page .space-list-details .list-header .meta,
body.bili-space-page .space-list-details .list-header .stats {
text-align: center !important;
justify-content: center !important;
}
/* 高特异性兜底(v131.36 套路) */
body.bili-space-page main.space-main.route_listDetails
> .space-list-details > .list-header > .subtitle > .meta > .stats {
text-align: center !important;
justify-content: center !important;
}
/* v131.50 顺带覆盖 .list-header 里除 .title 以外的任何直接子节点。
原因:探针算下来 .list-header 有 16px 对不上账——
.title 68 + mb 20 + .subtitle 20 + mb 20 = 128,
而 .list-header 实测 144 高,多出的 16px 在探针里找不到归属元素。
「默认 / 倒序」排序按键在这份探针里也完全查不到
(5 份探针全文 grep「排序 / 默认 / 倒序」均 0 命中),
很可能就是这块延迟渲染 / 未被探针遍历到的东西。
这条规则只写 text-align / justify-content,命中不了就完全无副作用,
命中了就顺手把它一起居中;真正的定位还要等新探针确认。 */
body.bili-space-page .space-list-details .list-header > *:not(.title) {
text-align: center !important;
justify-content: center !important;
}
/* v131.51 合集详情页:简介行「.desc」文字一半跑到屏幕外 + 居中
探针 09-28_18-14-58 实测(route_listDetails):
.list-header[344x210] top=134 bottom=344 mb=22
> .title[344x102] (.back[20x20] + .name[316x102])mb=20
> **.desc[677x20]** top=256 left=8 mb=12 ovf=hidden
> .subtitle[344x20] top=288(pos=relative)mb=20
真凶就是 .desc:它是站内 PC 版留下的**定宽 677px**,
在 360 的视口里从 left=8 一直伸到 685,右半截整个在屏幕外;
自身 overflow:hidden 又只给 20px 高,等于"一行 + 裁掉右边"。
(顺带结案:上一版探针里 .list-header 对不上账的那 16px,
就是这个 .desc —— 那份探针没有列出它,我当时推测是排序按键,
推错了,排序按键在 .subtitle 里,已由 v131.50 那条规则居中。)
改法:宽度收回 100%(344),高度放开让它按 344 宽自动换行
(这句 21 个字,677px 一行 -> 344px 两行),
再解掉站内的单行省略号机制(nowrap / ellipsis / line-clamp),
最后 text-align + justify-content 双通路居中。 */
body.bili-space-page .space-list-details .list-header .desc,
body.bili-space-page .space-list-details .list-header > .desc {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
margin: 0 0 12px 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
float: none !important;
line-height: 20px !important;
text-align: center !important;
justify-content: center !important;
white-space: normal !important;
word-break: break-word !important;
overflow-wrap: anywhere !important;
text-overflow: clip !important;
-webkit-line-clamp: unset !important;
line-clamp: unset !important;
overflow: visible !important;
background: transparent !important;
}
/* 高特异性兜底(v131.36 套路):站内这条定宽大概率写在选择器里,
用完整链路压过去,确保 677px 一定被 100% 顶掉。 */
body.bili-space-page main.space-main.route_listDetails
> .space-list-details > .list-header > .desc {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
max-height: none !important;
text-align: center !important;
white-space: normal !important;
overflow: visible !important;
}
body.bili-space-page .space-list-details .list-content {
display: grid !important;
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
grid-auto-rows: auto !important;
gap: 8px !important;
row-gap: 8px !important;
column-gap: 8px !important;
align-items: start !important;
align-content: start !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
float: none !important;
overflow: visible !important;
}
/* 桌面版给 item 算的是 5 列宽(59),这里放开让它吃满格子 */
body.bili-space-page .space-list-details .list-video-item {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
position: static !important;
transform: none !important;
left: auto !important;
top: auto !important;
float: none !important;
flex: 0 1 auto !important;
}
/* ============================================================
========== 通用两列视频卡片 ==========
============================================================ */
body.bili-home-page .container .bili-video-card,
body.bili-home-page .container .bili-live-card,
body.bili-search-page .bili-video-card,
body.bili-search-page .bili-live-card,
body.bili-search-page .search-video-card,
body.bili-space-page .bili-video-card,
body.bili-space-page .bili-live-card {
--cover-radio: 56.25% !important;
--title-font-size: 13px !important;
--title-line-height: 18px !important;
--title-padding-right: 0 !important;
--no-interest-entry-size: 22px !important;
--info-margin-top: 6px !important;
--subtitle-font-size: 11px !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
max-height: none !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
display: block !important;
align-self: start !important;
background: #ffffff !important;
border: none !important;
border-radius: 8px !important;
box-shadow: 0 1px 3px rgba(0,0,0,0.08) !important;
overflow: hidden !important;
box-sizing: border-box !important;
position: relative !important;
float: none !important;
}
body.bili-home-page .container .bili-video-card__wrap,
body.bili-home-page .container .bili-live-card__wrap,
body.bili-search-page .bili-video-card__wrap,
body.bili-search-page .bili-live-card__wrap,
body.bili-space-page .bili-video-card__wrap,
body.bili-space-page .bili-live-card__wrap {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
max-height: none !important;
margin: 0 !important;
padding: 0 !important;
display: block !important;
background: transparent !important;
border: none !important;
border-radius: 8px !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
body.bili-home-page .bili-video-card__image--wrap,
body.bili-home-page .bili-video-card__image--link,
body.bili-home-page .v-img.bili-video-card__cover,
body.bili-home-page .bili-video-card .b-img,
body.bili-home-page .bili-video-card picture,
body.bili-search-page .bili-video-card__image--wrap,
body.bili-search-page .bili-video-card__image--link,
body.bili-search-page .v-img.bili-video-card__cover,
body.bili-search-page .bili-video-card .b-img,
body.bili-search-page .bili-video-card picture,
body.bili-space-page .bili-video-card__image--wrap,
body.bili-space-page .bili-video-card__image--link,
body.bili-space-page .v-img.bili-video-card__cover,
body.bili-space-page .bili-video-card .b-img,
body.bili-space-page .bili-video-card picture {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
border-radius: 8px 8px 0 0 !important;
overflow: hidden !important;
position: relative !important;
display: block !important;
float: none !important;
box-sizing: border-box !important;
}
body.bili-home-page .bili-video-card__image--wrap img,
body.bili-home-page .bili-video-card__image--link img,
body.bili-home-page .v-img.bili-video-card__cover img,
body.bili-home-page .bili-video-card .b-img > img,
body.bili-home-page .bili-video-card .b-img__inner,
body.bili-home-page .bili-video-card picture img,
body.bili-search-page .bili-video-card__image--wrap img,
body.bili-search-page .bili-video-card__image--link img,
body.bili-search-page .v-img.bili-video-card__cover img,
body.bili-search-page .bili-video-card .b-img > img,
body.bili-search-page .bili-video-card .b-img__inner,
body.bili-search-page .bili-video-card picture img,
body.bili-space-page .bili-video-card__image--wrap img,
body.bili-space-page .bili-video-card__image--link img,
body.bili-space-page .v-img.bili-video-card__cover img,
body.bili-space-page .bili-video-card .b-img > img,
body.bili-space-page .bili-video-card .b-img__inner,
body.bili-space-page .bili-video-card picture img {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
aspect-ratio: 16 / 9 !important;
object-fit: cover !important;
display: block !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
body.bili-home-page .bili-video-card__image--wrap picture > *,
body.bili-search-page .bili-video-card__image--wrap picture > *,
body.bili-space-page .bili-video-card__image--wrap picture > * {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
display: block !important;
box-sizing: border-box !important;
}
body.bili-home-page .bili-video-card__info,
body.bili-home-page .bili-live-card__info,
body.bili-home-page .video-info,
body.bili-search-page .bili-video-card__info,
body.bili-search-page .bili-live-card__info,
body.bili-search-page .video-info,
body.bili-space-page .bili-video-card__details,
body.bili-space-page .bili-video-card__info,
body.bili-space-page .bili-live-card__info {
width: 100% !important;
padding: 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
text-align: center !important;
display: block !important;
height: auto !important;
max-height: none !important;
min-height: 0 !important;
background: transparent !important;
}
body.bili-home-page .bili-video-card__info--tit,
body.bili-home-page .bili-video-card__info--tit a,
body.bili-home-page .bili-video-card h3,
body.bili-home-page .bili-video-card h3 a,
body.bili-home-page .bili-live-card__info--tit,
body.bili-home-page .bili-live-card__info--tit a,
body.bili-search-page .bili-video-card__info--tit,
body.bili-search-page .bili-video-card__info--tit a,
body.bili-search-page .bili-video-card h3,
body.bili-search-page .bili-video-card h3 a,
body.bili-search-page .bili-live-card__info--tit,
body.bili-search-page .bili-live-card__info--tit a,
body.bili-space-page .bili-video-card__title,
body.bili-space-page .bili-video-card__title > a,
body.bili-space-page .bili-video-card__title .bili-ellipsis,
body.bili-space-page .bili-video-card__info--tit,
body.bili-space-page .bili-video-card__info--tit a {
display: -webkit-box !important;
-webkit-line-clamp: 2 !important;
-webkit-box-orient: vertical !important;
overflow: hidden !important;
text-align: center !important;
font-size: 13px !important;
line-height: 18px !important;
min-height: 36px !important;
max-height: 36px !important;
color: #18191c !important;
font-weight: 500 !important;
margin: 0 !important;
padding: 0 !important;
word-break: break-all !important;
width: 100% !important;
}
body.bili-home-page .bili-video-card__info--bottom,
body.bili-home-page .bili-video-card__info--owner,
body.bili-home-page .bili-video-card__info--stat,
body.bili-search-page .bili-video-card__info--bottom,
body.bili-search-page .bili-video-card__info--owner,
body.bili-search-page .bili-video-card__info--stat,
body.bili-space-page .bili-video-card__info--bottom,
body.bili-space-page .bili-video-card__info--owner,
body.bili-space-page .bili-video-card__stats,
body.bili-space-page .bili-video-card__subtitle,
body.bili-space-page .bili-video-card__date {
display: flex !important;
justify-content: center !important;
align-items: center !important;
text-align: center !important;
width: 100% !important;
margin-top: 4px !important;
margin-left: auto !important;
margin-right: auto !important;
padding: 0 !important;
height: 21px !important;
min-height: 21px !important;
}
/* ---- v132.10:直播卡「UP主名那一行」与综合页对齐 ----
两份探针对比(都是搜索页 · 168x172 两列卡片):
综合页(card top=60)
封面 60 → 155 (95)
info 155 → 232 (77 = pt8 + 61 + pb8)
标题 163 → 199 (36)
UP主行 203 → 224 (21,margin-top 4)
直播页(card top=88)
封面 88 → 183 (95)
info 183 → 257 (75 = pt8 + 59 + pb8)
标题 191 → 227 (36)← 与综合页同为「卡顶 +103」,已对齐
UP主行 231 → 249 (18,站内原生)← 少了 3px
标题那一行两页完全一致(都是卡顶 +103),差的只有下面这行:
· 综合页被上面那条规则钉成了 21px 高 + margin-top 4px
· 直播页的 UP主行没人管,保持站内原生的 18px,
于是整行比综合页矮 3px,卡片底也短了 2px
(wrap 169 vs 172,卡底留 3px 空隙)
修法:给直播卡的 UP主行套上与综合页一致的几何值
(21px 高 + margin-top 4px),
info = 8 + (36+4+21) + 8 = 77,wrap 补到 172。
⚠ v132.09 的翻车点(本版修正):
上一版给这一行写了 width:100% + justify-content:center,
结果名字那一格(--author,站内是 flex:1)被撑满到 136px,
而 text-align:center 又是从 .bili-live-card__info 继承下来的,
于是:
图标 16 → 32 ← 贴在行的最左边
名字 32 → 168 ← 占满剩余,文字在这 136px 里居中
名字文字实际落在 74~126 附近,与图标之间空出一大段,
看起来就是「UP 图标和名字分家了」。
探针实证(bili_probe_2026-09-30_18-30-41):
a.bili-live-card__info--uname [152x21] left=16
svg.bili-live-card__info--uname-icon [16x16] left=16 ← 顶到最左
span.bili-live-card__info--author [136x21] left=32 ← 撑满剩余
修法:这一行改成**收缩到内容宽**(inline-flex),
让「图标 + 名字」作为一个整体、由父级的 text-align:center
整体居中;名字不再 flex:1,而是紧贴图标、左对齐,
超长才省略。图标的原生右间距也别再抹掉。 ---- */
body.bili-home-page .bili-live-card__info--uname,
body.bili-home-page .bili-live-card__info--owner,
body.bili-home-page .bili-live-card__info--bottom,
body.bili-search-page .bili-live-card__info--uname,
body.bili-search-page .bili-live-card__info--owner,
body.bili-search-page .bili-live-card__info--bottom,
body.bili-space-page .bili-live-card__info--uname,
body.bili-space-page .bili-live-card__info--owner,
body.bili-space-page .bili-live-card__info--bottom,
body.bili-home-page .bili-live-card__info--text > *:not(.bili-live-card__info--tit),
body.bili-search-page .bili-live-card__info--text > *:not(.bili-live-card__info--tit),
body.bili-space-page .bili-live-card__info--text > *:not(.bili-live-card__info--tit) {
/* inline-flex:宽度收缩到「图标 + 名字」的实际内容宽,
整体再由父级的 text-align:center 居中 —— 图标不再被
甩到行首,两者始终贴在一起。 */
display: inline-flex !important;
flex-wrap: nowrap !important;
align-items: center !important;
justify-content: center !important;
width: auto !important;
max-width: 100% !important;
min-width: 0 !important;
height: 21px !important;
min-height: 21px !important;
max-height: 21px !important;
margin: 4px auto 0 auto !important;
padding: 0 !important;
line-height: 21px !important;
box-sizing: border-box !important;
}
/* 名字那一格:只占自己内容那么宽,紧跟图标;超长才省略。
⚠ 不写 text-align:center —— 那会让文字在剩余空间里居中,
与图标之间空出一大段,正是"分家"的成因。 */
body.bili-home-page .bili-live-card__info--author,
body.bili-search-page .bili-live-card__info--author,
body.bili-space-page .bili-live-card__info--author,
body.bili-home-page .bili-live-card__info--uname > span,
body.bili-search-page .bili-live-card__info--uname > span,
body.bili-space-page .bili-live-card__info--uname > span {
flex: 0 1 auto !important;
width: auto !important;
max-width: 100% !important;
min-width: 0 !important;
height: 21px !important;
max-height: 21px !important;
margin: 0 !important;
padding: 0 !important;
line-height: 21px !important;
text-align: left !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
/* UP 图标:固定 16x16,保留站内原生的右间距(不再 margin:0 抹平) */
body.bili-home-page .bili-live-card__info--uname-icon,
body.bili-search-page .bili-live-card__info--uname-icon,
body.bili-space-page .bili-live-card__info--uname-icon,
body.bili-home-page .bili-live-card__info--uname > svg,
body.bili-search-page .bili-live-card__info--uname > svg,
body.bili-space-page .bili-live-card__info--uname > svg {
flex: 0 0 auto !important;
width: 16px !important;
height: 16px !important;
min-width: 16px !important;
max-height: none !important;
line-height: normal !important;
flex-shrink: 0 !important;
}
body.bili-home-page .bili-watch-later,
body.bili-home-page [class*="watch-later"],
body.bili-home-page [class*="watchlater"],
body.bili-home-page [class*="add-to-watch-later"],
body.bili-home-page [class*="watch-later-btn"],
body.bili-home-page .bili-video-card__mask,
body.bili-search-page .bili-watch-later,
body.bili-search-page [class*="watch-later"],
body.bili-search-page [class*="watchlater"],
body.bili-search-page [class*="add-to-watch-later"],
body.bili-search-page [class*="watch-later-btn"],
body.bili-search-page .bili-video-card__mask,
body.bili-space-page .bili-card-watch-later,
body.bili-space-page .bili-video-card .bili-watch-later,
body.bili-space-page .bili-video-card [class*="watch-later"] {
display: none !important;
visibility: hidden !important;
}
/* v131.21 投稿页 / 搜索页的卡片外观改为与主页卡片完全一致。
主页和投稿页用的是同一个 .bili-video-card 组件(168x172,
封面 95 + 信息区 77,标题 152x36,副标题 152x21),DOM 尺寸本来就一样,
差的只是这条规则把投稿卡的背景/圆角/阴影全清掉了,看起来比主页卡"素"。
这里只保留 border:none(v131.6 要去掉的投稿卡文字框边框),
背景、圆角、阴影统统交还给原生 -> 与主页同源、必然一致。
搜索页的卡片同样包在 .upload-video-card 里,一并生效。 */
body.bili-space-page .upload-video-card .bili-video-card,
body.bili-space-page .upload-video-card .bili-video-card__wrap {
border: none !important;
overflow: hidden !important;
}
/* ============================================================
v131.13 UP主主页三处调整
============================================================ */
/* ---------- 1) 隐藏「收藏夹 ·N」整块 ----------
结构:section.home-section > .section-wrap.fav-section
> .section-wrap__header + .section-wrap__content
> .fav-section__content > .items
用 :has() 把外层 section 一并收掉,避免留下空壳占位。 */
/* ---------- 1c) 隐藏「最近点赞的视频」整块(v131.22)----------
探针实测(洛克宅桑主页):
section.home-section:nth-of-type(8) > .section-wrap.like-section[344x964]
> .section-wrap__header(标题「最近点赞的视频」)
> .section-wrap__content > .like-section__content[344x890] > .items
用 :has() 连带外层 section,避免只收内层留下空壳。 */
body.bili-space-page .route_home .section-wrap.like-section,
body.bili-space-page .route_home .like-section__content,
body.bili-space-page .route_home .home-section:has(> .section-wrap.like-section) {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* ---------- 1b) 隐藏「订阅追番 ·N」整块(v131.21)----------
与收藏夹同一套路:按区块类名收掉,并用 :has() 连带外层 section。
站内这一块的类名在 bangumi / sub / follow 之间换过,
这里三种写法都写上,任一命中即隐藏。 */
body.bili-space-page .route_home .section-wrap.bangumi-section,
body.bili-space-page .route_home .bangumi-section__content,
body.bili-space-page .route_home .section-wrap.sub-section,
body.bili-space-page .route_home .sub-section__content,
body.bili-space-page .route_home .section-wrap.follow-section,
body.bili-space-page .route_home .follow-section__content,
body.bili-space-page .route_home .home-section:has(> .section-wrap.bangumi-section),
body.bili-space-page .route_home .home-section:has(> .section-wrap.sub-section),
body.bili-space-page .route_home .home-section:has(> .section-wrap.follow-section) {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
overflow: hidden !important;
}
body.bili-space-page .route_home .section-wrap.fav-section,
body.bili-space-page .route_home .fav-section__content,
body.bili-space-page .route_home .home-section:has(> .section-wrap.fav-section) {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
overflow: hidden !important;
}
/* ---------- 2) 专栏卡片 -> 与视频卡片完全一致 ----------
视频卡实测:168x172 = 封面 95(16:9) + 信息区 77
信息区 = padding8 + 标题36(13px/18px 两行) + 间距4 + 副标题21 + padding8
专栏卡原为 168x166(封面 95 + 底部 61,标题 15px/22.5px 三行),
这里把外框/圆角/阴影/字号行高全部对齐视频卡,并把信息区锁成 77px,
保证两列网格里两种卡片等高、标题基线一致。 */
body.bili-space-page .route_home .article-section .article-list {
margin-top: 20px !important;
}
body.bili-space-page .article-card {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 172px !important;
max-height: 172px !important;
min-height: 172px !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
display: block !important;
position: relative !important;
float: none !important;
background: #ffffff !important;
border: none !important;
border-radius: 8px !important;
box-shadow: 0 1px 3px rgba(0,0,0,0.08) !important;
overflow: hidden !important;
}
/* 封面区:原生是用 padding-top 比例盒(或定高 95px)撑开、
封面
绝对定位铺满的。上一版在这里写了
height:auto + padding:0,把比例盒清零 -> 封面塌成 0 高,
文字就顶到了卡片最上面。这里只改外观,不再碰 height/padding,
比例交给原生(168x95 本身就是 16:9)。 */
body.bili-space-page .article-card__top {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
/* 兜底:高度算不出来时用 16:9 撑开(定高或比例盒在时不起作用) */
aspect-ratio: 16 / 9 !important;
position: relative !important;
float: none !important;
border: none !important;
border-radius: 8px 8px 0 0 !important;
overflow: hidden !important;
background: transparent !important;
}
body.bili-space-page .article-card__cover {
display: block !important;
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
border: none !important;
border-radius: 8px 8px 0 0 !important;
overflow: hidden !important;
background: transparent !important;
}
/* 缩略图兜底:万一原生高度没算出来,用 16:9 撑住,
图片铺满并按 cover 裁切,保证任何情况下都有封面 */
body.bili-space-page .article-card__top > .article-card__cover,
body.bili-space-page .article-card__top .bili-cover-card__thumbnail {
position: absolute !important;
inset: 0 !important;
width: 100% !important;
height: 100% !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .article-card__top img,
body.bili-space-page .article-card__cover img,
body.bili-space-page .article-card__top .b-img__inner {
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
object-fit: cover !important;
display: block !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
border-radius: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .article-card__bottom {
width: 100% !important;
height: 77px !important;
min-height: 77px !important;
max-height: 77px !important;
margin: 0 !important;
padding: 8px !important;
box-sizing: border-box !important;
background: transparent !important;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-items: stretch !important;
text-align: center !important;
overflow: hidden !important;
}
body.bili-space-page .article-card__bottom .title {
display: -webkit-box !important;
-webkit-line-clamp: 2 !important;
-webkit-box-orient: vertical !important;
overflow: hidden !important;
text-align: center !important;
width: 100% !important;
font-size: 13px !important;
line-height: 18px !important;
min-height: 36px !important;
max-height: 36px !important;
color: #18191c !important;
font-weight: 500 !important;
margin: 0 !important;
padding: 0 !important;
word-break: break-all !important;
text-decoration: none !important;
}
/* 标题内层再套了一层 .vui_ellipsis.multi-mode,
让它退化为普通内联文本,避免两层 clamp 叠出额外高度 */
body.bili-space-page .article-card__bottom .title > * {
display: inline !important;
font-size: 13px !important;
line-height: 18px !important;
color: #18191c !important;
font-weight: 500 !important;
-webkit-line-clamp: unset !important;
-webkit-box-orient: unset !important;
min-height: 0 !important;
max-height: none !important;
margin: 0 !important;
padding: 0 !important;
text-align: center !important;
white-space: normal !important;
}
/* ---------- 3) 顶部 tab 蓝色位置条:改为跟随选中项自身定位 ----------
原因:脚本用 fixSpaceNavTabs() 把「收藏夹/订阅」等 tab 设为 display:none,
站内那条蓝色条是按 tab 序号/旧布局算出来的绝对定位元素,
隐藏若干 tab 后算出的 left 就对不上了(每次刷新还不一定一样)。
做法:隐藏所有非 的兄弟节点(即那条 JS 定位的滑动条),
改由选中项自身的 ::after 画线,位置永远等于该项实际位置。 */
body.bili-space-page .nav-tab {
position: relative !important;
}
body.bili-space-page .nav-tab > *:not(a) {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
body.bili-space-page .nav-tab::before,
body.bili-space-page .nav-tab::after,
body.bili-space-page .nav-tab > a.nav-tab__item::before {
content: none !important;
display: none !important;
}
body.bili-space-page .nav-tab > a.nav-tab__item {
position: relative !important;
}
body.bili-space-page .nav-tab > a.nav-tab__item::after {
content: '' !important;
display: block !important;
position: absolute !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: auto !important;
min-width: 0 !important;
height: 3px !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
border-radius: 2px !important;
transform: none !important;
transition: none !important;
background: transparent !important;
}
body.bili-space-page .nav-tab > a.nav-tab__item.active::after,
body.bili-space-page .nav-tab > a.nav-tab__item.router-link-exact-active::after {
background: #00aeec !important;
}
body.bili-space-page .nav-tab > a.nav-tab__item.active,
body.bili-space-page .nav-tab > a.nav-tab__item.router-link-exact-active {
color: #00aeec !important;
}
/* ---------- 4a) 投稿 → 图文:筛选栏「全部图文 / 专栏 / 动态」上下间距 8px ----------
v131.42 结构(探针 09-27_18-12-07 实测,route_uploadOpus):
.upload-content[360x2422](脚本设的 padding: 0 8px 16px)
> .opus[344x2406]
> .opus-header[344x34](全部图文 专栏 动态)
> .opus-header__top[344x34] > .content-filter
> .content-tab(.active = 全部图文 / 专栏 / 动态)
> .opus-body[344x2222] > .opus-feed > .masonry_grid_v2
目标(与卡片间距 8px 一致):
① 胶囊栏「视频 图文 音频」底 → 筛选栏顶 = 8
= upload-sidenav 自带的 padding-bottom 8
+ .opus / .opus-header 的 margin-top 归零
② 筛选栏底 → 卡片顶 = 8
= .opus-header margin-bottom 8 + .opus-body margin-top 归零
站内原生在 header 与 body 之间留了很大空档(旧探针里
.opus 2406 − header 34 − body 2222 = 150),这里一并归零。
------------------------------------------------------------ */
body.bili-space-page .opus {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
/* v131.43 修正下边距:v131.42 把 .opus-header 和它的子元素
.opus-header__top 都设了 margin-bottom: 8px,父子两层嵌套叠加
-> 实际间距 16px。这里只保留外层 .opus-header 一个 8,
内层 __top 的 margin 全部归零。 */
/* v131.44 下边距仍偏高 -> 说明 margin 不是唯一来源。
既然 header 内部可能还挂着别的子节点(或站内给它留了固有高度),
这里不再猜内容,直接把「筛选栏这一行的可见高度」锁死为 34px
(探针实测筛选胶囊就是 34 高)+ overflow:hidden 裁掉多余,
下方间距就恒等于 margin-bottom 8px,与内容多寡无关。 */
body.bili-space-page .opus-header {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 34px !important;
min-height: 34px !important;
max-height: 34px !important;
margin: 0 0 8px 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
body.bili-space-page .opus-header__top {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 34px !important;
min-height: 34px !important;
max-height: 34px !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
/* v131.46 筛选栏整行居中(纯 CSS,不用 JS 量宽度)。
探针 09-28_17-02-40 实测:.content-filter[344x34] 内三个
.content-tab 分别 130 / 82 / 48,gap 8 -> 内容总宽 276,
右侧空 68,故为左对齐(left 依次 8 / 146 / 236)。
只加 justify-content:center 即可让 276 在 344 内左右各留 34,
不动 tab 自身宽度 / padding / flex,避免连带改变胶囊外观。 */
body.bili-space-page .content-filter {
display: flex !important;
flex-direction: row !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 34px !important;
min-height: 34px !important;
max-height: 34px !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
body.bili-space-page .content-tab {
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
/* v131.46 兜底:沿用 v131.36 的思路,把完整链路写进选择器抬高特异性,
防止站内晚加载的同权重 !important 规则把居中顶掉。 */
body.bili-space-page main.space-main .upload-content .opus
> .opus-header > .opus-header__top > .content-filter {
justify-content: center !important;
}
/* ---------- 4a-2) 投稿 → 图文:筛选栏竖条居中 + 文字缩小 ----------
v131.47 探针 09-28_17-15-03 实测(居中已生效):
.content-filter[344x34](justify-content:center 生效)
> .content-tab[130x24] left=42 全部图文
> .content-tab.active[82x24] left=180 专栏
> .content-tab[48x24] left=270 动态
竖条在探针里查不到——探针只遍历真实元素,竖条是 .content-tab 的
伪元素。但宽度把它暴露了:「动态」是最后一个胶囊、身后没有竖条,
48 = 2 字 + 左右内边距;「专栏」2 字却占 82,「全部图文」4 字占 130,
两者都比纯文字多出约 34px。这 34px 就是**在文档流里**的竖条
(约 1px 线 + 左右各 16px 外边距),它长在胶囊内部右侧。
于是「文字 → 竖条」只有 16,而「竖条 → 下一个胶囊的文字」是
16 + 我们设的 gap 8 + 对方内边距 —— 竖条自然偏向左边那个按键,
这正是用户看到的不平分。
解法(依旧纯 CSS):
① 先把站内挂在 ::before / ::after 上的竖条全部停掉,
让胶囊宽度回归纯文字宽度;
② 竖条由我们自己用 ::after 重画,position:absolute +
left:100% + margin-left:3.5px —— 即落在 8px 间隙的正中
((8 − 1) / 2 = 3.5),与左右两个按键严格等距;
③ 字号 14 → 12,行高锁 24 保持胶囊高度与垂直居中不变。
绝对定位的竖条不占文档流,所以 gap 就是纯粹的文字间距,
整行仍由 .content-filter 的 justify-content:center 居中。
------------------------------------------------------------ */
body.bili-space-page .content-filter > .content-tab {
position: relative !important;
height: 24px !important;
min-height: 24px !important;
max-height: 24px !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
box-sizing: border-box !important;
font-size: 12px !important;
line-height: 24px !important;
flex: 0 0 auto !important;
}
/* ① 停掉站内自绘的竖条(两个伪元素都清,避免漏网或重复) */
body.bili-space-page .content-filter > .content-tab::before {
display: none !important;
content: none !important;
}
body.bili-space-page .content-filter > .content-tab::after {
display: none !important;
content: none !important;
}
/* ② 我们自己画:只在非最后一个胶囊的右侧、8px 间隙正中 */
body.bili-space-page .content-filter > .content-tab:not(:last-child)::after {
display: block !important;
content: '' !important;
position: absolute !important;
top: 50% !important;
left: 100% !important;
right: auto !important;
width: 1px !important;
height: 10px !important;
margin: 0 0 0 3.5px !important;
padding: 0 !important;
border: none !important;
border-radius: 0 !important;
transform: translateY(-50%) !important;
background: #e5e9ef !important;
}
/* 高特异性兜底:与 v131.36 / v131.46 同一套路,
防站内晚加载的同权重 !important 把上面这组顶掉。 */
body.bili-space-page main.space-main .upload-content .opus
> .opus-header > .opus-header__top > .content-filter > .content-tab {
position: relative !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
font-size: 12px !important;
line-height: 24px !important;
}
/* v131.43:下游这一串的上边距全部归零,
下边距只由 .opus-header 那一个 8px 提供,避免任何一处再叠加。 */
body.bili-space-page .opus-body {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .opus-body .opus-feed,
body.bili-space-page .opus-body .opus-feed .masonry_grid_v2,
body.bili-space-page .opus-body .opus-feed .masonry_grid_v2 > .container,
body.bili-space-page .opus-body .opus-feed .masonry_grid_v2 > .container > .item {
margin-top: 0 !important;
padding-top: 0 !important;
min-height: 0 !important;
box-sizing: border-box !important;
}
/* v131.44 兜底:瀑布流是 JS 布局,站内常给容器留 min-height /
给首个 item 写 transform 偏移。这里把首行之前的一切偏移清掉。 */
body.bili-space-page .opus-body .opus-feed .masonry_grid_v2 > .container > .item:first-child,
body.bili-space-page .opus-body .opus-feed .masonry_grid_v2 > .container > .item:nth-of-type(1) {
margin-top: 0 !important;
padding-top: 0 !important;
transform: none !important;
translate: none !important;
}
/* ---------- 4) 投稿 → 图文:瀑布流改两列网格,卡片对齐主页专栏卡 ----------
结构:.opus-feed > .masonry_grid_v2 > .container[814 宽,JS 瀑布流]
> .item(绝对定位 + transform) > .opus-card > .opus-card--with-cover
> [a.opus-card__cover(缩略图 + stats), a.opus-card__title]
原卡 189x187(封面 142 + 标题 46),瀑布流列宽由 JS 算。
(!important 的作者样式优先级高于站内 JS 写在 style 属性里的普通声明,
所以 transform / position / width 都能直接压住。) */
/* 外层只做"满宽容器",绝不能再设成网格:
一旦 .masonry_grid_v2 也是两列网格,它唯一的子元素 .container
就会变成占一列的网格项,宽度掉到 (344-8)/2 = 168,
卡片再被挤成 80x172,整块内容就都堆在屏幕左半边了。 */
body.bili-space-page .opus-feed .masonry_grid_v2 {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
position: static !important;
overflow: visible !important;
}
body.bili-space-page .opus-feed .masonry_grid_v2 > .container {
display: grid !important;
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
grid-auto-rows: auto !important;
gap: 8px !important;
row-gap: 8px !important;
column-gap: 8px !important;
align-items: start !important;
align-content: start !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
position: static !important;
overflow: visible !important;
list-style: none !important;
}
body.bili-space-page .opus-feed .masonry_grid_v2 > .container > .item {
position: static !important;
transform: none !important;
translate: none !important;
left: auto !important;
top: auto !important;
right: auto !important;
bottom: auto !important;
inset: auto !important;
width: auto !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
float: none !important;
}
/* 卡片本体:与主页专栏卡同一套外观(白底 / 8px 圆角 / 同一条阴影 / 172 高) */
body.bili-space-page .opus-card,
body.bili-space-page .opus-card--with-cover {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 172px !important;
min-height: 172px !important;
max-height: 172px !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
display: block !important;
position: relative !important;
float: none !important;
background: #ffffff !important;
border: none !important;
border-radius: 8px !important;
box-shadow: 0 1px 3px rgba(0,0,0,0.08) !important;
overflow: hidden !important;
}
body.bili-space-page .opus-card__cover {
display: block !important;
position: relative !important;
float: none !important;
width: 100% !important;
max-width: 100% !important;
height: 95px !important;
min-height: 95px !important;
max-height: 95px !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
border: none !important;
border-radius: 8px 8px 0 0 !important;
overflow: hidden !important;
background: transparent !important;
}
body.bili-space-page .opus-card__cover > .bili-cover-card__thumbnail,
body.bili-space-page .opus-card__cover > a.bili-cover-card__thumbnail {
position: absolute !important;
inset: 0 !important;
width: 100% !important;
height: 100% !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body.bili-space-page .opus-card__cover img,
body.bili-space-page .opus-card__cover .b-img__inner {
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
object-fit: cover !important;
display: block !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
border-radius: 0 !important;
box-sizing: border-box !important;
}
/* 标题区:高度仍是 77px(= 卡片 172 − 封面 95),但内部不再留白。
v131.48 探针 09-28_17-02-40 实测:
a.opus-card__title[168x77](pt 8 / pb 8,overflow hidden)
> div.vui_ellipsis.multi-mode[152x36] ← 只有这一个子节点
关键差异:别的页面卡片(主页 / 投稿视频 / 专栏)标题下方还有一行
日期·播放量之类的元信息,所以 77px 里必须给那行留位置;
而图文卡的标题盒里**只有文字**,没有任何元信息行,
旧规则照抄 77px 结构 + 2 行截断,就白扔掉了
77 − 8×2 − 36 = 25px 的空白。
可用文字高度 = 77 − 上下 padding 8×2 = 61px:
2 行 × 18 = 36(旧,浪费 25)
3 行 × 20 = 60(新,只剩 1px 余量,几乎填满)
4 行 × 18 = 72 > 61(放不下,会被 overflow 裁掉半行)
所以取 3 行,并把行高从 18 提到 20 —— 字号仍是 13px 不变,
多出的 2px 行距既补足高度,也让三行不至于挤在一起。 */
body.bili-space-page .opus-card__title {
display: block !important;
width: 100% !important;
max-width: 100% !important;
height: 77px !important;
min-height: 77px !important;
max-height: 77px !important;
padding: 8px !important;
margin: 0 !important;
box-sizing: border-box !important;
text-align: center !important;
text-decoration: none !important;
background: transparent !important;
overflow: hidden !important;
}
body.bili-space-page .opus-card__title > * {
display: -webkit-box !important;
-webkit-line-clamp: 3 !important;
line-clamp: 3 !important;
-webkit-box-orient: vertical !important;
overflow: hidden !important;
text-align: center !important;
width: 100% !important;
font-size: 13px !important;
line-height: 20px !important;
min-height: 60px !important;
max-height: 60px !important;
color: #18191c !important;
font-weight: 500 !important;
margin: 0 !important;
padding: 0 !important;
word-break: break-all !important;
white-space: normal !important;
}
/* v131.48 兜底:站内 .vui_ellipsis.multi-mode 自己带一套
line-clamp / max-height(探针里它被压成 152x36 就是这套在起作用),
用完整链路抬特异性,确保 3 行 / 60px 压得住。 */
body.bili-space-page .opus-card .opus-card--with-cover
> a.opus-card__title > .vui_ellipsis.multi-mode {
display: -webkit-box !important;
-webkit-line-clamp: 3 !important;
line-clamp: 3 !important;
-webkit-box-orient: vertical !important;
overflow: hidden !important;
width: 100% !important;
max-width: 100% !important;
height: 60px !important;
min-height: 60px !important;
max-height: 60px !important;
font-size: 13px !important;
line-height: 20px !important;
text-align: center !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
word-break: break-all !important;
white-space: normal !important;
text-overflow: ellipsis !important;
}
/* ---------- 4a-3) 投稿 → 图文 → 专栏:隐藏封面底部的播放量浮层 ----------
v131.52 探针 09-28_18-44-13 实测(route_uploadOpus,专栏 tab):
.opus-collection[344x209] mb=30
> .opus-collection-wrap[344x208]
> .opus-collection-list[344x208] pb=30 ← 一行 5 张
> .upload-opus-collection-card[51x178] ×5
> .upload-opus-collection-card__top[51x68]
> a.upload-opus-collection-card__cover[51x68]
(pt=68.4062px,用 padding 撑封面比例)
> .bili-cover-card__thumbnail[51x68](absolute)
> **.bili-cover-card__stats[51x34]**
(absolute z=2,pt=14 pb=4,top=230→264)
text = 30万 1篇专栏 / 111.7万 4篇专栏 …
> .upload-opus-collection-card__bottom[51x74]
(a.title[51x44] + .subtitle[51x26])
用户要去掉的「眼睛图标 30万 / 眼睛图标 111.7万」就是
.bili-cover-card__stats 这层浮在封面底部的半透明条。
⚠ 一个硬限制:探针显示 .bili-cover-card__stats **没有任何子元素**,
「30万」和「1篇专栏」是同一个 div 里的两串文本节点
(眼睛图标走伪元素 / 图标字体),CSS 能选到的最小粒度就是这个
div 整体 —— 没法只挑出播放量那一串而留下「N篇专栏」。
所以这里整层 display:none,「N篇专栏」会一并消失。
真要只留「N篇专栏」,就只能上 JS 遍历文本节点,与"尽量用 CSS"相悖。
封面本体不受影响:比例是靠 a 上的 padding-top:68.4062px 撑的,
与 stats 无绝对定位依赖,隐藏后封面不会塌陷。
作用域严格锁在 .upload-opus-collection-card 内 ——
全部图文 tab 的 .opus-card 封面同样挂着 .bili-cover-card__stats
(显示 379 / 420 之类播放量),那处用户没要求动,绝不能误伤。
------------------------------------------------------------ */
body.bili-space-page .opus-collection-list
.upload-opus-collection-card .bili-cover-card__stats {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
}
body.bili-space-page .upload-opus-collection-card__cover
> .bili-cover-card__stats {
display: none !important;
}
/* 高特异性兜底(v131.36 套路):完整链路压过去,
防站内晚加载的同权重 !important 把浮层放回来。 */
body.bili-space-page main.space-main.route_uploadOpus .opus-collection
> .opus-collection-wrap > .opus-collection-list
> .upload-opus-collection-card > .upload-opus-collection-card__top
> a.upload-opus-collection-card__cover > .bili-cover-card__stats {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
}
/* ---------- 4a-4) 投稿 → 图文 → 专栏:5 卡一行的间距统一 8px ----------
v131.53 探针 09-28_18-44-13 实测(route_uploadOpus,专栏 tab):
.opus-collection[344x209] left=8 mb=30
> .opus-collection-wrap[344x208] left=8
> .opus-collection-list[344x208] left=8 pb=30
> .upload-opus-collection-card[51x178] ×5
5 张卡的实测 left 与宽度:
①left=8 ②left=81 ③left=154 ④left=228 ⑤left=301,每张 w=51
由此反推现状:
卡间间隙 = 81-59=22 / 154-132=22 / 228-205=23 / 301-279=22
末卡右边 = 301+51 = 352 = 容器右边(8+344)
5×51 + (22+22+23+22) = 255 + 89 = 344 ✓ 正好占满
即:**左右边距本来就是 8px**(首卡 left=8 距屏幕左边 8,
末卡右边 352 距屏幕右边 360-352 = 8),需要改的只有卡间间隙。
22/22/23/22 这种"余数摊不平"的分布,是 flex + space-between
把 344-255=89 的剩余空间平分给 4 个间隙的结果(89/4=22.25)。
改法:不跟站内的定宽 + space-between 纠缠,直接把容器改成
5 等分网格 + gap 8,卡片宽度交还给网格(width:100% 填满列):
列宽 = (344 - 4×8) / 5 = 312 / 5 = 62.4px
卡间 = 8px 恒定,不再有 22/23 的抖动
首末 = 8px(网格铺满 344,与容器 padding 一致)→ 距屏幕边缘仍 8px ✓
用 grid 而非 flex 的原因:62.4 是小数,flex 定宽要写 calc 且
仍可能因舍入差 1px;grid 的 1fr 由浏览器精确分配,天然铺满。
注意保留 .opus-collection-list 自带的 padding-bottom:30
(那是这一行到下方内容的纵向间距,不在本次需求内),
所以只写 grid / gap / width,不碰 padding 与 margin。
------------------------------------------------------------ */
body.bili-space-page .opus-collection-list {
display: grid !important;
grid-template-columns: repeat(5, minmax(0, 1fr)) !important;
grid-auto-rows: auto !important;
grid-auto-flow: row !important;
gap: 8px !important;
row-gap: 8px !important;
column-gap: 8px !important;
justify-content: stretch !important;
justify-items: stretch !important;
align-items: start !important;
align-content: start !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
float: none !important;
}
/* 卡片宽度交还网格:站内那套 51px 定宽必须让位,
否则 5×51 + 4×8 = 287 < 344,右边会空出 57px,
"末卡距屏幕右边 8px"就不成立了。 */
body.bili-space-page .opus-collection-list > .upload-opus-collection-card {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
float: none !important;
box-sizing: border-box !important;
}
/* 卡内各层同样满宽跟随,否则封面 / 标题仍按 51px 排,
卡片变宽后右侧会留白 */
body.bili-space-page .opus-collection-list .upload-opus-collection-card__top,
body.bili-space-page .opus-collection-list .upload-opus-collection-card__bottom,
body.bili-space-page .opus-collection-list a.upload-opus-collection-card__cover,
body.bili-space-page .opus-collection-list .upload-opus-collection-card__bottom > .title,
body.bili-space-page .opus-collection-list .upload-opus-collection-card__bottom > .subtitle,
body.bili-space-page .opus-collection-list .upload-opus-collection-card .vui_ellipsis {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
/* 高特异性兜底(v131.36 套路) */
body.bili-space-page main.space-main.route_uploadOpus .opus-collection
> .opus-collection-wrap > .opus-collection-list {
display: grid !important;
grid-template-columns: repeat(5, minmax(0, 1fr)) !important;
gap: 8px !important;
row-gap: 8px !important;
column-gap: 8px !important;
}
body.bili-space-page main.space-main.route_uploadOpus .opus-collection
> .opus-collection-wrap > .opus-collection-list
> .upload-opus-collection-card {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
}
/* ============================================================
========== 专栏文集页(/read/readlist/rlXXX)头部整块居中 ==========
v131.54 探针 09-29_07-17-17 实测(body.bili-opus-page,360x951):
#app[360x943]
> .container[344x879] left=8 pt=27 pb=30 ← 8..352,本身已居中
> .list[344x822] top=99
> .list-header[344x226] left=8 pt=20 pb=20 mb=10
> **.list-header__right[294x186] left=38** pt=6
> .title[275x36] left=57 「宝可梦剧场版 神速的炎帝与圈圈熊觉醒」
> .up-info[275x42] left=57 mt=13 mb=10
> .up-info__holder[42x42] left=57 (头像 24 + 挂件 42)
> .up-name[89x42] left=103 (.up-name-text 50 + .nameplate 25)
> button.follow-btn.on[49x24] left=206 「已关注」
> .desc[275x30] left=57 mb=12
> div[30x30] left=57 「4篇专栏」
> div[38x30] left=97 「7591个字」
> div[57x30] left=145 「1117550次阅读」
> div[50x30] left=212 「2023-11-26更新」
> div[50x30] left=272 「文集号:771595」
> .list-content[344x586]
不居中的根因:这一栏是 PC 版的「左封面 + 右信息」两栏布局。
左侧封面位在手机站没渲染出来(探针里查不到 .list-header__left),
但它的占位还在 —— .list-header__right 被推到 left=38
(距容器左边 30,距右边 352-332 = 20),自身又是 294 定宽,
里面的 .title / .up-info / .desc 全是 275 定宽左对齐,
所以标题、UP 行、5 个统计项统统偏在左半边。
⚠ 还有一处对不上账:.list-header__right 高 186,
pt6 + title36 + up-info(13+42+10) + desc(30+12) = 149,
差 37px 在探针里找不到归属元素 —— 用户报的最后一行
「宝可梦同人剧场版」在整份探针里 grep 也是 0 命中,
这 37px 极可能就是它(探针漏遍历,和上一版 .desc 被漏掉同因)。
所以这里**不逐个点名**,改用 .list-header__right > * 通配,
让探针没列出来的那一行也一并被覆盖到。
改法(三步,纯 CSS):
① .list-header 打散成单列块级,隐藏 PC 的左侧封面占位;
② .list-header__right 满宽 344 + margin auto,回到正中;
③ 右栏每个直接子节点满宽 + text-align:center +
justify-content:center 双通路(块级文本 / flex 行都能命中),
其中 .up-info 的头像+名字+关注按钮、.desc 的 5 个统计项
都是"整组居中",组内相对位置不变。
只写 margin-left/right: auto,**不写 margin 简写**,
以保住 .up-info 的 mt13/mb10 与 .desc 的 mb12 这些纵向节奏。
------------------------------------------------------------ */
/* ⑦ 头部整块(标题 / UP 行 / 统计 / 简介)左右各留 8px(v131.59)
探针 09-29_10-24-31 实测(视口 360):
.container[344x29700] left=8 ← 8..352,容器本身距屏幕已 8px
> .list[344x29643] left=8
> .list-header[344x268] **left=8 宽 344** ← 与容器同宽
> .list-header__right[344x228] left=8
> .title / .up-info / .desc / .introduce 全是 344
即头部内容 344 宽 = 容器 344 宽 -> **距容器左右边距 = 0**,
标题、UP 行、5 个统计项、简介统统顶到容器边上。
改法:.list-header 外框保持 344(仍占 8..352),
只加 padding-left/right: 8px + box-sizing: border-box,
内容盒自然收成 328(占 16..344)—— 距容器左右各 8px。
⚠ 只写 padding-left/right,**不写 padding 简写**,
以保住站内 .list-header 原本的 pt20 / pb20 纵向节奏。
下面的 .list-header__right 与其子节点都是 width:100%,
会自动继承这 328 —— 不需要逐个改数字。
注意:只缩头部。**章节列表 .list-content 仍是 344(8..352)**,
这是 v131.55 为了和全站其它页对齐才去掉的内边距,本轮不动。---- */
body.bili-opus-page .list > .list-header {
display: block !important;
width: 100% !important;
max-width: 100% !important;
padding-left: 8px !important;
padding-right: 8px !important;
box-sizing: border-box !important;
text-align: center !important;
}
/* 高特异性兜底(v131.36 套路):完整链路压过去,
防站内 padding:0 用同权重 !important 顶回来 */
body.bili-opus-page #app > .container > .list > .list-header {
padding-left: 8px !important;
padding-right: 8px !important;
box-sizing: border-box !important;
}
/* PC 版左侧封面位:手机站没渲染内容,但占位把右栏推偏了 30px */
body.bili-opus-page .list > .list-header > .list-header__left {
display: none !important;
width: 0 !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
}
body.bili-opus-page .list > .list-header > .list-header__right {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin-left: auto !important;
margin-right: auto !important;
padding-left: 0 !important;
padding-right: 0 !important;
box-sizing: border-box !important;
float: none !important;
text-align: center !important;
}
/* 右栏每一行:满宽 + 居中(含探针漏掉的那一行) */
body.bili-opus-page .list-header__right > * {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin-left: auto !important;
margin-right: auto !important;
box-sizing: border-box !important;
float: none !important;
text-align: center !important;
justify-content: center !important;
}
/* 5 个统计项:本身按内容宽,只补文字居中;
flex 场景下不许被拉伸,否则"整组居中"会变成"每项等分铺满"
v131.55 修正:这里原来写的 flex: 0 0 auto(禁止收缩)是错的。
探针 09-29_09-04-35 实测后果 —— 5 项各取自然单行宽
67 / 75 / 74 / 59 / 105,合计 380 + 间隙 ≈ 412 > 344,
整行从 left=-34 一直伸到 385,两端都戳出屏幕(视口只有 360)。
改成允许换行:单项仍不收缩(保持一行不断字),
但父容器 .desc 开 flex-wrap,装不下就整项折到第二行。 */
body.bili-opus-page .list-header__right .desc > * {
flex: 0 0 auto !important;
float: none !important;
width: auto !important;
max-width: 100% !important;
height: auto !important;
min-height: 0 !important;
line-height: normal !important;
white-space: nowrap !important;
text-align: center !important;
justify-content: center !important;
}
/* UP 行同理:头像 / 名字 / 关注按钮保持原尺寸,整组居中
v131.57:补 flex-wrap,超长昵称 + 按钮装不下时整组折行,不再溢出屏幕 */
body.bili-opus-page .list-header__right .up-info {
flex-wrap: wrap !important;
row-gap: 6px !important;
column-gap: 4px !important;
}
body.bili-opus-page .list-header__right .up-info > * {
flex: 0 0 auto !important;
}
/* 高特异性兜底(v131.36 套路):完整链路压过去,
防站内 PC 的定宽 294 / 275 用同权重 !important 顶回来 */
body.bili-opus-page #app > .container > .list > .list-header > .list-header__right {
display: block !important;
width: 100% !important;
max-width: 100% !important;
margin-left: auto !important;
margin-right: auto !important;
padding-left: 0 !important;
padding-right: 0 !important;
}
body.bili-opus-page #app > .container > .list > .list-header > .list-header__right
> .title,
body.bili-opus-page #app > .container > .list > .list-header > .list-header__right
> .up-info,
body.bili-opus-page #app > .container > .list > .list-header > .list-header__right
> .desc {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
text-align: center !important;
justify-content: center !important;
}
/* ============================================================
========== 专栏文集页:整页手机化(v131.55) ==========
探针 09-29_09-04-35("含隐藏"全量版,7629 节点,body 360x32219)
逐处实测与对策如下。
------------------------------------------------------------ */
/* ---- ① 头部统计行「233篇专栏 974595个字 5752次阅读 9-16更新 文集号:1018845」
探针实测(v131.54 之后):
.desc[344x10] left=8 mb=12
> div[67x10] left=-34 233篇专栏 ← 已经戳到屏幕外
> div[75x10] left=42 974595个字
> div[74x10] left=127 5752次阅读
> div[59x10] left=211 9-16更新
> div[105x10] left=280 文集号:1018845 ← 右端 385 > 360
5 项自然宽合计 380,加间隙约 412,远超 344,所以两端都溢出。
对策:父容器开 flex-wrap,整项折行(不在词中间断),
两行各自居中。实测会分成 4 项 + 1 项两行。---- */
body.bili-opus-page .list-header__right > .desc {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
justify-content: center !important;
align-items: center !important;
align-content: center !important;
column-gap: 8px !important;
row-gap: 4px !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
overflow: visible !important;
box-sizing: border-box !important;
}
/* ---- ② 文集简介「你我均是不谙世事的幼兽……」默认全文展开 + 去掉展开按键
探针实测:
.introduce[344x38] top=230
> .fold-text[344x19] ovf=hidden ← 只露 1 行(19px)
> .unfold-btn[344x19] text=展开
.fold-text 是"全文已在 DOM 里、靠 overflow:hidden 裁成一行"的
典型折叠组件(高度 19 = 单行),所以纯 CSS 放开高度即可展开全文,
不需要 JS 去点那个按键。
按键用 > *:not(.fold-text) 通配隐藏 —— 展开态它会变成「收起」,
类名可能变,通配才不会被漏掉。---- */
body.bili-opus-page .list-header__right .introduce {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
overflow: visible !important;
box-sizing: border-box !important;
}
body.bili-opus-page .list-header__right .introduce .fold-text {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
overflow: visible !important;
-webkit-line-clamp: unset !important;
line-clamp: unset !important;
text-overflow: clip !important;
white-space: normal !important;
word-break: break-word !important;
overflow-wrap: anywhere !important;
line-height: 1.7 !important;
box-sizing: border-box !important;
}
body.bili-opus-page .list-header__right .introduce > *:not(.fold-text) {
display: none !important;
}
/* 高特异性兜底(v131.36 套路) */
body.bili-opus-page #app > .container > .list > .list-header
> .list-header__right > .introduce > .fold-text {
height: auto !important;
max-height: none !important;
overflow: visible !important;
-webkit-line-clamp: unset !important;
}
/* ---- ③ 章节列表:序号与正文贴死 + 右侧封面整块跑到屏幕外
探针实测(单章):
.list-content[344x31854] left=8 padding 20(左右各 20)
> div[304x31814] left=28
> .list-content-item[304x137] left=28 pt=20
├ .list-content-item-index[13x117] left=28 序号「1」
└ .list-content-item-container[304x117] left=41 ← 304 定宽
├ .__left[304x117] left=41
│ ├ .title[304x29] ovf=hidden
│ │ └ .title-text[79x26](长标题时实测 378 宽,被父级裁掉)
│ ├ .desc[304x22] mt=5 ovf=hidden(章节摘录,1 行)
│ └ .info-bar[304x24] mt=16(分类 / 阅读 / 点赞 / 评论)
└ .__right[117x117] **left=365** ← 视口只有 360,整块在屏幕外
两个硬伤:
a) 序号 13 宽结束于 41,正文正好从 41 起 —— 间隙 = 0,贴死;
b) 13(序号) + 304(正文定宽) = 317 > 304(行宽),整行向右溢出 13,
连带把封面顶到 left=365 屏幕外;封面本身在窄屏也没意义。
对策:
· .list-content 去掉左右 20 内边距 -> 行宽 304 变 344,与头部对齐
(首末距屏幕边缘都是 8px,和全站其它页一致)
· 行改 flex,序号占固定 36px 列并居中(见下方 ⑥),
正文 flex:1 吃掉剩余宽度、min-width:0 允许收缩
· 封面 .__right 直接 display:none(顺带省掉 233 张懒加载图)
· 长标题不再被硬裁:宽度收回 100% + 单行省略号 ---- */
body.bili-opus-page .list > .list-content {
padding-left: 0 !important;
padding-right: 0 !important;
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
}
body.bili-opus-page .list > .list-content > div {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
body.bili-opus-page .list-content-item {
display: flex !important;
flex-direction: row !important;
flex-wrap: nowrap !important;
align-items: flex-start !important;
justify-content: flex-start !important;
/* ⑥ 序号列自带 36px(含与正文的视觉间距),所以行间距归零,
这样正文左边缘恒为 44,不随序号位数变化 */
gap: 0 !important;
column-gap: 0 !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
/* ---- ⑥ 章节序号:两位数以上紧贴左边缘 -> 在剩余宽度内居中(v131.58)
探针 09-29_10-24-31 实测(视口 360,行 left=8 / 行宽 344):
序号 1 位:.list-content-item-index[13x29] left=8 正文 left=44
序号 2 位: [26x29] left=8 正文 left=44
序号 3 位: [39x29] left=8 正文 **left=57**
数字是**全角**字形(13px 字号 -> 每字符 13px 宽):
1 位 13px、2 位 26px、3 位 39px。
原写法 min-width:26 + text-align:right 的后果:
· 2 位数:26px 正好填满 26px 的列,左边距 = 0 -> 紧贴容器左边缘;
· 3 位数:39 > 26,flex 项目被撑宽 13px,
连带把正文从 left=44 顶到 left=57 —— 前 99 章和后面的章节对不齐。
改法(纯 CSS):
· 整行 gap 归零,序号列**锁死 36px**(flex 0 0 36px + min/max 同值),
8 + 36 = 44,正文左边缘在任何位数下都稳定在 44,不再左右跳动;
· 序号 text-align:center,数字在这 36px 里居中,左右自然留出空隙:
1 位 13px -> 两侧各 11.5px
2 位 26px -> 两侧各 5px(原来左侧 0,这就是"紧贴"的根因)
3 位 39px -> 见下
· 3 位数 39px 仍略大于 36px,两道保险把它压进去:
a) font-size 13 -> 12px,全角 3 位降到 36px,刚好装下;
b) 指定西文字体族,数字走半角字形(3 位约 20px),
即使 a) 被站内样式顶回也依然宽松;
两道都命中时也不会显得过小 —— 序号本就是辅助信息,
比正文标题(约 15px)略小才符合层级。
· overflow:visible + white-space:nowrap:极端情况下宁可两侧等宽溢出,
也不让数字被裁掉半截或把正文挤走。---- */
body.bili-opus-page .list-content-item-index {
flex: 0 0 36px !important;
width: 36px !important;
min-width: 36px !important;
max-width: 36px !important;
height: auto !important;
align-self: flex-start !important;
/* 与 .title 的 29px 行高对齐,让序号和章节标题在同一水平线上 */
line-height: 29px !important;
text-align: center !important;
font-size: 12px !important;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif !important;
white-space: nowrap !important;
overflow: visible !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
/* 高特异性兜底(v131.36 套路):完整链路压过去,
防站内的 width:auto / min-width 用同权重 !important 顶回来 */
body.bili-opus-page .list > .list-content .list-content-item
> .list-content-item-index {
flex: 0 0 36px !important;
width: 36px !important;
min-width: 36px !important;
max-width: 36px !important;
text-align: center !important;
font-size: 12px !important;
overflow: visible !important;
}
body.bili-opus-page .list > .list-content .list-content-item {
gap: 0 !important;
column-gap: 0 !important;
}
body.bili-opus-page .list-content-item-container {
flex: 1 1 auto !important;
width: auto !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
body.bili-opus-page .list-content-item-container__left {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
/* 每章右侧封面:按要求整块隐藏(本来就在屏幕外,留着只会撑破行宽) */
body.bili-opus-page .list-content-item-container__right {
display: none !important;
width: 0 !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
}
body.bili-opus-page .list-content .title {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
body.bili-opus-page .list-content .title > .title-text {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
box-sizing: border-box !important;
}
/* 章节摘录:由 1 行放开到 3 行(v131.56)
探针实测 .desc[288x22] ovf=hidden —— 单行 22px 硬裁。
这里改成 -webkit-box + line-clamp:3,配合 height:auto 让第三行露出来,
第 4 行起才省略号截断。 */
body.bili-opus-page .list-content .desc {
display: -webkit-box !important;
-webkit-box-orient: vertical !important;
-webkit-line-clamp: 3 !important;
line-clamp: 3 !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: normal !important;
word-break: break-word !important;
overflow-wrap: anywhere !important;
line-height: 1.5 !important;
height: auto !important;
max-height: none !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
/* 高特异性兜底(v131.36 套路):压过站内同权重 !important 的单行裁切 */
body.bili-opus-page .list > .list-content .list-content-item
.list-content-item-container .list-content-item-container__left > .desc {
display: -webkit-box !important;
-webkit-box-orient: vertical !important;
-webkit-line-clamp: 3 !important;
line-clamp: 3 !important;
overflow: hidden !important;
white-space: normal !important;
height: auto !important;
max-height: none !important;
}
/* 章节统计行「原创连载 / 阅读 / 点赞 / 评论」整行隐藏(v131.56)
探针实测 .info-bar[288x24] mt=16,是 .__left 的最后一个子节点,
display:none 后行高自然收缩,序号与标题的相对位置不受影响。 */
body.bili-opus-page .list-content-item .info-bar,
body.bili-opus-page .list-content .list-content-item
.list-content-item-container__left > .info-bar {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
/* ---- ④ 顶部 #BiliMainHeader:一个 64px 的空壳
探针实测:#BiliMainHeader[344x64] top=8 bottom=72,无文字,
里面唯一的 .bili-header.bili-header--mini.bili-header--fixed
已经被脚本压成 [0x0] (hidden)。
即这 64px 是纯空白,手机站直接收掉,正文上移 64px。---- */
body.bili-opus-page #BiliMainHeader {
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* ---- ⑤ 取消关注确认弹窗「您确认要取消关注吗(゚Д゚≡゚д゚)!? 取消 确定」
整块跑到屏幕右外侧(v131.57)
探针 09-29_10-24-31 实测(视口 360):
.dialog[344x29700] pos=absolute top=8 left=8 ← 蒙层,铺满整页
> .box[360x173] pos=**fixed** z=9999
top=320 **left=144** ← 144+360 = 504,右边 144px 全在屏幕外
> .text[360x23] top=370 left=144
> .buttons[360x40] top=423 left=144
> button.cancel[120x40] left=174
> button.confirm[120x40] left=354 ← 右端 474,戳出屏幕
根因:.box 是 PC 版的定宽 360 弹窗,用固定 left 偏移定位
(144 ≈ 40%×360),在 360 视口下既没居中也没收缩,右半边被裁掉。
改法(纯 CSS,不动任何 JS):
· 蒙层 .dialog 改 fixed + inset:0,跟随视口而不跟着整页滚;
· .box 用 left:50% + translate(-50%,-50%) 做视口正中定位,
同时把定宽 360 换成 max-width: calc(100vw - 16px),
窄屏(如 320)自动再收,永不越界;
· 盒内留左右 16px 内边距,文案与按钮不会贴边;
· .text / .buttons 收回 100% 满宽,跟着新宽度走;
· 两个按钮加 flex-wrap,极端窄屏时上下排列而不是横向溢出。
注:translate 与 left/top 一起写,-50% 以自身尺寸为基准,
站内联样式即使改了 left 也不会破坏居中。---- */
body.bili-opus-page .dialog,
body.bili-space-page .dialog {
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100vw !important;
max-width: 100vw !important;
height: 100vh !important;
max-height: 100vh !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
body.bili-opus-page .dialog > .box,
body.bili-space-page .dialog > .box {
position: fixed !important;
top: 50% !important;
left: 50% !important;
right: auto !important;
bottom: auto !important;
transform: translate(-50%, -50%) !important;
width: 344px !important;
max-width: calc(100vw - 16px) !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
max-height: calc(100vh - 32px) !important;
margin: 0 !important;
padding-left: 16px !important;
padding-right: 16px !important;
box-sizing: border-box !important;
overflow: visible !important;
}
body.bili-opus-page .dialog > .box > .text,
body.bili-space-page .dialog > .box > .text {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
margin-left: 0 !important;
margin-right: 0 !important;
box-sizing: border-box !important;
text-align: center !important;
word-break: break-word !important;
overflow-wrap: anywhere !important;
}
body.bili-opus-page .dialog > .box > .buttons,
body.bili-space-page .dialog > .box > .buttons {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
justify-content: center !important;
align-items: center !important;
gap: 12px !important;
column-gap: 12px !important;
row-gap: 12px !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
box-sizing: border-box !important;
}
body.bili-opus-page .dialog > .box > .buttons > button,
body.bili-space-page .dialog > .box > .buttons > button {
flex: 0 1 120px !important;
width: 120px !important;
max-width: calc(50% - 6px) !important;
min-width: 0 !important;
height: 40px !important;
margin: 0 !important;
box-sizing: border-box !important;
}
/* 高特异性兜底(v131.36 套路):完整链路压过去,
防站内的定宽 360 / 固定 left 用同权重 !important 顶回来 */
body.bili-opus-page #app > .container > .dialog > .box,
body.bili-space-page #app > .container > .dialog > .box {
position: fixed !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
width: 344px !important;
max-width: calc(100vw - 16px) !important;
box-sizing: border-box !important;
}
/* ============================================================
========== 直播间页(live.bilibili.com/房间号) ==========
============================================================
探针 bili_probe_2026-09-30_08-03-19 实测(视口 360):
body.supportWebp
> div.live-room-app[360x4458]
> main.app-content(padding-top 74px)
> div.link-navbar-ctnr (PC 顶部导航, fixed z=1000, h64)
> div.app-body[980x4384]
> section.player-and-aside-area[980x428]
> #player-ctnr[668x428]
> #head-info-vm[668x52] ← 主播信息条
> .fullscreen-container-paddingbox[668x376] (padding-top 375.75px)
> #fullscreen-container (absolute)
> .player-section[668x292] > #live-player-ctnr > #live-player > video
> #gift-control-vm[668x84] ← 礼物栏
> #aside-area-vm (absolute left=680, w300)
> #rank-list-vm[300x96] ← 排行榜
> .chat-history-panel[300x223] ← ★评论区(聊天区)
> #chat-control-panel-vm[300x109] ← 发送框
> #sections-vm[980x3944] ← 动态/公告
> footer.link-footer
> #sidebar-vm (右下角悬浮 实验室/关注)
> #room-background-vm (房间背景图)
目标:整页只剩「播放器」+「评论区」两块,评论区落到播放器正下方。
· 播放器:3px #00aeec 边框 + 12px 圆角 + 左右各 8px + 顶部 36px + 16:9
—— 与番剧页 #bilibili-player-wrap 的数值逐项对齐(同一套 calc 公式)。
· 评论区:#aside-area-vm 由 absolute 改回 static,自然排到 #player-ctnr 之后。
全文纯 CSS,JS 只负责给 body 打上 bili-live-room-page(页面判定)。---- */
html:has(body.bili-live-room-page),
body.bili-live-room-page {
background: #ffffff !important;
width: 100% !important;
max-width: 100vw !important;
min-width: 0 !important;
overflow-x: hidden !important;
padding-top: 0 !important;
margin: 0 !important;
}
/* ---- 1) 除播放器 + 评论区外,其余板块全部隐藏 ---- */
body.bili-live-room-page #room-ssr-vm,
body.bili-live-room-page .link-navbar-ctnr,
body.bili-live-room-page .link-navbar-wrap,
body.bili-live-room-page nav.link-navbar,
body.bili-live-room-page #room-background-vm,
body.bili-live-room-page #head-info-vm,
body.bili-live-room-page #gift-control-vm,
body.bili-live-room-page #rank-list-vm,
body.bili-live-room-page #rank-list-ctnr-box,
body.bili-live-room-page #gift-screen-animation-vm,
body.bili-live-room-page #guard-popup,
body.bili-live-room-page #sections-vm,
body.bili-live-room-page footer.link-footer,
body.bili-live-room-page #sidebar-vm,
/* 播放器内的 PK / 礼物菜单 / 贴纸 / 连麦 等覆盖层 */
body.bili-live-room-page #universal-pk-vm,
body.bili-live-room-page #gift-menu-vm,
body.bili-live-room-page #interactive-sticker-vm,
body.bili-live-room-page #multi-voice-index,
/* v131.95:连麦(语音连线)入口条
探针实测 #link-mic-vm > .lin-mic-entrance [270x40],
浮在播放器正中(top=134,即画面垂直居中偏上),
上面写着「吃西瓜的夏冰 与主播通话中」,直接压在视频画面上。
它挂在 #businessContainerElement / .web-player-inject-wrap 里,
那两层只被设了 pointer-events:none(防挡点击),文字依然可见。
整条挂掉:父 #link-mic-vm + 子 .lin-mic-entrance 双写,
外加同级可能的 .link-mic-* 变体,纯 CSS 隐藏。 */
body.bili-live-room-page #link-mic-vm,
body.bili-live-room-page #link-mic-vm .lin-mic-entrance,
body.bili-live-room-page #link-mic-vm .link-mic-entrance,
body.bili-live-room-page .lin-mic-entrance,
body.bili-live-room-page .link-mic-entrance,
body.bili-live-room-page .web-player-icon-roomStatus {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* 兜底:main 下凡是「不是 .app-body」的一律不显示(导航条 / 页脚 / 未知挂件) */
body.bili-live-room-page main.app-content > *:not(.app-body) {
display: none !important;
visibility: hidden !important;
height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
/* ---- 2) 容器链拉直:980 定宽 -> 满宽,宽屏收窄并居中 ---- */
body.bili-live-room-page main.app-content,
body.bili-live-room-page .app-body,
body.bili-live-room-page section.player-and-aside-area {
width: 100% !important;
max-width: 820px !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
margin: 0 auto !important;
padding: 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
position: relative !important;
float: none !important;
left: auto !important;
right: auto !important;
}
/* ---- 3) 播放器:边框 / 边距 / 比例 与番剧页完全一致 ---- */
body.bili-live-room-page #player-ctnr {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
padding: 0 8px !important; /* 与番剧 .plp-player 一致:左右各 8px */
margin: 36px auto !important; /* 与番剧 .plp-player 一致:上下各 36px */
box-sizing: border-box !important;
overflow: visible !important;
position: relative !important;
float: none !important;
left: auto !important;
right: auto !important;
}
/* 站内 JS 按 PC 宽度算出的 padding-top: 375.75px(= 668 * 9/16)用来撑 16:9,
窄屏下必须顶掉,改由下方 #fullscreen-container 自己定高 */
body.bili-live-room-page .fullscreen-container-paddingbox {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
/* 与番剧页 #bilibili-player-wrap 同一套数值:
宽 100%(含 3px 边框)· 高 (100vw - 22px) * 9/16 + 6px
—— 100vw - 22px = 360 - 16(左右 8px) - 6(左右边框 3px) = 338,即内容区宽 */
body.bili-live-room-page #fullscreen-container {
position: relative !important;
width: 100% !important;
max-width: 100% !important;
height: calc((100vw - 22px) * 9 / 16 + 6px) !important;
max-height: calc((100vw - 22px) * 9 / 16 + 6px) !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 auto !important;
border: 3px solid #00aeec !important;
border-radius: 12px !important;
box-shadow: 0 4px 16px rgba(0, 174, 236, 0.25) !important;
overflow: hidden !important;
box-sizing: border-box !important;
}
/* ★★★ 播放器内部整条链:height:100% 跟随父级,消除次像素缝隙 ★★★
v131.93 重写:旧版用显式 calc 给内层链定高,与外层 calc 产生
两份独立取整,左/底部差出约 1px 缝隙。当时用 scale(1.012) 遮盖,
但会裁掉视频边缘 1~2px 内容。
新版改法(纯 CSS,不裁不拉伸):
内层链统一用 height:100% 跟随 #fullscreen-container 的内容盒,
只有一份取整(外层的 calc),不存在两份独立取整的差值,
视频严格铺满容器内容区,左/底部缝隙彻底消失。
站内 JS 行内 !important 仍会给 .player-section 写错误高度
(容器高 - 礼物栏 84px),CSS 压不过 → 由 JS applyLivePlayerSize
用同样的 100% 行内 !important 顶掉(后写覆盖先写)。
⚠ video 的 transform 必须是 none(不能有 scale),
否则画面会被轻微放大、边缘被 overflow:hidden 裁掉。
⚠ object-fit: contain 保证视频原始比例不变形。 ---- */
/* ★★★ v131.94:直播间「播放器内部下方 84px 空档 / 画面被压扁」根治 ★★★
探针实测(bili_probe_2026-09-30_12-43-30):
#fullscreen-container [344x196](3px 边框 → 内容盒 338x190)
> .player-section [338x106] ← 只有 106,应为 190
106 = 190 - 84 —— 站内 JS 一直按「容器高 - 礼物栏 84px」
给 .player-section 写**行内**几何值(礼物栏早已被隐藏,这 84px
却仍被扣掉),视频被压成扁条、下方空出一条黑边。
行内 !important 样式表压不过(它连 min/max-height 一起写,
所以写 100% 的 min-height 也救不回来),因此不跟它抢属性:
display:contents 让 .player-section 根本不生成盒子 ——
元素一旦不生盒,写在它身上的全部几何声明(height / min-height /
max-height / top / bottom…)无论行内与否一律失效。
#live-player-ctnr 于是直接以 #fullscreen-container 为定位父级,
height:100% = 内容盒 190px,画面满铺、零裁剪、零拉伸,
且只剩外层 calc 一份取整,v131.93 消灭的次像素缝隙不会回归。
(下方内层链规则里的 min-height:100% 与 JS 的
stripPlayerSectionInline 分别作为二、三道保险。) */
body.bili-live-room-page #fullscreen-container .player-section {
display: contents !important;
}
body.bili-live-room-page #fullscreen-container .player-section,
body.bili-live-room-page #live-player-ctnr,
body.bili-live-room-page #live-player-ctnr > .h-100.p-relative,
body.bili-live-room-page #live-player,
body.bili-live-room-page #live-player video {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
min-height: 100% !important;
max-height: 100% !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
border-radius: 0 !important;
transform: none !important;
box-sizing: border-box !important;
}
body.bili-live-room-page #live-player video {
object-fit: contain !important;
background-color: #000 !important;
}
/* 弹幕层:保留,但压回播放器范围内(站内给它加了 15° 旋转 transform,会溢出) */
body.bili-live-room-page #live-player .web-player-danmaku,
body.bili-live-room-page #live-player .danmaku-item-container {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
overflow: hidden !important;
z-index: 10 !important;
}
/* 业务注入层(PK / 礼物菜单 / 贴纸等都挂在它下面)已全部隐藏,
留着会是一张盖在播放器上的透明膜,拦掉播放器的点击,直接放行指针事件 */
body.bili-live-room-page #live-player .web-player-inject-wrap,
body.bili-live-room-page #businessContainerElement {
pointer-events: none !important;
overflow: hidden !important;
}
/* ---- 4) 评论区:从右侧 absolute 挪到播放器正下方 ---- */
body.bili-live-room-page #aside-area-vm {
position: static !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: 0 !important;
padding: 0 8px !important; /* 与播放器左右 8px 对齐 */
margin: 8px auto 0 !important; /* 距播放器 8px */
box-sizing: border-box !important;
overflow: visible !important;
float: none !important;
top: auto !important;
left: auto !important;
right: auto !important;
touch-action: pan-y !important; /* v131.96:纵向手势留给页面滚动 */
}
/* ★★★ v131.97:聊天区「定高 + 内部滚动」,页面不再需要滚动 ★★★
上一版(v131.96)改成 height:auto + overflow:visible 让聊天内容参与
页面排版,结果聊天越滚越长、整页无限往屏幕外延伸,而手指落在聊天区
依然纹丝不动 —— 说明聊天区上有东西把纵向手势吃掉了(站内为聊天区
绑的手势逻辑 / touch-action),页面滚动压根没被触发。
换个思路:既然手势在聊天区里必然被聊天区接管,那就让**聊天区自己
成为一个好用的滚动容器**,同时把它限死在屏内:
· .chat-history-panel 定高 calc(100dvh - 284px)
—— 284px = 顶部 36 + 播放器 196 + 播放器上下 margin 36x2
实测 #aside-area-vm 从 top=268 起算,再留 16px 底边距。
这样「播放器 + 聊天区」总高恒 ≤ 一屏,页面本身不再产生滚动,
聊天内容也就永远不会溢出到屏幕外。想看历史就在聊天区里滑。
· #chat-history-list 恢复 overflow-y:auto,由它承载滚动;
· overscroll-behavior:contain —— 聊天区滑到头不要把整页也拽动,
避免"滑聊天区时页面跟着抽"的连带感;
· transform:none —— 站内平滑滚动会给列表加 translateY,
会把整块内容平移出可视区;
· touch-action:pan-y 覆盖聊天区整棵子树 —— 站内若给其中某层
写了 touch-action:none / 绑了手势,纵向手势会被彻底掐死,
这里逐层强制把纵向手势交还给浏览器。
另配 JS bindLiveChatScroll:钉住列表高度 + 手势兜底。 */
body.bili-live-room-page .chat-history-panel {
width: 100% !important;
max-width: 100% !important;
/* v131.99:284 → 304,多留 36px 底距(面板顶距 268 + 36 = 304) */
height: calc(100vh - 304px) !important;
height: calc(100dvh - 304px) !important;
min-height: 120px !important;
max-height: calc(100vh - 304px) !important;
max-height: calc(100dvh - 304px) !important;
padding: 0 !important;
margin: 0 !important;
background: #f6f7f8 !important;
border-radius: 12px !important;
overflow: hidden !important;
box-sizing: border-box !important;
touch-action: pan-y !important;
overscroll-behavior: contain !important;
}
body.bili-live-room-page #chat-history-list {
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
min-height: 0 !important;
max-height: 100% !important;
padding: 6px 8px !important;
margin: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
overscroll-behavior: contain !important;
-webkit-overflow-scrolling: touch !important;
transform: none !important;
touch-action: pan-y !important;
box-sizing: border-box !important;
}
/* 聊天区整棵子树:纵向手势一律放行,谁也不许掐 */
body.bili-live-room-page #aside-area-vm *,
body.bili-live-room-page .chat-history-panel * {
touch-action: pan-y !important;
}
/* 盖在聊天区上方的浮层直接放行指针事件:
探针实测 .chat-overlay-layer [344x67] absolute z=10 压在聊天区顶部,
#welcome-area-bottom-vm [344x83](带 canvas 欢迎动画)也悬在同一片区域。
手指一落在聊天区上半部分就打在这些浮层上,手势自然传不到列表。 */
body.bili-live-room-page .chat-overlay-layer,
body.bili-live-room-page #welcome-area-bottom-vm,
body.bili-live-room-page #welcome-item-video,
body.bili-live-room-page .chat-overlay-layer *,
body.bili-live-room-page #welcome-area-bottom-vm * {
pointer-events: none !important;
}
body.bili-live-room-page #chat-items,
body.bili-live-room-page .chat-item {
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
overflow-wrap: break-word !important;
word-break: break-word !important;
}
/* ★★★ v131.96:隐藏「发送框」与它上方那一行「XX 进入直播间」★★★
探针实测(bili_probe_2026-09-30_13-41-13)聊天区纵向排布:
#chat-history-list 103 ~ 691
#brush-prompt [344x20] 691 ~ 711 ← 「南城浅忆萧 进入直播间」
#chat-control-panel-vm [344x109] 711 ~ 820 ← 输入区(图标行 + 输入框 + 发送)
手机端只用来看直播/弹幕,这两块纯占位,整条摘掉:
· #chat-control-panel-vm 整块(含 #control-panel-ctnr-box /
.control-panel-icon-row / .chat-input-ctnr / textarea / 发送按钮)
· #brush-prompt(进入直播间提示行,z=19 浮在聊天区与发送框之间) */
body.bili-live-room-page #chat-control-panel-vm,
body.bili-live-room-page #control-panel-ctnr-box,
body.bili-live-room-page .control-panel-icon-row,
body.bili-live-room-page .chat-input-ctnr,
body.bili-live-room-page .chat-input-area,
body.bili-live-room-page #brush-prompt,
body.bili-live-room-page .brush-prompt {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
/* ★★★ v132.00:点聊天内容弹出的「按键面板」不再弹出 ★★★
探针实测(bili_probe_2026-09-30_14-39-43,点击一条弹幕后):
.danmaku-menu.p-fixed.ts-dot-4 [148x212]
position:fixed z=30,挂在 .chat-history-panel 下
内含:用户名 / 去 TA 的个人空间 / @TA / 屏蔽发送者 /
举报选中弹幕 / 航海之旅
手机端这些操作一个都用不上(也点不准),面板还会盖住画面。
纯 CSS 整块隐藏即可;触发源 .open-menu 一并去掉 pointer 样式,
点击不再有"可点"的手型,也不会再有面板冒出来。 */
body.bili-live-room-page .danmaku-menu,
body.bili-live-room-page .danmaku-menu.p-fixed,
body.bili-live-room-page #aside-area-vm .danmaku-menu,
body.bili-live-room-page .chat-history-panel .danmaku-menu {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
pointer-events: none !important;
}
body.bili-live-room-page .chat-history-panel .open-menu,
body.bili-live-room-page .chat-history-panel .pointer {
cursor: default !important;
}
/* ---- 5) 全屏(原生全屏 / 网页全屏):前面所有约束一律让位 ----
v131.85 引出的两个全屏问题,根因都在"把 16:9 尺寸锁死"这件事上:
· 竖屏全屏「顶部没居中 + 左右有边距」
← #player-ctnr 的 margin:36px auto 与 padding:0 8px 把播放器推离顶部、
左右各留 8px,视频贴不到屏幕边缘,也没垂直居中。
· 横屏全屏「上下被裁掉」
← #fullscreen-container 及内层被锁成 calc((100vw - 22px) * 9 / 16),
横屏下 100vw 是**长边**,算出的高度远超屏幕高度,上下直接溢出被裁。
全屏时必须把尺寸控制权完整交回站内。
检测由 JS 完成(原生 fullscreenElement / 站内 class / 尺寸启发式),
命中即给 body 打 bili-live-fs。下面这组选择器多一个类,特异性更高,
能覆盖本页前面写下的全部尺寸约束。
播放器直接 fixed + inset:0 硬贴视口四边:
不再猜站内用的是 fixed 还是 absolute,也不依赖父级链是否 100%,
竖屏横屏都保证「贴边 + 完整」。 */
/* html 单独写一条:不给 定高,body 的 height:100% 无从参照。
刻意不与下面 body 那条合并成选择器列表 —— :has() 一旦不被支持,
整组选择器会被一起丢弃,body 那条也会跟着失效。 */
html:has(body.bili-live-room-page.bili-live-fs) {
width: 100% !important;
height: 100% !important;
max-width: none !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
background: #000 !important;
}
body.bili-live-room-page.bili-live-fs {
width: 100% !important;
height: 100% !important;
max-width: none !important;
min-width: 0 !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
background: #000 !important;
}
body.bili-live-room-page.bili-live-fs .live-room-app,
body.bili-live-room-page.bili-live-fs main.app-content,
body.bili-live-room-page.bili-live-fs .app-body,
body.bili-live-room-page.bili-live-fs section.player-and-aside-area,
body.bili-live-room-page.bili-live-fs #player-ctnr,
body.bili-live-room-page.bili-live-fs .fullscreen-container-paddingbox {
width: 100% !important;
height: 100% !important;
max-width: none !important;
min-width: 0 !important;
max-height: none !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
background: #000 !important;
overflow: hidden !important;
box-sizing: border-box !important;
float: none !important;
transform: none !important;
}
body.bili-live-room-page.bili-live-fs #fullscreen-container {
position: fixed !important;
top: 0 !important;
right: 0 !important;
bottom: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
max-width: none !important;
min-width: 0 !important;
max-height: none !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
background: #000 !important;
overflow: hidden !important;
box-sizing: border-box !important;
z-index: 2147483647 !important;
}
/* 内层链解除 16:9 的 calc 锁,改回跟随父级铺满 */
/* v131.94:同上,原生全屏态也摘掉 .player-section 的盒子
(站内网页全屏同样会扣 84px;这里用 100% 跟满视口) */
body.bili-live-room-page.bili-live-fs #fullscreen-container .player-section {
display: contents !important;
}
body.bili-live-room-page.bili-live-fs #fullscreen-container .player-section,
body.bili-live-room-page.bili-live-fs #live-player-ctnr,
body.bili-live-room-page.bili-live-fs #live-player-ctnr > .h-100.p-relative,
body.bili-live-room-page.bili-live-fs #live-player,
body.bili-live-room-page.bili-live-fs #live-player video,
body.bili-live-room-page.bili-live-fs #live-player .web-player-danmaku,
body.bili-live-room-page.bili-live-fs #live-player .danmaku-item-container {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
max-width: none !important;
max-height: none !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
transform: none !important;
box-sizing: border-box !important;
}
/* contain 保证横屏下画面完整不裁(cover 会填满但切掉上下) */
body.bili-live-room-page.bili-live-fs #live-player video {
object-fit: contain !important;
background-color: #000 !important;
}
/* 全屏时评论区不该再占位 */
body.bili-live-room-page.bili-live-fs #aside-area-vm {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
/* ============================================================
---- 6) v131.89:站内「网页全屏」body.player-full-win 一律
按**普通态**渲染(纯 CSS 兜底) ----
退出原生全屏(双击 / 返回键 / ESC)时,站内播放器会自己补一个
player-full-win —— 也就是「网页全屏」:带浏览器地址栏、底部留
84px 礼物栏空档、播放器被写死 668px 定宽。上一版把它当全屏
处理(isLiveFullscreen 命中即铺满视口),于是双击就在
「原生全屏 ↔ 带地址栏的全屏」之间来回跳,永远退不回普通态。
新规则:这个态我们根本不要,见到就当普通态。
· JS:class 一出现立刻摘掉(bindLiveWebFullscreenGuard)
· CSS:这里兜底 —— 万一它活了几帧,也强制按普通态排版,
不会出现"带地址栏的全屏"
:not(.bili-live-fs) 保证真正的原生全屏不受这组规则影响
(bili-live-fs 只在原生 Fullscreen API 命中时才打)。 ---- */
html:has(body.bili-live-room-page.player-full-win:not(.bili-live-fs)) {
width: 100% !important;
height: auto !important;
max-width: 100vw !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
overflow-x: hidden !important;
background: #ffffff !important;
}
body.bili-live-room-page.player-full-win:not(.bili-live-fs) {
position: static !important;
width: 100% !important;
height: auto !important;
max-width: 100vw !important;
max-height: none !important;
padding-top: 0 !important;
margin: 0 !important;
overflow-x: hidden !important;
background: #ffffff !important;
}
body.bili-live-room-page.player-full-win:not(.bili-live-fs) .live-room-app,
body.bili-live-room-page.player-full-win:not(.bili-live-fs) main.app-content,
body.bili-live-room-page.player-full-win:not(.bili-live-fs) .app-body,
body.bili-live-room-page.player-full-win:not(.bili-live-fs) section.player-and-aside-area {
position: relative !important;
width: 100% !important;
max-width: 820px !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
margin: 0 auto !important;
padding: 0 !important;
overflow: visible !important;
background: #ffffff !important;
box-sizing: border-box !important;
float: none !important;
left: auto !important;
right: auto !important;
top: auto !important;
bottom: auto !important;
}
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #player-ctnr {
position: relative !important;
width: 100% !important;
max-width: 100% !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
padding: 0 8px !important; /* 与普通态一致:左右各 8px */
margin: 36px auto !important; /* 与普通态一致:上下各 36px */
box-sizing: border-box !important;
overflow: visible !important;
left: auto !important;
right: auto !important;
top: auto !important;
bottom: auto !important;
}
/* 网页全屏给 #fullscreen-container 的 668px 定宽 / fixed 定位 / 满屏高
全部顶掉,回到普通态的 16:9 + 3px 边框 + 12px 圆角 */
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #fullscreen-container {
position: relative !important;
top: auto !important;
right: auto !important;
bottom: auto !important;
left: auto !important;
width: 100% !important;
max-width: 100% !important;
height: calc((100vw - 22px) * 9 / 16 + 6px) !important;
min-height: 0 !important;
max-height: calc((100vw - 22px) * 9 / 16 + 6px) !important;
padding: 0 !important;
margin: 0 auto !important;
border: 3px solid #00aeec !important;
border-radius: 12px !important;
box-shadow: 0 4px 16px rgba(0, 174, 236, 0.25) !important;
z-index: auto !important;
background: #000 !important;
box-sizing: border-box !important;
}
/* v131.94:网页全屏(player-full-win)是 84px 空档的重灾区 ——
站内正是为了给礼物栏留位置才扣掉这 84px。按普通态数值顶回。 */
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #fullscreen-container .player-section {
display: contents !important;
}
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #fullscreen-container .player-section,
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #live-player-ctnr,
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #live-player-ctnr > .h-100.p-relative,
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #live-player,
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #live-player video {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
min-height: 100% !important;
max-height: 100% !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
transform: none !important;
box-sizing: border-box !important;
}
/* 评论区:网页全屏会把播放器下的内容全吃掉,这里强制回到播放器正下方 */
body.bili-live-room-page.player-full-win:not(.bili-live-fs) #aside-area-vm {
display: block !important;
visibility: visible !important;
position: static !important;
width: 100% !important;
max-width: 100% !important;
height: auto !important;
min-height: 0 !important;
max-height: none !important;
padding: 0 8px !important;
margin: 8px auto 0 !important;
box-sizing: border-box !important;
overflow: visible !important;
float: none !important;
top: auto !important;
left: auto !important;
right: auto !important;
}
/* ============================================================
---- 7) v131.90:真·原生全屏的纯 CSS 兜底(不依赖任何 JS class)----
:fullscreen 只有原生 Fullscreen API 才会命中;站内自造的"假全屏"
(position:fixed 铺满视口、仍带浏览器地址栏)命中不了。
所以这条规则同时干两件事:
· 原生全屏时铺满视口(与第 5 段的 .bili-live-fs 等价,互为备份)
· 不在原生全屏时绝不生效 —— 假全屏因此永远走普通态排版
刻意写成独立的一条规则,不与其它选择器并列表:
:has() / :fullscreen 万一不被支持,这条被整条丢弃即可,
不会连累同规则里的其它选择器。 ---- */
html:has(body.bili-live-room-page):has(:fullscreen) {
width: 100% !important;
height: 100% !important;
max-width: none !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
background: #000 !important;
}
body.bili-live-room-page:has(:fullscreen) {
width: 100% !important;
height: 100% !important;
max-width: none !important;
min-width: 0 !important;
max-height: none !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
background: #000 !important;
}
body.bili-live-room-page:has(:fullscreen) .live-room-app,
body.bili-live-room-page:has(:fullscreen) main.app-content,
body.bili-live-room-page:has(:fullscreen) .app-body,
body.bili-live-room-page:has(:fullscreen) section.player-and-aside-area,
body.bili-live-room-page:has(:fullscreen) #player-ctnr,
body.bili-live-room-page:has(:fullscreen) .fullscreen-container-paddingbox {
width: 100% !important;
height: 100% !important;
max-width: none !important;
min-width: 0 !important;
max-height: none !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
background: #000 !important;
overflow: hidden !important;
box-sizing: border-box !important;
float: none !important;
transform: none !important;
}
body.bili-live-room-page:has(:fullscreen) #fullscreen-container {
position: fixed !important;
top: 0 !important;
right: 0 !important;
bottom: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
max-width: none !important;
min-width: 0 !important;
max-height: none !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
background: #000 !important;
overflow: hidden !important;
box-sizing: border-box !important;
z-index: 2147483647 !important;
}
/* v131.94::fullscreen 伪类兜底态同样摘掉 .player-section 的盒子 */
body.bili-live-room-page:has(:fullscreen) #fullscreen-container .player-section {
display: contents !important;
}
body.bili-live-room-page:has(:fullscreen) #fullscreen-container .player-section,
body.bili-live-room-page:has(:fullscreen) #live-player-ctnr,
body.bili-live-room-page:has(:fullscreen) #live-player-ctnr > .h-100.p-relative,
body.bili-live-room-page:has(:fullscreen) #live-player,
body.bili-live-room-page:has(:fullscreen) #live-player video,
body.bili-live-room-page:has(:fullscreen) #live-player .web-player-danmaku,
body.bili-live-room-page:has(:fullscreen) #live-player .danmaku-item-container {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
max-width: none !important;
max-height: none !important;
min-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
border-radius: 0 !important;
transform: none !important;
box-sizing: border-box !important;
object-fit: contain !important;
}
body.bili-live-room-page:has(:fullscreen) #aside-area-vm {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
/* ============================================================
---- 8) v131.91:屏蔽播放器「长按」 ----
长按会同时冒出两个东西:
A) 浏览器自己的「选中文字 / 复制分享」浮层
—— 纯 CSS 就能掐掉:touch-callout + user-select 全关。
B) 播放器自带的调试面板(探针实测:
#live-player > ul,z=99,里面是
「画面异常?切换解码策略试试 / 播放器日志信息 /
视频统计信息 / Room Player 3.11.9 / 关闭」)
—— 双击退出全屏时大概率被带出来,挡住画面;
连点还会点中面板里的按键。
CSS 直接隐藏(结构选择器 #live-player > ul 稳定),
JS 另给同类面板打 .bili-live-ctx-menu 兜底(按文本识别)。
pointer-events:none 再加一层保险:就算它真的被触发,
也点不到任何一项。 */
body.bili-live-room-page #fullscreen-container,
body.bili-live-room-page #fullscreen-container .player-section,
body.bili-live-room-page #live-player-ctnr,
body.bili-live-room-page #live-player-ctnr > .h-100.p-relative,
body.bili-live-room-page #live-player,
body.bili-live-room-page #live-player video,
body.bili-live-room-page #live-player .web-player-danmaku,
body.bili-live-room-page #live-player .danmaku-item-container {
-webkit-touch-callout: none !important;
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
body.bili-live-room-page #live-player > ul,
body.bili-live-room-page #fullscreen-container .bili-live-ctx-menu,
body.bili-live-room-page .bili-live-ctx-menu {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
opacity: 0 !important;
pointer-events: none !important;
}
/* ============================================================
---- 9) v131.91:控制栏只留「时间」+「清晰度」,居中 ----
探针 11-21-56 实测(视口 800,单击播放器弹出的那条):
#web-player-controller-wrap-el
> div.live-web-player-controller.svelte-4rgwwa
> div.control-area.svelte-4rgwwa [778x36]
> div.left-area [148x36] 含「47:43」时间
> div.right-area [606x36] 含「自动」清晰度 + 一串图标
窄屏下右侧那排图标挤成一团、显示不全也点不准,全部隐藏;
时间按键与清晰度按键由 JS 按文本识别后打 data-bili-live-keep="1",
这里只做「非标记即隐藏」+ flex 居中 —— 隐藏和排版全在 CSS。 ---- */
body.bili-live-room-page .control-area {
display: flex !important;
flex-direction: row !important;
flex-wrap: nowrap !important;
align-items: center !important;
justify-content: center !important;
width: 100% !important;
max-width: 100% !important;
padding: 0 !important;
}
body.bili-live-room-page .control-area > .left-area,
body.bili-live-room-page .control-area > .right-area,
body.bili-live-room-page .live-web-player-controller > .left-area,
body.bili-live-room-page .live-web-player-controller > .right-area {
display: flex !important;
flex-direction: row !important;
flex-wrap: nowrap !important;
align-items: center !important;
justify-content: center !important;
flex: 0 0 auto !important;
width: auto !important;
min-width: 0 !important;
max-width: none !important;
height: auto !important;
margin: 0 !important;
padding: 0 !important;
float: none !important;
position: static !important;
}
/* 两个区之间留 8px;空的那个区直接不占位(:has 支持时) */
body.bili-live-room-page .control-area > .left-area { margin-right: 8px !important; }
body.bili-live-room-page .control-area > .right-area { margin-left: 0 !important; }
body.bili-live-room-page .control-area > .left-area:not(:has([data-bili-live-keep])),
body.bili-live-room-page .control-area > .right-area:not(:has([data-bili-live-keep])) {
display: none !important;
width: 0 !important;
margin: 0 !important;
overflow: hidden !important;
}
body.bili-live-room-page .control-area .left-area > *:not([data-bili-live-keep]),
body.bili-live-room-page .control-area .right-area > *:not([data-bili-live-keep]) {
display: none !important;
visibility: hidden !important;
width: 0 !important;
min-width: 0 !important;
height: 0 !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
pointer-events: none !important;
}
/* 保留的两个键:居中、字号统一、不再被压缩 */
body.bili-live-room-page .control-area [data-bili-live-keep] {
display: flex !important;
visibility: visible !important;
flex: 0 0 auto !important;
align-items: center !important;
justify-content: center !important;
width: auto !important;
min-width: 0 !important;
max-width: none !important;
height: auto !important;
margin: 0 !important;
padding: 0 4px !important;
opacity: 1 !important;
overflow: visible !important;
}
/* ============================================================
---- 10) v131.92:三处细节 ----
① 播放器右上角 36x36 的「反馈」图标
探针实测:它是 #live-player 的**直接子级** svg#图层_1,
[36x36] top=39 left=301,常年盖在画面右上角。窄屏下用不上,
直接隐藏(控制栏内的图标都在更深的层级里,不受影响)。
② 画面与边框之间约 1px 的露边(v131.93 根治)
根因是「两份取整」:
#fullscreen-container 高 calc((100vw - 22px) * 9 / 16 + 6px) = 196.125px
→ 内容盒 = 196.125 - 6(上下边框) = 190.125px
v131.92 时内层链又各自写了一条
calc((100vw - 22px) * 9 / 16) = 190.125px
两条算式分别取整时,左侧 / 底部会差出不到 1px,
露出容器底色 —— 就是看到的那条细缝。
视频页用的是 height:100%(跟随父级内容盒,只有一份取整),所以没事。
v131.92 用 scale(1.012) 放大视频遮盖缝隙,
但会裁掉视频边缘 1~2px 内容(不符合"不裁剪"要求)。
v131.93 根治:内层链全部改用 height:100% 跟随父级内容盒,
只有一份取整,缝隙彻底消失。站内 JS 行内 !important
写死的错误高度由 applyLivePlayerSize 用 100% 行内 !important 顶掉。
容器底色补 #000 兜底保留。
全屏态由 .bili-live-fs / :has(:fullscreen) 那两组
特异性更高的规则接管,不受本条影响。
③ 画质面板(.quality-wrap .panel)
探针「点击自动按键后」实测:
.panel [160x236],transform: matrix(1,0,0,1,-80,-238)
→ 相对按钮向上弹 238px,最终落在 top=-148 ~ bottom=88,
比按钮(top=190)高出一百多像素。
普通态 / 横屏下它整个跑到可视区外面被裁,只有竖屏全屏
(屏高够)才显示得全。改成视口居中 + 限高可滚动,
任何尺寸、任何朝向都完整可见。 ---- */
/* ① 隐藏「反馈」图标 */
body.bili-live-room-page #live-player > svg,
body.bili-live-room-page #live-player > svg[id],
body.bili-live-room-page #live-player > [class*="feedback"],
body.bili-live-room-page #live-player [class*="feedback"],
body.bili-live-room-page #live-player [class*="FeedBack"] {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-width: 0 !important;
min-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
pointer-events: none !important;
}
/* ② v131.93:次像素缝隙已由内层链 height:100% 根治(见第 3 段),
不再需要 scale 放大。video 的 transform 保持 none(上面已写),
画面不被裁剪也不被拉伸。容器底色补黑兜底仍保留。 */
body.bili-live-room-page #fullscreen-container {
background: #000 !important;
}
/* ③ 画质面板:视口居中 + 限高可滚动 */
body.bili-live-room-page .quality-wrap .panel,
body.bili-live-room-page .control-area .panel {
position: fixed !important;
top: 50% !important;
right: auto !important;
bottom: auto !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
width: 160px !important;
max-width: 200px !important;
min-width: 0 !important;
height: auto !important;
max-height: calc(100vh - 32px) !important;
margin: 0 !important;
border-radius: 10px !important;
overflow-x: hidden !important;
overflow-y: auto !important;
-webkit-overflow-scrolling: touch !important;
z-index: 2147483000 !important;
}
/* ============================================================
---- 11) v132.05:弃用站内遮罩层,自建渐变遮罩 ----
【目标】按键贴播放器底、遮罩从底部连续铺上来,
同时**绝不破坏站内自己的"点击收起 / 延时自动隐藏"**。
【v132.01 / v132.02 为什么把自动隐藏改坏了 —— 复盘】
站内控制栏的唤出/收起,动画走的是控制栏自身的
transform(translateY 滑入滑出),配合高度/透明度。
而那两版给控制栏整条链写了:
· height:100% / inset:0 ← 顶掉站内"收起"时的高度
· transform: none !important ← 顶掉站内的滑出动画
结果:站内以为自己收起了,节点却仍铺在画面上 ——
表现出来就是"弹出来就不隐藏,点屏幕也没反应"。
这两类属性(height / transform / inset)是站内的
**状态通道**,外部一律不许碰。
【v132.04 的遮罩为什么会在 84px 处闪一下】
站内遮罩层 .web-player-controller-bg 是
height:56px + bottom:84px(礼物栏让位的残留)
唤出瞬间它先在 84px 处渲染出来,我们的 JS 要等到
下一拍(MutationObserver 30ms / 轮询 250ms)才把
margin 补偿写上去 —— 这一拍的错位就是肉眼看到的"闪一下"。
补偿永远比站内渲染慢一拍,这个闪没法靠加快轮询根治。
【本版做法:干脆不用站内那层,自己画】
① 站内遮罩层直接 display:none —— 它只是纯视觉层
(本来就已被设成 pointer-events:none),
隐藏它不影响任何交互,也就不存在"闪"了;
② 遮罩改用 #live-player 的 ::after 伪元素:
· 常驻、opacity:0,靠 .bili-live-ctrl-on 切到 1,
带 180ms 过渡,跟控制栏滑入同步淡入,不突兀;
· 铺满整个播放器(不使用百分比之外的任何几何值),
底部最浓、向上渐隐,本身就不存在"断在 84px"的问题;
· pointer-events:none + 纯视觉,点击照样穿透回画面;
· z=11 —— 低于控制栏包层 z=13,不挡按键;
③ 按键行仍用 margin 位移补偿(v132.03 起的成熟做法),
JS 实测偏移量,不动任何状态通道。 ---- */
/* ① 弃用站内遮罩层(纯视觉层,隐藏不影响交互) */
body.bili-live-room-page .web-player-controller-bg,
body.bili-live-room-page #live-player > [class*="controller-bg"] {
display: none !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* ② 自建遮罩:常驻 + opacity 0/1 过渡,彻底没有"闪一下" */
body.bili-live-room-page #live-player::after {
content: '' !important;
position: absolute !important;
top: 0 !important;
right: 0 !important;
bottom: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
background: linear-gradient(
to top,
rgba(0, 0, 0, 0.62) 0%,
rgba(0, 0, 0, 0.44) 9%,
rgba(0, 0, 0, 0.22) 20%,
rgba(0, 0, 0, 0.08) 32%,
rgba(0, 0, 0, 0) 45%
) !important;
opacity: 0 !important;
transition: opacity 180ms ease !important;
pointer-events: none !important;
z-index: 11 !important;
}
body.bili-live-room-page #live-player.bili-live-ctrl-on::after {
opacity: 1 !important;
}
/* ③ 按键行:下移补偿(只动 margin,不动 transform / height / inset)
探针实证(bili_probe_2026-09-30_17-16,全屏 800x360):
.control-area [800x36] top=324 bottom=360(补偿后贴底 ✓)
84 只是首帧兜底(限全屏态),真实偏移由 JS 实测
(播放器底 − 按键底)后写精确值;普通态实测为 0 就写 0。 */
body.bili-live-room-page.bili-live-fs .control-area,
body.bili-live-room-page:has(:fullscreen) .control-area {
margin-bottom: -84px !important;
}
/* ============================================================
---- 12) v132.06:首屏零闪 —— 顶部栏等"一出生就该藏" ----
现象:刚打开直播间,官方 PC 顶部导航会先显示一下(还带着
被窄屏挤压后的变形),过一瞬才消失。
根因:本页所有隐藏规则都挂在
body.bili-live-room-page ×××
这个前缀上,而 bili-live-room-page 是 JS 给 打的。
脚本虽然是 document-start(样式表在 HTML 解析前就已注入),
但 body 要等 HTML 解析到才存在、class 要等 syncPageClass
跑过才生效 —— 中间这段时间导航栏是"无人管"的状态,
浏览器于是老老实实把它画了出来。
修法:这些元素是直播间**独有**的(#room-ssr-vm 是直播间
SSR 根节点 id,.link-navbar / footer.link-footer / #sidebar-vm
都只在 live.bilibili.com 出现,主站用的是 .bili-header),
所以可以直接用**不带任何 class 前缀**的选择器隐藏 ——
不依赖 body、不依赖 JS 打标,样式表一注入就成立,
元素刚被解析出来就是 display:none,一帧都不会画出来。
⚠ 刻意放在样式表**最后**:同为 !important 且特异性相同时
后写覆盖先写,放在末尾保证它压过前面任何一条同分规则。
⚠ 用 html:root 前缀抬特异性到 (1,1,1),与
body.bili-live-room-page #room-ssr-vm 同分,靠位置取胜。
⚠ main.app-content 的 padding-top:74px 是顶部栏留的位置,
顶部栏一藏它就是一块无来由的顶部空白,一并归零。 ---- */
html:root #room-ssr-vm,
html:root #room-ssr-vm *,
html:root .link-navbar-ctnr,
html:root .link-navbar-wrap,
html:root nav.link-navbar,
html:root .link-navbar,
html:root #head-info-vm,
html:root #gift-control-vm,
html:root #rank-list-vm,
html:root #rank-list-ctnr-box,
html:root #sections-vm,
html:root #sidebar-vm,
html:root #room-background-vm,
html:root #gift-screen-animation-vm,
html:root #guard-popup,
html:root footer.link-footer {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-width: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
padding: 0 !important;
margin: 0 !important;
border: none !important;
overflow: hidden !important;
pointer-events: none !important;
}
/* 顶部栏留的那 74px,一并抹掉,避免首屏内容先被推下去再弹回来 */
html:root main.app-content,
html:root main.app-content.p-relative {
padding-top: 0 !important;
}
`;
root.appendChild(style);
}
const PAGE_CLASS_RULES = [
{ test: isSearchPage, cls: ['bili-search-page'] },
{ test: isTBiliDynamic, cls: ['bili-dynamic-page'] },
{ test: isOpusPage, cls: ['bili-opus-page'] },
{ test: isHome, cls: ['bili-home-page'] },
{ test: isSpacePage, cls: ['bili-space-page'] },
// 播放列表页:额外带上 bili-video-page,直接复用视频页的全部优化
{ test: isListPage, cls: ['bili-video-page', 'bili-list-page'] },
{ test: isVideoPage, cls: ['bili-video-page'] },
{ test: isBangumiPage, cls: ['bili-bangumi-page'] },
{ test: isLiveRoomPage, cls: ['bili-live-room-page'] }
];
const ALL_PAGE_CLASSES = [
'bili-search-page', 'bili-dynamic-page', 'bili-opus-page', 'bili-home-page',
'bili-space-page', 'bili-video-page', 'bili-list-page', 'bili-bangumi-page',
'bili-live-room-page'
];
function currentPageClasses() {
for (let i = 0; i < PAGE_CLASS_RULES.length; i++) {
if (PAGE_CLASS_RULES[i].test()) return PAGE_CLASS_RULES[i].cls;
}
return [];
}
function syncPageClass() {
if (!document.body) return false;
const want = currentPageClasses();
const cl = document.body.classList;
ALL_PAGE_CLASSES.forEach(c => { if (want.indexOf(c) === -1) cl.remove(c); });
want.forEach(c => cl.add(c));
return true;
}
function applyPageClassEarly() {
if (!syncPageClass()) {
const obs = new MutationObserver(() => {
if (syncPageClass()) obs.disconnect();
});
obs.observe(document.documentElement, { childList: true, subtree: true });
}
// 站内跳转(如 /list/ 与 /video/ 互跳)时同步页面 class
window.addEventListener('popstate', syncPageClass);
['pushState', 'replaceState'].forEach(fn => {
const orig = history[fn];
if (typeof orig !== 'function') return;
history[fn] = function () {
const ret = orig.apply(this, arguments);
setTimeout(syncPageClass, 0);
return ret;
};
});
}
function fixVideoControls() {
if (!isVideoPage() && !isBangumiPage() && !isListPage()) return;
if (fixVideoControls._done) return;
const playerContainer = document.querySelector('body.bili-video-page .bpx-player-container') || document.querySelector('body.bili-bangumi-page .bpx-player-container');
if (!playerContainer) return;
const videoArea = playerContainer.querySelector('.bpx-player-video-area');
if (!videoArea) return;
const videoPerch = videoArea.querySelector('.bpx-player-video-perch');
const videoWrap = (videoPerch && videoPerch.querySelector('.bpx-player-video-wrap'))
|| videoArea.querySelector('.bpx-player-video-wrap');
if (!videoWrap) return;
const video = videoWrap.querySelector('video');
if (!video) return;
if (videoWrap.parentElement === videoArea && videoArea.firstElementChild === videoWrap) {
fixVideoControls._done = true;
return;
}
if (videoPerch && videoWrap.parentElement !== videoArea) {
videoArea.insertBefore(videoWrap, videoPerch);
}
video.playsInline = true;
const oldControlWrap = videoArea.querySelector('.bpx-player-control-wrap:not(.new)');
if (!oldControlWrap) return;
const controlEntity = oldControlWrap.querySelector('.bpx-player-control-entity');
if (!controlEntity) return;
let clickTimer;
let hideTimer;
const controlWrap = document.createElement('div');
controlWrap.className = 'bpx-player-control-wrap new';
controlWrap.innerHTML = '';
videoArea.insertBefore(controlWrap, oldControlWrap);
controlWrap.appendChild(controlEntity);
const controlTop = controlEntity.querySelector('.bpx-player-control-top');
const bottomRight = controlEntity.querySelector('.bpx-player-control-bottom-right');
const isBpxStateShow = () => controlEntity.querySelector('.bpx-player-control-bottom-right > .bpx-state-show');
const isShown = () => playerContainer.getAttribute('ctrl-shown') === 'true';
playerContainer.setAttribute('ctrl-shown', 'false');
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
const firstNode = mutation.addedNodes[0];
if (firstNode && firstNode.nodeType === Node.ELEMENT_NODE
&& firstNode.classList.contains('bpx-player-ctrl-web')) {
if (video.paused) showControlWrap();
const subtitleBtn = document.querySelector('.bpx-player-ctrl-subtitle');
if (subtitleBtn) {
window.addEventListener('click', (event) => {
if (!subtitleBtn.contains(event.target)) {
subtitleBtn.dispatchEvent(new MouseEvent('mouseleave'));
}
});
}
observer.disconnect();
}
});
});
if (bottomRight) observer.observe(bottomRight, { childList: true });
function hideControlWrap(isEnd = false) {
if ((!video.paused && !isBpxStateShow()) || isEnd) {
playerContainer.setAttribute('ctrl-shown', 'false');
clearTimeout(hideTimer);
} else {
delayHideTimer();
}
}
function showControlWrap() {
playerContainer.setAttribute('ctrl-shown', 'true');
delayHideTimer();
}
function delayHideTimer() {
clearTimeout(hideTimer);
hideTimer = setTimeout(hideControlWrap, 3000);
}
function unmute() {
video.muted = false;
if (video.volume === 0) {
const muteIcon = document.querySelector('.bpx-player-ctrl-muted-icon');
if (muteIcon) muteIcon.click();
}
}
video.addEventListener('ended', () => hideControlWrap(true));
video.addEventListener('play', delayHideTimer);
videoWrap.addEventListener('mousemove', (e) => e.stopPropagation());
videoWrap.addEventListener('click', () => {
clearTimeout(clickTimer);
clickTimer = setTimeout(() => {
if (isShown()) hideControlWrap();
else showControlWrap();
if (video.paused) video.play();
else video.pause();
}, 250);
});
videoWrap.addEventListener('dblclick', () => {
clearTimeout(clickTimer);
unmute();
const isPortrait = video.videoHeight / video.videoWidth > 1;
if (isPortrait) {
const webBtn = document.querySelector('.bpx-player-ctrl-web');
if (webBtn) webBtn.click();
} else if (videoPerch) {
videoPerch.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }));
}
});
controlWrap.addEventListener('mousemove', (e) => e.stopPropagation());
controlWrap.addEventListener('click', (e) => {
e.stopPropagation();
delayHideTimer();
});
if (controlTop) controlTop.addEventListener('touchstart', delayHideTimer);
fixVideoControls._done = true;
}
function bindVideoSlideGesture() {
if (!isVideoPage() && !isBangumiPage() && !isListPage()) return;
if (bindVideoSlideGesture._bound) return;
bindVideoSlideGesture._bound = true;
let mask = document.getElementById('my-bili-right-mask');
if (!mask) {
mask = document.createElement('div');
mask.id = 'my-bili-right-mask';
document.body.appendChild(mask);
}
const MIN_DISTANCE = 60;
const MAX_TIME = 600;
function getPanel() {
if (isListPage()) return document.querySelector('body.bili-list-page .playlist-container--right');
if (isVideoPage()) return document.querySelector('body.bili-video-page .right-container');
if (isBangumiPage()) return document.querySelector('body.bili-bangumi-page .plp-r-wrap');
return null;
}
function isOpen() { const r = getPanel(); return r && r.classList.contains('show'); }
function openPanel() { const r = getPanel(); if (r) r.classList.add('show'); mask.classList.add('show'); }
function closePanel() { const r = getPanel(); if (r) r.classList.remove('show'); mask.classList.remove('show'); }
mask.addEventListener('click', closePanel);
let startX = 0, startY = 0, startTime = 0;
document.addEventListener('touchstart', e => {
if (e.touches.length !== 1) return;
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
startTime = Date.now();
}, { passive: true });
document.addEventListener('touchend', e => {
if (e.changedTouches.length !== 1) return;
const dx = e.changedTouches[0].clientX - startX;
const dy = e.changedTouches[0].clientY - startY;
const dt = Date.now() - startTime;
if (Math.abs(dy) > Math.abs(dx)) return;
if (dt > MAX_TIME) return;
if (dx < -MIN_DISTANCE && !isOpen()) openPanel();
else if (dx > MIN_DISTANCE && isOpen()) closePanel();
}, { passive: true });
}
function bindFullscreenFix() {
if (!isVideoPage() && !isListPage()) return;
if (bindFullscreenFix._bound) return;
bindFullscreenFix._bound = true;
const handleChange = () => {
const isFull = !!(document.fullscreenElement || document.webkitFullscreenElement ||
document.mozFullScreenElement || document.msFullscreenElement);
if (isFull) {
document.body.classList.add('video-fullscreen');
} else {
document.body.classList.remove('video-fullscreen');
}
};
document.addEventListener('fullscreenchange', handleChange);
document.addEventListener('webkitfullscreenchange', handleChange);
document.addEventListener('mozfullscreenchange', handleChange);
document.addEventListener('MSFullscreenChange', handleChange);
document.addEventListener('orientationchange', () => {
if (document.fullscreenElement || document.webkitFullscreenElement) {
setTimeout(handleChange, 100);
}
});
}
/* ================================================================
关键词屏蔽(+必含 / -排除)v131.62
官方搜索没有屏蔽词,这里在自建搜索栏的输入语法上补一层:
输入 "+洛克王国 -手游 -世界"
· 提交给 B 站的关键词只剩 "洛克王国"(+ 号本身只是标记,会被剥掉)
· "手游"、"世界" 存为屏蔽词,结果页把标题/UP主命中它们的卡片整块隐藏
屏蔽词同时写进 URL(?_no=手游|世界)和 sessionStorage:
· URL —— 刷新、翻页、切排序后仍然有效,链接分享给别人也带着
· 存储 —— URL 参数万一被站内跳转抹掉时兜底
过滤范围:卡片标题 + UP主 + 底部信息(播放/弹幕/时间那一行),
大小写不敏感,命中任意一个屏蔽词就整块消失。
⚠ 这一段必须用 JS:CSS 选择器无法按元素的文本内容做匹配
(规范里的 :contains() 从未实装,至今也没有替代方案),
想"标题含某个词就不显示"只能遍历节点判断。
其余部分仍全部走 CSS,这段 JS 只负责打标记 + 插入提示条。
================================================================ */
const FILTER_PARAM = '_no';
const FILTER_STORE = 'bili_mobile_minus_words';
// 把 " +洛克王国 -手游 -世界 " 拆成 include / exclude 两组
function parseQueryTokens(raw) {
const tokens = String(raw || '').split(/\s+/).filter(Boolean);
const include = [], exclude = [];
tokens.forEach(function (t) {
if (t.length > 1 && t.charAt(0) === '-') exclude.push(t.slice(1));
else if (t.length > 1 && t.charAt(0) === '+') include.push(t.slice(1));
else include.push(t);
});
return { include: include, exclude: exclude };
}
function readBlockedWords() {
let raw = '';
try {
raw = new URL(location.href).searchParams.get(FILTER_PARAM) || '';
} catch (e) {}
if (raw) {
try { sessionStorage.setItem(FILTER_STORE, raw); } catch (e) {}
} else {
try { raw = sessionStorage.getItem(FILTER_STORE) || ''; } catch (e) {}
}
return raw.split('|').filter(Boolean);
}
function saveBlockedWords(list) {
try {
if (list && list.length) sessionStorage.setItem(FILTER_STORE, list.join('|'));
else sessionStorage.removeItem(FILTER_STORE);
} catch (e) {}
}
function escapeHTML(s) {
return String(s).replace(/[&<>"']/g, function (c) {
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c];
});
}
// 四种搜索结果的卡片根元素(v131.83:原来只写了 .bili-video-card,
// 导致屏蔽词只对综合页生效,直播 / 专栏 / 用户页一张都不过滤)
const FILTER_CARD_SELECTOR = [
'.bili-video-card', // 综合页 视频(综合页的直播区也是 .bili-live-card)
'.bili-live-card', // 直播页 直播间 / 综合页 直播区
'.b-article-card', // 专栏页
'.b-user-info-card' // 用户页
].join(', ');
// 卡片上参与匹配的文本:标题 + UP主 + 信息行 / 摘要
function cardMatchText(card) {
const pick = function (sel) {
const el = card.querySelector(sel);
return el ? (el.textContent || '') : '';
};
const parts = [
// 综合页 · 视频卡
pick('.bili-video-card__info--tit'),
pick('.bili-video-card__info--owner'),
pick('.bili-video-card__info--bottom'),
// 直播卡
pick('.bili-live-card__info--tit'),
pick('.bili-live-card__info--uname'),
pick('.bili-live-card__info--text'),
// 专栏卡(h2 标题 + 摘要 + 信息行)
pick('.i_card_title'),
pick('.atc-desc'),
pick('.atc-info'),
// 用户卡(名字 + 粉丝数/简介)
pick('.user-content'),
pick('.user-name')
].filter(Boolean);
// 兜底:万一某个页面的类名又变了,用整卡文本,保证任何卡片都参与匹配
return parts.length ? parts.join(' ') : (card.textContent || '');
}
function removeFilterBar() {
const bar = document.getElementById('my-bili-filterbar');
if (bar && bar.parentNode) bar.parentNode.removeChild(bar);
if (document.body) document.body.classList.remove('has-filter-bar');
renderFilterBar._sig = null;
}
function renderFilterBar(blocked, hidden) {
if (!document.body) return;
// 内容没变就不重绘 —— run() 会被 MutationObserver 反复触发,
// 每次都重建 innerHTML 会让横向滚动位置被重置、看着一闪一闪
const sig = blocked.join('|') + '#' + hidden;
if (renderFilterBar._sig === sig && document.getElementById('my-bili-filterbar')) return;
renderFilterBar._sig = sig;
let bar = document.getElementById('my-bili-filterbar');
if (!bar) {
bar = document.createElement('div');
bar.id = 'my-bili-filterbar';
document.body.appendChild(bar);
}
document.body.classList.add('has-filter-bar');
bar.innerHTML =
'已屏蔽' +
blocked.map(function (w) {
return '' + escapeHTML(w) + '';
}).join('') +
'已过滤 ' + hidden + ' 条' +
'清除';
const clear = bar.querySelector('.fb-clear');
if (clear) {
clear.addEventListener('click', function () {
saveBlockedWords([]);
try {
const u = new URL(location.href);
u.searchParams.delete(FILTER_PARAM);
location.href = u.toString();
} catch (e) {
location.reload();
}
});
}
}
function applyKeywordFilter() {
if (!isSearchPage()) { removeFilterBar(); return; }
const blocked = readBlockedWords();
// 先复位:把上一轮(或刚点了"清除")隐藏过的卡片全部放出来,再重算
document.querySelectorAll('[data-blocked="1"]').forEach(function (el) {
el.style.removeProperty('display');
el.removeAttribute('data-blocked');
});
if (!blocked.length) { removeFilterBar(); return; }
const lowBlocked = blocked.map(function (w) { return w.toLowerCase(); });
let hidden = 0;
document.querySelectorAll(FILTER_CARD_SELECTOR).forEach(function (card) {
const text = cardMatchText(card).toLowerCase();
let hit = false;
for (let i = 0; i < lowBlocked.length; i++) {
if (text.indexOf(lowBlocked[i]) !== -1) { hit = true; break; }
}
if (!hit) return;
// 隐藏"网格项"而不是内层卡片 —— 探针实测外层才占栅格单元,
// 只藏内层卡片的话外层仍占 168x172,会留下一排空洞
// 综合页 / 直播页:.col_3、.video-list-item.col_3…
// 专栏页:.col_6.mb_x40 用户页:.col_6.col_md_4
let item = card;
const p = card.parentElement;
if (p && /\bcol_/.test(p.className)) item = p;
item.setAttribute('data-blocked', '1');
item.style.setProperty('display', 'none', 'important');
hidden++;
});
renderFilterBar(blocked, hidden);
}
// 搜索类型:/live 直播、/article 专栏、/upuser 用户,其余算综合
const SEARCH_TYPES = [
{ key: 'all', name: '综合', path: '/all' },
{ key: 'live', name: '直播', path: '/live' },
{ key: 'article', name: '专栏', path: '/article' },
{ key: 'upuser', name: '用户', path: '/upuser' }
];
const MENU_CARET = '';
function currentSearchType() {
const p = location.pathname.replace(/\/$/, '') || '/';
let t = 'all';
SEARCH_TYPES.forEach(function (x) { if (p === x.path) t = x.key; });
return t;
}
// SPA 跳转 / 异步渲染后,重算菜单项的高亮与链接
function syncSearchMenu() {
const bar = document.getElementById('my-bili-searchbar');
if (bar && typeof bar._refreshMenu === 'function') bar._refreshMenu();
}
function createSearchBar() {
if (!isHome() && !isSearchPage() && !isSpacePage()) return;
if (document.getElementById('my-bili-searchbar')) return;
const onSearch = isSearchPage();
const onSpace = isSpacePage();
const url = new URL(location.href);
const currentOrder = url.searchParams.get('order') || '';
const curType = currentSearchType();
// 直播页的排序是「综合排序 / 最新开播」,参数 online / live_time,
// 与综合页、专栏页的 pubdate 不是一套,必须分开判断。
const onLive = onSearch && curType === 'live';
const isLatest = onLive ? (currentOrder === 'live_time') : (currentOrder === 'pubdate');
const bar = document.createElement('div');
bar.id = 'my-bili-searchbar';
// 用户搜索页(/upuser)的排序是「默认排序/粉丝数/Lv等级」,
// 与综合页的「综合/最新」不是一套参数,这里点了没效果,直接不显示。
const onUpuser = onSearch && curType === 'upuser';
const showLeftBtn = !onSpace && !onUpuser;
let leftBtnHTML = '';
if (showLeftBtn) {
if (onSearch) {
// 左侧按钮:名字改为「排序」,点击逻辑与「切换」一致(展开/收起一行)
leftBtnHTML = `
`;
} else {
leftBtnHTML = `
`;
}
}
// 右侧「切换」按钮 + 两行展开菜单(只在搜索页)
let switchBtnHTML = '';
let menuHTML = '';
if (onSearch) {
switchBtnHTML = `
`;
// 名字统一为「综合 / 最新」,与各页保持一致;
// 直播页底层参数仍是官方的 online / live_time(不是 pubdate)。
const orderItems = onLive
? [{ v: '', n: '综合' }, { v: 'live_time', n: '最新' }]
: [{ v: '', n: '综合' }, { v: 'pubdate', n: '最新' }];
menuHTML = (onUpuser ? '' : `
`) + `
`;
}
// 两个隐藏 checkbox 必须排在所有被控元素之前(CSS 只有后继兄弟选择器)
// 用户页没有「排序」按钮,对应的 checkbox 也不生成
const cbHTML = !onSearch ? '' :
(onUpuser ? '' : '') +
'';
const placeholderText = onSpace ? '搜索视频、动态'
: '搜索视频、番剧、UP主...(用 -词 排除,例:洛克王国 -手游)';
const kw = onSearch ? (url.searchParams.get('keyword') || '') : '';
// 回填时把屏蔽词拼回原文("洛克王国 -手游 -世界"),用户接着编辑不会丢
const blockedNow = onSearch ? readBlockedWords() : [];
const fullKw = blockedNow.length
? kw + ' ' + blockedNow.map(function (w) { return '-' + w; }).join(' ')
: kw;
const escapedKw = fullKw.replace(/"/g, '"').replace(//g, '>');
bar.innerHTML = `
${cbHTML}
${leftBtnHTML}
${switchBtnHTML}
${menuHTML}
`;
const attach = () => {
if (!document.body) { setTimeout(attach, 50); return; }
document.body.appendChild(bar);
// ⚠ 必须用 id 取!bar 里第一个 input 是隐藏 checkbox #my-bili-order-cb,
// checkbox 的默认 value 就是字符串 "on",裸 querySelector('input') 会抓到它,
// 导致搜索关键词变成 "on"(v131.69 修复)。
const input = bar.querySelector('#my-bili-search-input');
const btn = bar.querySelector('.my-search-btn');
const doSearch = () => {
// 拆出 +必含 / -排除,只把正经关键词交给 B 站
const parsed = parseQueryTokens(input.value.trim());
const keyword = parsed.include.join(' ');
if (!keyword) return;
saveBlockedWords(parsed.exclude);
if (onSpace) {
const mid = location.pathname.split('/').filter(Boolean)[0] || '';
if (!mid || !/^\d+$/.test(mid)) return;
location.href = `https://space.bilibili.com/${mid}/search?keyword=${encodeURIComponent(keyword)}`;
return;
}
// v131.82:原来硬编码跳 /all,导致在直播 / 专栏 / 用户页搜索
// 都会跳回综合页。改成按当前页路径构造:
// 综合 /all、直播 /live、专栏 /article、用户 /upuser
// 并带上各页需要的官方参数(vt / from_source / search_type)。
const ct = currentSearchType();
let base = 'https://search.bilibili.com/all';
SEARCH_TYPES.forEach(function (t) { if (t.key === ct) base = 'https://search.bilibili.com' + t.path; });
const next = new URL(base);
next.searchParams.set('keyword', keyword);
if (ct !== 'all') {
next.searchParams.set('vt', '63088886');
next.searchParams.set('from_source', 'web_search');
}
// 直播页:主播区已隐藏,只搜直播间,与页面「共找到 N 个结果」一致
if (ct === 'live') next.searchParams.set('search_type', 'live_room');
// 屏蔽词带在 URL 上:刷新 / 翻页 / 切排序都还在
if (parsed.exclude.length) next.searchParams.set(FILTER_PARAM, parsed.exclude.join('|'));
// 排序保持当前状态:直播页用 live_time,其余用 pubdate
if (isLatest) next.searchParams.set('order', ct === 'live' ? 'live_time' : 'pubdate');
location.href = next.toString();
};
input.addEventListener('keydown', e => {
if (e.key === 'Enter' || e.keyCode === 13) { e.preventDefault(); doSearch(); }
});
btn.addEventListener('click', doSearch);
// ---- 菜单项链接:随输入框实时重算,保证切过去用的是当前关键词 ----
const currentKeyword = () => {
const parsed = parseQueryTokens(input.value.trim());
return {
kw: parsed.include.join(' '),
exclude: parsed.exclude
};
};
// 切类型:综合走 /all,直播/专栏/用户照抄官方带的 vt 与 from_source
const buildSwitchHref = (type) => {
const c = currentKeyword();
let base = 'https://search.bilibili.com/all';
SEARCH_TYPES.forEach(function (t) { if (t.key === type) base = 'https://search.bilibili.com' + t.path; });
const next = new URL(base);
const kw = c.kw || url.searchParams.get('keyword') || '';
if (kw) next.searchParams.set('keyword', kw);
if (type !== 'all') {
next.searchParams.set('vt', '63088886');
next.searchParams.set('from_source', 'web_search');
}
if (c.exclude.length) next.searchParams.set(FILTER_PARAM, c.exclude.join('|'));
return next.toString();
};
// 排序:留在当前搜索类型上,只动 order 参数(不会莫名跳回综合页)
const buildOrderHref = (order) => {
const c = currentKeyword();
const next = new URL(location.href);
const kw = c.kw || next.searchParams.get('keyword') || '';
if (kw) next.searchParams.set('keyword', kw);
else next.searchParams.delete('keyword');
if (c.exclude.length) next.searchParams.set(FILTER_PARAM, c.exclude.join('|'));
else next.searchParams.delete(FILTER_PARAM);
if (order) next.searchParams.set('order', order);
else next.searchParams.delete('order');
// 直播页:主播区已隐藏,排序只针对直播间,
// 补上官方「直播间」用的 search_type=live_room,
// 这样结果数与页面上「共找到 N 个结果」一致。
if (currentSearchType() === 'live') next.searchParams.set('search_type', 'live_room');
return next.toString();
};
const refreshMenuHrefs = () => {
const ct = currentSearchType();
const ordNow = new URL(location.href).searchParams.get('order') || '';
const latestNow = ct === 'live' ? (ordNow === 'live_time') : (ordNow === 'pubdate');
bar.querySelectorAll('.my-bili-menu-item').forEach(function (a) {
if (a.dataset.type) {
a.href = buildSwitchHref(a.dataset.type);
a.classList.toggle('is-current', a.dataset.type === ct);
} else if (a.hasAttribute('data-order')) {
a.href = buildOrderHref(a.dataset.order || '');
a.classList.toggle('is-current', !!a.dataset.order === latestNow);
}
});
};
// 供 syncSearchMenu 在 SPA 跳转后复用
bar._refreshMenu = refreshMenuHrefs;
refreshMenuHrefs();
input.addEventListener('input', refreshMenuHrefs);
// ---- 互斥 + 点击外部收起(展开/收起本身是纯 CSS,这里只管状态互斥) ----
const allCb = () => bar.querySelectorAll('.my-bili-menu-cb');
const closeAll = () => { allCb().forEach(function (o) { o.checked = false; }); };
bar.addEventListener('change', function (e) {
const t = e.target;
if (!t.classList || !t.classList.contains('my-bili-menu-cb')) return;
if (t.checked) {
allCb().forEach(function (o) { if (o !== t) o.checked = false; });
}
});
document.addEventListener('click', function (e) {
if (bar.contains(e.target)) return;
closeAll();
});
// 菜单项点完就跳走了,顺手收起,避免 SPA 返回时菜单还开着
bar.querySelectorAll('.my-bili-menu-item').forEach(function (a) {
a.addEventListener('click', function () { setTimeout(closeAll, 0); });
});
// 兜底:B站是 SPA,站内跳转后如果 bar 还在,重置菜单状态
window.addEventListener('popstate', closeAll);
};
attach();
}
function fixSpaceNavTabs() {
if (!isSpacePage()) return;
const allowedTabs = ['主页', '动态', '投稿', '合集和系列'];
document.querySelectorAll('body.bili-space-page .nav-tab > a.nav-tab__item').forEach(el => {
const text = (el.textContent || '').trim();
el.style.removeProperty('display');
el.style.removeProperty('visibility');
const isAllowed = allowedTabs.some(t => text.indexOf(t) !== -1);
if (!isAllowed) {
el.style.setProperty('display', 'none', 'important');
el.style.setProperty('visibility', 'hidden', 'important');
}
});
}
function run() {
if (!document.body) return;
// 兜底:直播页 / 用户页偶发首屏拿不到自建搜索栏,这里补建并同步菜单状态
createSearchBar();
syncSearchMenu();
if (isTBiliDynamic()) {
// 动态页
} else if (isOpusPage()) {
// opus 详情页
} else if (isHome()) {
// 首页
} else if (isSearchPage()) {
// 搜索页:按 -排除词 过滤卡片(结果懒加载,run() 会被 MutationObserver 反复触发)
applyKeywordFilter();
} else if (isSpacePage()) {
fixSpaceNavTabs();
} else if (isVideoPage() || isListPage()) {
fixVideoControls();
bindVideoSlideGesture();
bindFullscreenFix();
} else if (isBangumiPage()) {
fixVideoControls();
bindVideoSlideGesture();
} else if (isLiveRoomPage()) {
liveDropWebFullscreenClass(); // 站内补的网页全屏,每次 run 顺手清一次
syncLiveFullscreen();
applyLivePlayerSize();
bindLivePlayerSizeWatch();
bindLiveDblclickFullscreen();
bindLiveWebFullscreenGuard();
bindLiveBackExitFullscreen();
liveTrimController(); // 控制栏只留时间 + 清晰度
applyLiveControllerGeom(); // v132.05:按键行偏移补偿 + 自建遮罩开关
liveMarkContextMenu(); // 给长按调试面板打标记(隐藏在 CSS)
bindLiveControllerWatch();
bindLiveLongPressGuard();
bindLiveChatScroll(); // 聊天区滚动(v131.98)
bindLiveControllerCompLoop(); // v132.05:按键行偏移补偿 + 遮罩开关轮询
}
}
/* ===== 直播间:全屏状态检测(v131.90 重写)=====
CSS 自己认不出"当前是不是全屏",只能由 JS 判断后给 body 打 bili-live-fs,
再由 CSS 里那组更高特异性的 .bili-live-fs 规则撤掉全部尺寸约束。
⚠⚠ 旧判定的致命坑(v131.88 / 131.89 都没修好,现象"没变化"就出在这):
旧版第 4 条「尺寸启发式:播放器贴满视口四边就算全屏」。
而退出原生全屏的那一刻,站内播放器会自己给 #fullscreen-container
写上一套 position:fixed + 铺满视口的**行内样式**(所谓"网页全屏",
仍带浏览器地址栏)。于是:
尺寸启发式命中 -> 判成"全屏" -> applyLivePlayerSize 走全屏分支,
把整条链写成 100%/100% -> 它真的铺满视口
-> 用户看到的就是"带地址栏的全屏"。
下一拍双击:不在原生全屏 -> 又 requestFullscreen 进原生全屏。
⇒ 两种全屏来回跳,永远退不回普通态。返回键同理:
浏览器用第一次返回退出原生全屏,站内立刻补上假全屏,
"看起来就是退到了带地址栏的全屏",再按一次才真的离开页面。
新判定:只认**原生**全屏,其余一切(class、行内尺寸、fixed 定位)都不算。
1) document.fullscreenElement / webkit 前缀
2) #fullscreen-container 命中 :fullscreen / :-webkit-full-screen(等价兜底)
站内自造的假全屏一律判"非全屏",由普通态那套 16:9 排版接管,
并立刻被 applyLivePlayerSize 写回正常尺寸 —— 即"双击 = 退出全屏"。
唯一例外:iOS Safari 不支持元素级 requestFullscreen,liveEnterFullscreen
只能退回点站内全屏键(那种确实是假全屏),此时靠 liveFsViaButton 放开,
仍按全屏铺满。Android 走不到这条分支,不会重新引入来回跳。 */
function isLiveFullscreen() {
if (liveIsNativeFs()) return true;
if (liveFsViaButton) return true;
const wrap = document.querySelector('#fullscreen-container');
if (wrap) {
try {
if (wrap.matches(':fullscreen') || wrap.matches(':-webkit-full-screen')) return true;
} catch (e) {}
}
return false;
}
function syncLiveFullscreen() {
if (!isLiveRoomPage() || !document.body) return false;
const on = isLiveFullscreen();
document.body.classList.toggle('bili-live-fs', on);
return on;
}
/* ===== 直播间:站内「假全屏」class 的摘除(辅助,非主力)=====
主播间的"网页全屏"在不同版本里挂过 body.player-full-win。
它不是根因(根因是 isLiveFullscreen 的尺寸启发式,已在 v131.90 修正),
但留着无害:class 一出现就摘掉,配合样式表第 6 段把它按普通态渲染。
只有"摘 class"这件事 CSS 做不到,所以保留这一小段 JS。 */
function liveDropWebFullscreenClass() {
if (!document.body) return false;
// 原生全屏生效时留着无害,但没必要动,免得和站内状态机互相抖
if (liveIsNativeFs()) return false;
if (!document.body.classList.contains('player-full-win')) return false;
document.body.classList.remove('player-full-win');
return true;
}
/* 假全屏不只会挂 class,还会给容器链写行内 position:fixed / inset / z-index
(行内 !important,样式表压不过,只能清行内)。非全屏时清一次,
播放器和评论区才会老老实实回到普通流里。 */
const LIVE_RESET_SEL = [
'.live-room-app', 'main.app-content', '.app-body',
'section.player-and-aside-area', '#player-ctnr', '.fullscreen-container-paddingbox'
];
const LIVE_RESET_PROPS = [
'position', 'top', 'left', 'right', 'bottom', 'inset',
'width', 'height', 'max-width', 'min-height', 'max-height',
'transform', 'z-index', 'overflow'
];
function resetLiveFakeFullscreenInline() {
let changed = false;
const roots = [document.documentElement, document.body];
roots.forEach(function (el) {
if (!el || !el.style) return;
LIVE_RESET_PROPS.forEach(function (p) {
if (el.style.getPropertyValue(p)) { el.style.removeProperty(p); changed = true; }
});
});
LIVE_RESET_SEL.forEach(function (s) {
const el = document.querySelector(s);
if (!el || !el.style) return;
LIVE_RESET_PROPS.forEach(function (p) {
if (el.style.getPropertyValue(p)) { el.style.removeProperty(p); changed = true; }
});
});
return changed;
}
function bindLiveWebFullscreenGuard() {
if (!isLiveRoomPage() || bindLiveWebFullscreenGuard._done) return;
const start = function () {
if (!document.body) { setTimeout(start, 50); return; }
if (bindLiveWebFullscreenGuard._done) return;
bindLiveWebFullscreenGuard._done = true;
const obs = new MutationObserver(function () {
// 摘掉后自己也会触发一次(class 没了 -> 直接返回 false),不会自激
const a = liveDropWebFullscreenClass();
const b = isLiveFullscreen() ? false : resetLiveFakeFullscreenInline();
if (a || b) {
syncLiveFullscreen();
applyLivePlayerSize();
}
});
obs.observe(document.body, { attributes: true, attributeFilter: ['class', 'style'] });
liveDropWebFullscreenClass();
};
start();
}
/* ===== 直播间:返回键 =====
实测行为:浏览器自己会把「全屏中的第一次返回」用来退出全屏(不发生导航),
第二次返回才真的后退。所以只要把退出全屏后站内补上的"假全屏"及时压回普通态
(见 isLiveFullscreen / applyLivePlayerSize),返回键的行为就自动正确了:
第一次返回 = 退出全屏,仍停在直播间
第二次返回 = 正常离开直播间页面
v131.89 曾经用 pushState 哨兵条目去"吃"这次返回,实测无效(浏览器压根不派
popstate,哨兵反而多留一条历史记录),这里删掉,只保留一条兜底:
万一有浏览器在返回时既退全屏又派 popstate,这里补一次 exitFullscreen,
保证不会带着全屏态去后退。 */
function bindLiveBackExitFullscreen() {
if (!isLiveRoomPage() || bindLiveBackExitFullscreen._done) return;
bindLiveBackExitFullscreen._done = true;
window.addEventListener('popstate', function () {
if (!isLiveRoomPage()) return;
if (liveIsNativeFs()) liveExitFullscreen();
}, true);
}
function bindLiveFullscreenWatch() {
if (!isLiveRoomPage()) return;
const sync = function () { syncLiveFullscreen(); };
['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange'].forEach(function (ev) {
document.addEventListener(ev, function () {
// 进来过就是成功,别再被 liveEnterFullscreen 的复核当成失败去重试
const on = isLiveFullscreen();
if (on) {
liveFsSawFs = true;
} else {
// 退出原生全屏的瞬间,站内会补一套"假全屏"(fixed 铺满视口)。
// 连清几拍:class、行内定位、尺寸全部压回普通态。
[0, 60, 150, 300, 600, 1000].forEach(function (ms) {
setTimeout(function () {
const a = liveDropWebFullscreenClass();
const b = resetLiveFakeFullscreenInline();
if (a || b) {
syncLiveFullscreen();
applyLivePlayerSize();
}
}, ms);
});
}
// 站内切换全屏后还要重排一帧,延后一拍才量得到真实尺寸
setTimeout(sync, 0);
setTimeout(sync, 120);
setTimeout(sync, 400);
setTimeout(applyLivePlayerSize, 0);
setTimeout(applyLivePlayerSize, 120);
setTimeout(applyLivePlayerSize, 400);
});
});
window.addEventListener('resize', function () {
sync();
applyLivePlayerSize(); // 假全屏常在 resize 时补写行内尺寸,一并压回去
});
window.addEventListener('orientationchange', function () {
[0, 300, 800].forEach(function (ms) {
setTimeout(function () { sync(); applyLivePlayerSize(); }, ms);
});
});
}
/* ================================================================
直播间:控制栏只留「时间」+「清晰度」
================================================================
单击播放器弹出的那条控制栏,探针实测:
.control-area > .left-area(含「47:43」)+ .right-area(含「自动」+ 一排图标)
窄屏(360)下右侧那排图标挤成一团,显示不全、点了也没反应(音量/弹幕/网页全屏
这些在手机上都用不了),全部隐藏;只留:
· 时间(形如 12:34 / 1:02:03)
· 清晰度(自动 / 流畅 / 高清 / 蓝光 / 原画 / 1080P …)
⚠ 为什么需要一点点 JS:CSS 选择器无法按「元素里的文字」匹配
(:contains() 从未实装),认不出哪个是时间、哪个是清晰度。
所以 JS 只做一件事:给要留的按键打 data-bili-live-keep="1";
隐藏、居中、间距全部由样式表第 9 段的 CSS 完成。 ---- */
const LIVE_TIME_RE = /^\d{1,3}:\d{2}(:\d{2})?$/;
const LIVE_QUALITY_RE = /^(自动|流畅|清晰|标清|高清|超清|蓝光|原画|真彩|4K|8K|\d{3,4}[pP](30|50|60)?)$/;
const LIVE_QUALITY_KEY = /画质|清晰度|quality|definition/i;
function liveIsKeepCtrl(node) {
if (!node || node.nodeType !== 1) return false;
const txt = ((node.textContent || '').trim());
if (LIVE_TIME_RE.test(txt)) return true;
if (LIVE_QUALITY_RE.test(txt)) return true;
const meta = (typeof node.className === 'string' ? node.className : '') + ' ' +
(node.getAttribute('aria-label') || '') + ' ' +
(node.getAttribute('title') || '');
return LIVE_QUALITY_KEY.test(meta);
}
// 文字有时在嵌套的子 div 里(探针:时间文字在 .tip-wrap 内的 div 上),
// 所以自己不匹配时再往下看一层;太宽的直接不认,避免整条区域被保留
function liveCtrlKeep(node) {
if (!node || node.nodeType !== 1) return false;
const r = node.getBoundingClientRect();
if (r.width > 200 || r.height > 80) return false;
if (liveIsKeepCtrl(node)) return true;
const kids = node.children || [];
if (kids.length > 8) return false;
for (let i = 0; i < kids.length; i++) {
if (liveIsKeepCtrl(kids[i])) return true;
}
return false;
}
function liveTrimController() {
if (!isLiveRoomPage()) return false;
const wrap = document.querySelector('#fullscreen-container') || document.body;
if (!wrap) return false;
const ctrl = wrap.querySelector('#web-player-controller-wrap-el') ||
wrap.querySelector('.web-player-controller-wrap') ||
wrap.querySelector('.live-web-player-controller') ||
wrap.querySelector('[class*="web-player-controller"]');
if (!ctrl) {
// 控制栏节点被整块换掉了:放开重绑开关,让 watch 重新挂到新节点上
bindLiveControllerWatch._done = false;
return false;
}
const area = ctrl.querySelector('.control-area') ||
ctrl.querySelector('[class*="control-area"]') || ctrl;
const areas = [];
['.left-area', '.right-area'].forEach(function (sel) {
Array.prototype.forEach.call(area.querySelectorAll(sel), function (a) {
// 只取直接子级,避免把嵌套区域也算进来
if (a.parentElement === area && areas.indexOf(a) === -1) areas.push(a);
});
});
if (!areas.length) areas.push(area);
let changed = false;
areas.forEach(function (a) {
Array.prototype.forEach.call(a.children, function (c) {
if (!c || c.nodeType !== 1) return;
const keep = liveCtrlKeep(c);
const has = c.getAttribute('data-bili-live-keep') === '1';
if (keep && !has) { c.setAttribute('data-bili-live-keep', '1'); changed = true; }
else if (!keep && has) { c.removeAttribute('data-bili-live-keep'); changed = true; }
});
});
return changed;
}
function bindLiveControllerWatch() {
if (!isLiveRoomPage() || bindLiveControllerWatch._done) return;
const start = function () {
const wrap = document.querySelector('#fullscreen-container');
const ctrl = wrap && (wrap.querySelector('#web-player-controller-wrap-el') ||
wrap.querySelector('.live-web-player-controller') ||
wrap.querySelector('.control-area'));
if (!ctrl) { setTimeout(start, 400); return; }
if (bindLiveControllerWatch._done) return;
bindLiveControllerWatch._done = true;
const obs = new MutationObserver(function () {
if (obs._t) clearTimeout(obs._t);
obs._t = setTimeout(function () {
liveTrimController();
applyLiveControllerGeom(); // v132.05:控制栏重渲染后重新测偏移
}, 80);
});
// 控制栏是 svelte 组件,会整体重渲染;class 变化也一起盯
obs.observe(ctrl, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] });
liveTrimController();
applyLiveControllerGeom();
};
start();
}
/* ================================================================
直播间:屏蔽播放器「长按」
================================================================
双击(尤其是退出全屏那一下)会带出两个东西:
A) 浏览器的「选中文字 / 复制分享」浮层
—— 已由 CSS 的 -webkit-touch-callout:none + user-select:none 掐掉。
B) 播放器自带的调试面板(#live-player > ul,z=99,
「画面异常?切换解码策略试试 / 播放器日志信息 / 视频统计信息 / Room Player」)
—— 挡画面,连点还会误触面板里的按键。
CSS 已经把 #live-player > ul 整块隐藏;这里再补两件 CSS 做不到的事:
1) contextmenu 在捕获阶段拦掉(浏览器长按浮层 + 站内面板都靠它触发),
stopImmediatePropagation 保证站内挂在元素上的监听也收不到;
2) 按文本识别面板,打 .bili-live-ctx-menu —— 万一站内换了容器
(不再挂在 #live-player 下面),CSS 那组选择器照样能隐藏它。 */
function liveMarkContextMenu() {
if (!isLiveRoomPage() || !document.body) return false;
let changed = false;
// 面板可能被挂到播放器外(portal),所以整棵文档都扫;
// 识别串("画面异常 / 切换解码 / 播放器日志 / Room Player")是播放器独有的,不会误伤
const nodes = document.querySelectorAll('ul, [class*="menu"], [class*="context"]');
Array.prototype.forEach.call(nodes, function (el) {
const txt = (el.textContent || '') + ' ' +
((typeof el.className === 'string' ? el.className : '') || '');
if (!/画面异常|播放器日志|视频统计信息|Room Player|切换解码/.test(txt)) return;
if (el.classList.contains('bili-live-ctx-menu')) return;
el.classList.add('bili-live-ctx-menu');
changed = true;
});
return changed;
}
function bindLiveLongPressGuard() {
if (!isLiveRoomPage() || bindLiveLongPressGuard._done) return;
bindLiveLongPressGuard._done = true;
// 捕获阶段:window 是最外层,先于站内任何元素级监听,能彻底掐断
window.addEventListener('contextmenu', function (e) {
if (!isLiveRoomPage()) return;
const t = e.target;
if (!t || !t.closest) return;
if (!t.closest('#fullscreen-container, #live-player')) return;
e.preventDefault();
e.stopPropagation();
if (e.stopImmediatePropagation) e.stopImmediatePropagation();
// 面板万一已经被触发,立刻补一次标记,让 CSS 收掉
setTimeout(liveMarkContextMenu, 0);
}, true);
// 切换全屏后的一小段时间里,长按 / 连点最容易误触,多扫几次
const sweep = function () {
if (liveMarkContextMenu()) liveTrimController();
};
[0, 120, 400, 900].forEach(function (ms) { setTimeout(sweep, ms); });
liveMarkContextMenu();
}
/* ===== 直播间:播放器尺寸接管 =====
站内有两种「行内 !important」写死的尺寸,样式表压不过,只能由 JS 补写行内:
A) 正常态:站内 JS 按「容器高 - 礼物栏 84px」给 .player-section 写高度,
礼物栏被我们隐藏后这 84 仍被扣掉,视频被压成 106 高的扁条(应为 190)。
B) 网页全屏(body.player-full-win):站内把 #fullscreen-container 写成
行内 668px(PC 定宽),塞进 360 的视口 → 右侧溢出被裁、左侧一片空白。
两种都靠"后写覆盖先写"解决:同一元素的 inline style 是同一个声明块,
我们后写同一属性就会顶掉站内的值。
v131.93:内层链改用 height:100%(而非 calc),跟随外层内容盒高度,
只有一份取整,彻底消除左/底部约 1px 的次像素缝隙(旧版 calc 与外层
calc 分别取整会产生差值)。min-height 与 max-height 同步写 100%,
防止站内再改 height 时出现闪动。
外层仍用 calc 维持 16:9 比例(含 6px 边框补偿)。 */
/* v131.93:内层链统一用 100% 跟随父级,消除两份 calc 取整带来的次像素缝隙。
外层仍用 calc 维持 16:9 比例(含 3px 边框 x2 = 6px)。 */
const LIVE_PLAYER_H = '100%';
// 外层还要带上 3px 边框 x2 = 6px,与 CSS 里 #fullscreen-container 的取值一致
const LIVE_WRAP_H = 'calc((100vw - 22px) * 9 / 16 + 6px)';
const LIVE_PLAYER_SEL = ['.player-section', '#live-player-ctnr', '#live-player', '#live-player video'];
// 只在值真的不一样时才写:observer 会盯着 style 属性,无脑重写会自激死循环
function setLiveStyle(el, prop, val) {
if (!el || !el.style) return;
if (el.style.getPropertyValue(prop) === val &&
el.style.getPropertyPriority(prop) === 'important') return;
el.style.setProperty(prop, val, 'important');
}
/* v131.94 兜底(只在 display:contents 不被支持的环境才会真正起作用):
CSS 里已让 .player-section 走 display:contents,行内几何值自然失效。
万一某个 WebView 不支持 display:contents,站内那套「容器高 - 84px」
的行内 height / min-height / max-height / bottom 就会重新压扁画面,
而样式表压不过行内 !important —— 这里直接把它摘掉,交回样式表。
摘完后 setLiveStyle 会立刻补写 100%,两边不会打架。 */
function stripPlayerSectionInline(wrap) {
const sec = wrap && wrap.querySelector('.player-section');
if (!sec || !sec.style) return;
['height', 'min-height', 'max-height', 'top', 'bottom'].forEach(function (p) {
if (sec.style.getPropertyValue(p)) sec.style.removeProperty(p);
});
}
function applyLivePlayerSize() {
const wrap = document.querySelector('#fullscreen-container');
if (!wrap) return;
stripPlayerSectionInline(wrap);
const chain = LIVE_PLAYER_SEL.map(function (s) { return wrap.querySelector(s); });
if (isLiveFullscreen()) {
// 原生全屏:贴满视口,顶掉站内行内的 668px 定宽
setLiveStyle(wrap, 'position', 'fixed');
setLiveStyle(wrap, 'top', '0');
setLiveStyle(wrap, 'left', '0');
setLiveStyle(wrap, 'width', '100%');
setLiveStyle(wrap, 'max-width', 'none');
setLiveStyle(wrap, 'height', '100%');
setLiveStyle(wrap, 'max-height', 'none');
setLiveStyle(wrap, 'min-height', '0');
setLiveStyle(wrap, 'transform', 'none');
chain.forEach(function (el) {
if (!el) return;
setLiveStyle(el, 'width', '100%');
setLiveStyle(el, 'max-width', 'none');
setLiveStyle(el, 'height', '100%');
setLiveStyle(el, 'min-height', '0');
setLiveStyle(el, 'max-height', 'none');
});
applyLiveControllerGeom(); // v132.05:全屏态同样实测补偿
return;
}
// 正常态:恢复 16:9。外层必须一并写回来 ——
// 上面全屏分支给它写过 height:100%,退出全屏后行内 !important 会压过 CSS,
// 播放器就会一直顶着满屏高。两条分支的属性集要对齐,才能来回切换都收敛。
//
// v131.90:这里额外把 position / inset / transform / z-index 一并写回。
// 站内退出原生全屏时会给 #fullscreen-container 写上一套行内
// 「position:fixed; top/left:0; 满视口」的假全屏,光改尺寸不够 ——
// 它还 fixed 着,就会盖在整页上面,看着仍然像全屏(只是带地址栏)。
//
// v131.93:内层链 height 改为 100%(不再用 calc),跟随外层内容盒,
// 只有一份取整,彻底消除左/底部约 1px 的次像素缝隙。
setLiveStyle(wrap, 'position', 'relative');
setLiveStyle(wrap, 'top', 'auto');
setLiveStyle(wrap, 'right', 'auto');
setLiveStyle(wrap, 'bottom', 'auto');
setLiveStyle(wrap, 'left', 'auto');
setLiveStyle(wrap, 'transform', 'none');
setLiveStyle(wrap, 'z-index', 'auto');
setLiveStyle(wrap, 'width', '100%');
setLiveStyle(wrap, 'max-width', '100%');
setLiveStyle(wrap, 'height', LIVE_WRAP_H);
setLiveStyle(wrap, 'min-height', '0');
setLiveStyle(wrap, 'max-height', LIVE_WRAP_H);
chain.forEach(function (el) {
if (!el) return;
setLiveStyle(el, 'position', 'absolute');
setLiveStyle(el, 'top', '0');
setLiveStyle(el, 'left', '0');
setLiveStyle(el, 'transform', 'none');
setLiveStyle(el, 'width', '100%');
setLiveStyle(el, 'max-width', '100%');
setLiveStyle(el, 'height', LIVE_PLAYER_H);
setLiveStyle(el, 'min-height', LIVE_PLAYER_H);
setLiveStyle(el, 'max-height', LIVE_PLAYER_H);
});
applyLiveControllerGeom(); // v132.05:同上,普通态也实测(通常 d=0)
}
/* ===== 直播间:控制栏偏移补偿 + 自建遮罩开关(v132.05)=====
样式表第 11 段负责两件 CSS 能做的事:
① 弃用站内遮罩层 .web-player-controller-bg(display:none)
—— 它带着 bottom:84px 让位,唤出瞬间会先在 84px 处渲染,
补偿永远比它慢一拍,因此"闪一下"无法靠轮询根治,直接弃用;
② 自建遮罩 #live-player::after(常驻 opacity:0,
.bili-live-ctrl-on 时淡入到 1),铺满播放器、底部渐隐向上。
这里补 CSS 做不到的一件事:**测出按键行真实的偏移像素数**
d = 播放器底边 − 按键行底边
只写 margin(绝不写 height / top / bottom / transform / opacity
—— 那是站内收起动画的状态通道,v132.01/02 碰了它才改坏自动隐藏)。
⚠ 用哪条 margin 取决于站内用的是 top 还是 bottom 定位:
bottom 定位 → margin-bottom: -d 下移
top 定位 / 静态 → margin-top: +d 下移
读了 computed style 再决定,两条都写会双重位移。
⚠ 撤除规则:
· d <= 2px(已贴底)→ 撤;
· 元素零尺寸 / 整块跑到播放器外(站内已收起卸载)→ 撤;
· 撤除必须写 0(行内 !important),光 removeProperty 会让
样式表那条 -84px 兜底立刻重新生效。
⚠ 补偿会让测得底边跟着下移,所以每轮都要用当前生效的位移量
还原原始位置再算,避免自激振荡。 ---- */
// 需要补偿的目标:按键行(站内遮罩层已在第 11 段直接弃用)
const LIVE_SHIFT_SEL = ['.control-area'];
/* 读当前**实际生效**的位移量与定位方式。
返回 { v: 下移像素(正数=已下移), via: 'mb' | 'mt' } */
function liveShiftState(el) {
let cs = null;
try { cs = window.getComputedStyle(el); } catch (e) {}
if (!cs) return { v: 0, via: 'mb' };
// bottom 定位时用 margin-bottom 负值下移;否则用 margin-top 正值
const via = (cs.bottom && cs.bottom !== 'auto') ? 'mb' : 'mt';
const raw = via === 'mb' ? cs.marginBottom : cs.marginTop;
const n = parseInt(raw, 10);
const v = isNaN(n) ? 0 : n;
return { v: (via === 'mb' ? -v : v), via: via };
}
/* 写入下移 d(另一条 margin 清零,避免残留造成双重位移) */
function liveSetShift(el, via, d) {
const val = (via === 'mb' ? (-d) : d) + 'px';
setLiveStyle(el, via === 'mb' ? 'margin-top' : 'margin-bottom', '0px');
setLiveStyle(el, via === 'mb' ? 'margin-bottom' : 'margin-top', val);
}
function liveClearShift(el) {
if (!el || !el.style) return;
setLiveStyle(el, 'margin-bottom', '0px');
setLiveStyle(el, 'margin-top', '0px');
}
function applyLiveControllerGeom() {
if (!isLiveRoomPage()) return false;
const player = document.querySelector('#live-player') ||
document.querySelector('#fullscreen-container');
if (!player) return false;
const pr = player.getBoundingClientRect();
if (pr.height <= 0) return false;
const pBottom = pr.bottom;
let shown = false;
LIVE_SHIFT_SEL.forEach(function (sel) {
Array.prototype.forEach.call(document.querySelectorAll(sel), function (el) {
if (!el || !el.style) return;
const r = el.getBoundingClientRect();
// 零尺寸 / 整块跑到播放器外 —— 站内已收起或卸载,撤补偿
if (r.height <= 0 || r.width <= 0 || r.top >= pBottom - 2 || r.bottom <= 2) {
liveClearShift(el);
return;
}
if (sel === '.control-area') shown = true;
const st = liveShiftState(el);
// 还原未补偿时的原始底边
const rawBottom = r.bottom - st.v;
const d = Math.round(pBottom - rawBottom);
if (d <= 2) { liveClearShift(el); return; }
if (d === st.v) return; // 已收敛,别反复写(防自激)
liveSetShift(el, st.via, d);
});
});
// 补底渐变的开关:控制栏显示时才亮,收起立刻灭
if (player.classList) player.classList.toggle('bili-live-ctrl-on', shown);
return true;
}
function bindLiveControllerCompLoop() {
if (!isLiveRoomPage() || bindLiveControllerCompLoop._done) return;
bindLiveControllerCompLoop._done = true;
// 站内滑入滑出有动画 + 会重新挂载,轮询跟上;250ms 一次,只在直播间页跑
setInterval(applyLiveControllerGeom, 250);
// 控制栏一挂载就立刻量一次,免得等下一拍才贴底(首帧闪一下)
const host = document.querySelector('#live-player') || document.body;
if (host) {
const mo = new MutationObserver(function () {
if (mo._t) clearTimeout(mo._t);
mo._t = setTimeout(applyLiveControllerGeom, 30);
});
// 只听**直接子节点**:控制栏就是 #live-player 的子孙,
// 用 subtree 会被弹幕的频繁插入带着一直跑
mo.observe(host, { childList: true });
}
applyLiveControllerGeom();
}
/* 站内会随时重写行内尺寸(切清晰度、切全屏、双击…),
光靠 run() 的那几个定时器抓不住,这里专盯着播放器链的 style/class 变化。 */
function bindLivePlayerSizeWatch() {
if (!isLiveRoomPage() || bindLivePlayerSizeWatch._done) return;
const wrap = document.querySelector('#fullscreen-container');
if (!wrap) { setTimeout(bindLivePlayerSizeWatch, 300); return; }
bindLivePlayerSizeWatch._done = true;
const obs = new MutationObserver(function () {
if (obs._t) clearTimeout(obs._t);
obs._t = setTimeout(applyLivePlayerSize, 60);
});
obs.observe(wrap, { attributes: true, attributeFilter: ['style', 'class'] });
LIVE_PLAYER_SEL.forEach(function (s) {
const el = wrap.querySelector(s);
if (el) obs.observe(el, { attributes: true, attributeFilter: ['style', 'class'] });
});
if (document.body) obs.observe(document.body, { attributes: true, attributeFilter: ['class'] });
applyLivePlayerSize();
}
/* ===== 直播间:聊天区滚动(v131.98 真·修好)=====
探针实录(bili_probe 含隐藏的探针)暴露了真正的根因:
.chat-history-panel [344x516] ← 面板被限死在一屏内(v131.97 生效了)
> #chat-history-list [344x1286] ← 列表却有 1286 高,跟内容一样长!
列表自己跟内容一样高 ⇒ scrollHeight === clientHeight ⇒
可滚动量 max = 0 ⇒ **它压根不是滚动容器**:
· 手指在聊天区滑 → 没有可滚的东西 → 纹丝不动
· 面板 overflow:hidden 把它裁掉 → 页面也不产生滚动 → 整页也滑不动
这正是「从一开始只要手指落在聊天区,滑动就完全无效」的原因,
也解释了 v131.97 的 JS 兜底为何没动静(它第一条就是 max<=2 直接 return)。
为什么 CSS 的 height:100% !important 没把它压回 516?
站内给列表写了**行内 !important** 的高度(与播放器那套 84px 同款手段),
样式表的 !important 压不过行内的 !important,只能由 JS 后写覆盖。
本版两步走:
① forceLiveChatSize —— JS 用行内 !important 把列表高度钉成面板高度
(优先取 panel.clientHeight 的 px 值,最稳;拿不到才退回 100%),
并补齐 overflow-y:auto / overscroll-behavior:contain / touch-action 等。
站内随时会重写(Vue 重渲染、新弹幕),用 MutationObserver 盯着补写。
② 手势兜底 —— 监听挂在 document **捕获阶段**(比站内任何监听器都早,
否则站内在祖先上 stopPropagation 我们就永远收不到事件),
只在「原生确实没动」时接管:defaultPrevented 为真,或累计位移
> 12px 而 scrollTop 纹丝不动。接管后手动写 scrollTop,
用 passive:false 以便必要时 preventDefault 掐掉页面滚动。 */
/* v131.99:聊天区高度改为「实测视口 - 面板顶距 - 36px」
—— 为什么不用纯 CSS 的 100dvh?两份探针对比说明了问题:
刚进直播间:100dvh ≈ 524 → 面板 240,看着很矮
全屏再退出:100dvh ≈ 800 → 面板 516,明显变高
同一个页面视口差出 276px,是移动端浏览器地址栏/工具栏收放造成的,
dvh 在某些 WebView 里还会滞后一拍,纯 CSS 算出来的高度忽高忽低。
这里直接读 visualViewport.height(拿不到退 innerHeight),
再用面板的**文档坐标**顶距(rect.top + scrollY,不随滚动变化)换算:
目标高 = 视口高 - 面板顶距 - 36
这样无论地址栏是收是放,聊天区底边恒距屏幕底 36px。 */
function forceLiveChatSize() {
const panel = document.querySelector('.chat-history-panel');
const list = document.querySelector('#chat-history-list');
if (!list) return false;
let h = '100%';
if (panel) {
const vp = window.visualViewport;
const vh = (vp && vp.height) || window.innerHeight ||
(document.documentElement && document.documentElement.clientHeight) || 0;
const scrollY = window.scrollY || window.pageYOffset || 0;
const docTop = panel.getBoundingClientRect().top + scrollY; // 文档坐标,稳定
if (vh > 320 && docTop > 0) {
const target = Math.round(vh - docTop - 36); // 距屏幕底 36px
if (target > 120) h = target + 'px';
} else if (panel.clientHeight > 40) {
h = panel.clientHeight + 'px'; // 兜底:沿用面板高
}
}
setLiveStyle(list, 'height', h);
setLiveStyle(list, 'min-height', '0');
setLiveStyle(list, 'max-height', h);
setLiveStyle(list, 'overflow-x', 'hidden');
setLiveStyle(list, 'overflow-y', 'auto');
setLiveStyle(list, 'overscroll-behavior', 'contain');
setLiveStyle(list, 'touch-action', 'pan-y');
setLiveStyle(list, 'transform', 'none');
setLiveStyle(list, '-webkit-overflow-scrolling', 'touch');
if (panel) {
// 面板跟着列表一起定高,两者始终等高(否则列表会被面板裁掉一截)
if (h !== '100%') {
setLiveStyle(panel, 'height', h);
setLiveStyle(panel, 'min-height', '0');
setLiveStyle(panel, 'max-height', h);
}
setLiveStyle(panel, 'overflow', 'hidden');
setLiveStyle(panel, 'overscroll-behavior', 'contain');
setLiveStyle(panel, 'touch-action', 'pan-y');
}
return true;
}
function bindLiveChatScroll() {
if (!isLiveRoomPage() || bindLiveChatScroll._done) return;
if (!forceLiveChatSize()) { setTimeout(bindLiveChatScroll, 400); return; }
bindLiveChatScroll._done = true;
// 站内随时重写行内尺寸 / 重渲染,盯着补写
const panel = document.querySelector('.chat-history-panel');
const list = document.querySelector('#chat-history-list');
const obs = new MutationObserver(function () {
if (obs._t) clearTimeout(obs._t);
obs._t = setTimeout(forceLiveChatSize, 60);
});
if (list) obs.observe(list, { attributes: true, attributeFilter: ['style', 'class'] });
if (panel) obs.observe(panel, { attributes: true, attributeFilter: ['style', 'class'] });
window.addEventListener('resize', function () { setTimeout(forceLiveChatSize, 120); });
window.addEventListener('orientationchange', function () { setTimeout(forceLiveChatSize, 300); });
// v131.99:地址栏收放 / 键盘弹出只改 visualViewport,不触发 window.resize,
// 这里单独盯住,视口一变立刻按新的可视高度重算「距底 36px」
if (window.visualViewport) {
const vv = window.visualViewport;
const onVV = function () { setTimeout(forceLiveChatSize, 80); };
vv.addEventListener('resize', onVV);
vv.addEventListener('scroll', onVV);
}
// 首屏 dvh 常滞后一拍,多补几次让高度尽快收敛
[0, 150, 400, 900, 1800].forEach(function (ms) { setTimeout(forceLiveChatSize, ms); });
let active = false, hijack = false, lastY = 0, startTop = 0, moved = 0;
const inChat = function (t) {
return !!(t && t.closest && t.closest('.chat-history-panel, #aside-area-vm'));
};
document.addEventListener('touchstart', function (e) {
if (e.touches.length !== 1 || !inChat(e.target)) { active = false; return; }
forceLiveChatSize(); // 每次手势前先确认列表被钉住
const l = document.querySelector('#chat-history-list');
if (!l) { active = false; return; }
active = true;
hijack = false;
moved = 0;
lastY = e.touches[0].clientY;
startTop = l.scrollTop;
}, { capture: true, passive: true });
document.addEventListener('touchmove', function (e) {
if (!active || e.touches.length !== 1) return;
const l = document.querySelector('#chat-history-list');
if (!l) return;
const y = e.touches[0].clientY;
const dy = lastY - y; // 手指上滑 dy>0 → scrollTop 变大
lastY = y;
moved += Math.abs(dy);
const max = l.scrollHeight - l.clientHeight;
if (max <= 2) return; // 列表还是没被限高,滚不了
if (e.defaultPrevented) hijack = true;
else if (!hijack && moved > 12 && Math.abs(l.scrollTop - startTop) < 2) hijack = true;
if (hijack) {
const next = Math.max(0, Math.min(max, l.scrollTop + dy));
if (next !== l.scrollTop) l.scrollTop = next;
if (e.cancelable) e.preventDefault(); // 掐掉页面滚动,避免两头一起动
}
}, { capture: true, passive: false });
const reset = function () { active = false; hijack = false; };
document.addEventListener('touchend', reset, { capture: true, passive: true });
document.addEventListener('touchcancel', reset, { capture: true, passive: true });
}
/* 控制栏最右侧那个全屏键 —— 只在兜底时才用(见 liveEnterFullscreen 说明) */
function liveFindFullscreenButton() {
const wrap = document.querySelector('#fullscreen-container') || document.body;
const ctrl = wrap.querySelector('#web-player-controller-wrap-el') ||
wrap.querySelector('.web-player-controller-wrap') ||
wrap.querySelector('[class*="web-player-controller"]');
if (!ctrl) return null;
// 探针「按键」实测:控制栏 = .control-area > .left-area / .right-area,
// 全屏键在 .right-area 最右端(right=777,与 .right-area 右边缘齐平)
const area = ctrl.querySelector('.right-area') ||
ctrl.querySelector('[class*="right-area"]') || ctrl;
let best = null, bestScore = -1, bestRight = -Infinity;
const nodes = area.querySelectorAll(
'button, [role="button"], [class*="tip-wrap"], [class*="btn"], [class*="icon"], ' +
'[class*="full"], [class*="screen"]'
);
Array.prototype.forEach.call(nodes, function (el) {
const tag = (el.tagName || '').toLowerCase();
if (tag === 'svg' || tag === 'path' || tag === 'g') return; // 图标内部节点,点了不触发
const r = el.getBoundingClientRect();
// 只认图标级小元素,排除整条 .right-area(597 宽)
if (r.width < 8 || r.height < 8 || r.width > 80 || r.height > 80) return;
const cls = (typeof el.className === 'string' ? el.className : '') || '';
const aria = (el.getAttribute && el.getAttribute('aria-label')) || '';
const key = cls + ' ' + aria + ' ' + (el.textContent || '');
let score = 0;
if (/full|screen|全屏/i.test(key)) score += 4; // 明确是全屏键
if (tag === 'button' || el.getAttribute('role') === 'button') score += 2;
if (/tip-wrap|btn|button/i.test(cls)) score += 1; // 按钮外层,比内部 span 稳
if (score > bestScore || (score === bestScore && r.right > bestRight)) {
best = el; bestScore = score; bestRight = r.right;
}
});
return best;
}
/* ===== 直播间:双击 = 进出「原生全屏」 =====
目标行为(v131.89 收紧为**严格二态**):
· 未开全屏 → 双击进入**原生全屏**(没有浏览器地址栏)
· 已开原生全屏 → 双击退出全屏,回到普通态(播放器 16:9 + 评论区在下)
为什么不再点站内那个键:
实测它切出来的是「网页全屏」body.player-full-win —— 带浏览器地址栏,
底部还留着给礼物栏的 84px 空档,而且会把播放器写死成 668px 定宽。
上一版正是"无条件点那个键",才出现
· 未开全屏双击没反应(控制栏未渲染时找不到键,退回的 API 调用也没生效)
· 全屏中双击在"正常全屏 ↔ 带地址栏的全屏"之间来回跳
v131.90 的三条修复(v131.89 只做了第 2 条,判定没改,所以现象"没变化"):
1) ★根因★ isLiveFullscreen 只认原生全屏,删掉"尺寸启发式"
—— 旧版一看播放器贴满视口就判"全屏",于是退出原生全屏后站内补的
假全屏被当成全屏、还被写成 100%/100%,真就铺满视口(带地址栏)。
现在假全屏一律判"非全屏",被强制压回 16:9,双击自然回到普通态。
2) 退出原生全屏的瞬间,站内有概率补 class / 写行内 fixed 定位,
由 liveExitFullscreen 连清几拍 + bindLiveWebFullscreenGuard 常驻清理,
行内 position/inset 也被写回 relative/auto(行内 !important 只能这样顶)
3) 返回键交给浏览器自身:它本来就会用第一次返回退出全屏,
假全屏被压回普通态后,"第一次=退全屏、第二次=离开页面"自动成立
进全屏仍带一条自愈链:依次试 #fullscreen-container / #live-player /
.player-section,并对每个候选做结果复核 —— 有些浏览器是 promise 不 reject
但实际压根没进全屏,400ms 后复查一次,没进就换下一个候选;
三个都失败才退回点站内那个键(老浏览器没有 Fullscreen API 时的最后退路)。
—— 状态判断、事件拦截、触发点击,CSS 都做不到,这一处只能 JS。 ---- */
// 由 fullscreenchange 置位:用来区分"请求失败"和"进来又被人手动退出了"
let liveFsSawFs = false;
// 只有 iOS Safari 这类不支持元素级 requestFullscreen 的浏览器才会置位:
// 表示"当前的全屏其实是站内自造的假全屏",此时仍要按全屏铺满(否则双击等于没反应)
let liveFsViaButton = false;
function liveIsNativeFs() {
return !!(document.fullscreenElement || document.webkitFullscreenElement);
}
function liveExitNativeFullscreen() {
const exit = document.exitFullscreen || document.webkitExitFullscreen ||
document.webkitCancelFullScreen || document.msExitFullscreen;
if (!exit) return false;
try {
const p = exit.call(document);
if (p && p.catch) p.catch(function () {});
} catch (e) { return false; }
return true;
}
/* 退出全屏:API 退出 + 把站内随后补上的假全屏清干净。
站内补发的时机不定(实测在下一帧到几百毫秒之间),所以连清几拍:
· class(player-full-win)
· 容器链的行内 fixed / inset / z-index(行内 !important,只能清行内)
· 播放器链的行内尺寸(applyLivePlayerSize 写回 16:9)
每次清理后都要 syncLiveFullscreen(),好让 bili-live-fs 立刻摘掉。 */
function liveExitFullscreen() {
liveFsViaButton = false;
const clean = function () {
const a = liveDropWebFullscreenClass();
const b = !liveIsNativeFs() ? resetLiveFakeFullscreenInline() : false;
syncLiveFullscreen();
applyLivePlayerSize();
return a || b;
};
clean();
const ok = liveExitNativeFullscreen();
[0, 60, 150, 300, 600, 1000, 1600].forEach(function (ms) {
setTimeout(clean, ms);
});
return ok;
}
function liveClickFsButton() {
const btn = liveFindFullscreenButton();
if (!btn) return false;
liveFsViaButton = true; // 这一路切出来的是站内假全屏,只能认它
btn.click();
return true;
}
function liveEnterFullscreen() {
const cands = ['#fullscreen-container', '#live-player', '.player-section'];
liveFsSawFs = false;
let done = false;
const tryOne = function (idx) {
if (done) return;
if (idx >= cands.length) { done = true; liveClickFsButton(); return; }
const el = document.querySelector(cands[idx]);
const req = el && (el.requestFullscreen || el.webkitRequestFullscreen ||
el.webkitRequestFullScreen || el.msRequestFullscreen);
if (!req) { tryOne(idx + 1); return; }
let p = null;
try { p = req.call(el); } catch (e) { tryOne(idx + 1); return; }
if (p && p.then) {
p.then(function () { done = true; },
function () { if (!liveIsNativeFs()) tryOne(idx + 1); });
}
// 复核:没收到过 fullscreenchange、现在也没在全屏,才算这次尝试失败
setTimeout(function () {
if (done || liveFsSawFs || liveIsNativeFs()) return;
tryOne(idx + 1);
}, 400);
};
tryOne(0);
return true;
}
/* 严格二态:全屏中 -> 退出;否则 -> 进原生全屏。
中间的"站内假全屏"不是一个合法状态 —— 进之前先把它清掉,
免得 requestFullscreen 被站内的状态机带偏。 */
function liveToggleFullscreen() {
if (liveIsNativeFs()) return liveExitFullscreen();
// 只有 iOS 兜底那条路会是真的假全屏,点站内键退出它
if (liveFsViaButton) {
liveFsViaButton = false;
const hit = liveClickFsButton();
setTimeout(function () { liveFsViaButton = false; syncLiveFullscreen(); applyLivePlayerSize(); }, 300);
return hit;
}
liveDropWebFullscreenClass();
resetLiveFakeFullscreenInline();
return liveEnterFullscreen();
}
// 切换后按站内重排的节奏复核几次:状态类 + 尺寸都要跟上
function liveAfterToggle() {
[60, 200, 400, 900].forEach(function (ms) {
setTimeout(function () {
syncLiveFullscreen();
applyLivePlayerSize();
applyLiveControllerGeom(); // v132.05:切全屏后重新测偏移
}, ms);
});
}
function bindLiveDblclickFullscreen() {
if (!isLiveRoomPage() || bindLiveDblclickFullscreen._done) return;
bindLiveDblclickFullscreen._done = true;
let lastTapT = 0, lastTapX = 0, lastTapY = 0, lastHandledT = 0, lastHandledSrc = '';
// 只认落在播放器画面上的操作:控制栏自己身上的双击不抢
const inPlayer = function (t) {
if (!t || !t.closest) return false;
// v132.02:探针(探测脚本 v3.4)在全屏时会被搬进 #fullscreen-container,
// 它虽在播放器容器内却不是画面,双击它不该切换全屏
if (t.closest('#__probe_btn, #__probe_panel')) return false;
if (!t.closest('#fullscreen-container, #live-player')) return false;
if (t.closest('#web-player-controller-wrap-el, .web-player-controller-wrap, .control-area')) return false;
return true;
};
window.addEventListener('dblclick', function (e) {
if (!inPlayer(e.target)) return;
const now = Date.now();
// 手机上手势已经被 touchstart 那条处理过,浏览器紧跟着合成的 dblclick
// 会让同一次双击被切换两次(等于没切 / 或切到另一个全屏态),这里挡掉
if (now - lastHandledT < 700 && lastHandledSrc === 'touch') return;
e.preventDefault();
e.stopPropagation();
if (e.stopImmediatePropagation) e.stopImmediatePropagation();
lastHandledT = now;
lastHandledSrc = 'dbl';
liveToggleFullscreen();
liveAfterToggle();
}, true);
// 站内若走 touch 而非 dblclick,这里兜住;lastHandledT 防与 dblclick 重复触发
window.addEventListener('touchstart', function (e) {
if (!e.touches || e.touches.length !== 1) return;
if (!inPlayer(e.target)) return;
const t = e.touches[0];
const now = Date.now();
if (now - lastHandledT < 700) return;
if (now - lastTapT < 300 &&
Math.abs(t.clientX - lastTapX) < 40 && Math.abs(t.clientY - lastTapY) < 40) {
lastTapT = 0;
lastHandledT = now;
lastHandledSrc = 'touch';
e.stopPropagation();
if (e.stopImmediatePropagation) e.stopImmediatePropagation();
liveToggleFullscreen();
liveAfterToggle();
return;
}
lastTapT = now; lastTapX = t.clientX; lastTapY = t.clientY;
}, true);
}
/* ============================================================
---- 首屏零闪(JS 兜底):元素一插进 DOM 就立刻藏 ----
样式表第 12 段已经用不依赖 body class 的选择器把这些元素
display:none 了,理论上样式表在 document-start 注入、元素一解析
出来就是隐藏的。但实测仍有"先显示一下再隐藏",说明在部分
移动端脚本环境里脚本并不是真的在文档开始时执行 ——
页面已经画过一帧,CSS 再补就必然有闪。
CSS 管不到"脚本来晚了"这种情况,只能靠 JS 在**能跑的第一刻**
就动手,并且盯着 DOM:节点刚被插进来(哪怕还没画到屏幕)
就立刻写行内 display:none,把可见时间压到最短。
行内 !important 只用于"藏",不碰任何几何/动画属性,
不影响站内其它逻辑。 ---- */
const LIVE_CHROME_SEL = [
'#room-ssr-vm',
'.link-navbar-ctnr',
'.link-navbar-wrap',
'nav.link-navbar',
'.link-navbar',
'#head-info-vm',
'#gift-control-vm',
'#rank-list-vm',
'#rank-list-ctnr-box',
'#sections-vm',
'#sidebar-vm',
'#room-background-vm',
'#gift-screen-animation-vm',
'#guard-popup',
'footer.link-footer'
].join(',');
function hideChromeEl(el) {
if (!el || !el.style) return;
const st = el.style;
if (st.getPropertyValue('display') !== 'none') {
st.setProperty('display', 'none', 'important');
}
if (st.getPropertyValue('visibility') !== 'hidden') {
st.setProperty('visibility', 'hidden', 'important');
}
}
/* main.app-content 的 padding-top:74px 是顶部栏留的位置,
顶部栏一藏它就是无来由的一块空白,顺手按当前页面状态归零。 */
function fixChromePadding() {
const m = document.querySelector && document.querySelector('main.app-content');
if (!m || !m.style) return;
let pt = 0;
try { pt = parseFloat(window.getComputedStyle(m).paddingTop) || 0; } catch (e) {}
if (pt > 40) m.style.setProperty('padding-top', '0px', 'important');
}
function sweepLiveChrome() {
if (!isLiveRoomPage()) return;
if (!document.querySelectorAll) return;
const list = document.querySelectorAll(LIVE_CHROME_SEL);
for (let i = 0; i < list.length; i++) hideChromeEl(list[i]);
fixChromePadding();
}
function bindEarlyChromeHide() {
if (!isLiveRoomPage() || bindEarlyChromeHide._done) return;
bindEarlyChromeHide._done = true;
let pending = false;
const raf = window.requestAnimationFrame ? window.requestAnimationFrame.bind(window)
: function (fn) { return setTimeout(fn, 16); };
const schedule = function () {
if (pending) return;
pending = true;
raf(function () { pending = false; sweepLiveChrome(); });
};
const attach = function () {
const target = document.documentElement;
if (!target) { setTimeout(attach, 0); return; }
sweepLiveChrome();
// 盯着整个文档:节点一被插入(含 SSR 解析、JS 后插)就立刻藏,
// 不等下一帧布局,把可见窗口压到最短
const mo = new MutationObserver(schedule);
mo.observe(target, { childList: true, subtree: true });
document.addEventListener('DOMContentLoaded', sweepLiveChrome, true);
window.addEventListener('load', sweepLiveChrome, true);
// 只是为了压住"首屏那一下"。稳定期交给样式表(CSS 一直在),
// 15 秒后停掉监听,省得跟着弹幕插入一直空跑。
setTimeout(function () { try { mo.disconnect(); } catch (e) {} }, 15000);
};
attach();
}
function start() {
installShadowRootPatch();
bindEarlyChromeHide(); // v132.07:能跑的第一刻就藏顶部栏等(先于样式表)
injectStyle();
applyPageClassEarly();
fixViewport();
createSearchBar();
bindLiveFullscreenWatch();
bindLivePlayerSizeWatch();
bindLiveDblclickFullscreen();
bindLiveWebFullscreenGuard();
bindLiveBackExitFullscreen();
bindLiveControllerWatch();
bindLiveLongPressGuard();
bindLiveChatScroll();
bindLiveControllerCompLoop();
const runAll = () => {
run();
setTimeout(run, 300);
setTimeout(run, 800);
setTimeout(run, 1500);
setTimeout(run, 3000);
setTimeout(run, 5000);
setTimeout(run, 8000);
setTimeout(run, 12000);
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', runAll);
} else {
runAll();
}
window.addEventListener('load', runAll);
const observer = new MutationObserver(() => {
if (observer._t) clearTimeout(observer._t);
observer._t = setTimeout(() => {
run();
}, 200);
});
const observeStart = () => {
if (!document.body) { setTimeout(observeStart, 50); return; }
observer.observe(document.body, { childList: true, subtree: true });
};
observeStart();
}
start();
})();