环境:Typecho 1.3.0 + nexmoe 主题,实测用 Chrome DevTools Protocol 读取真实渲染值
时间:2026-10-07 凌晨
一、起因:四条反馈
文章目录树做完之后,收到四条意见:
- 鼠标悬停时那块背景是直角的,要更圆润
- 圆点和竖连线是灰色的,应该用主题色
- 目录树压到正文了,没必要所有设备都显示 —— 顺带问:原主题是让所有设备都看到目录树吗?
- 我这台笔记本(华硕天选3,Windows 缩放 150%)看不到目录树
前三条是样式与显示范围问题,第四条是布局问题 —— 而且根因完全不在目录本身。
二、原主题的目录:确实是「所有设备都显示」
先回答疑问。把用户最初下载的原版主题包解出来对比:
原版 post.php 里一条 @media 都没有,而且目录的定位是:
.nexmoe-post-right .nexmoe-fixed {
position: fixed;
z-index: 1000;
height: 100vh;
display: inline-block;
top: 0;
}top: 0 + height: 100vh —— 从屏幕最顶端开始、占满整屏高度。
结论:原版就是所有设备都显示,在手机上还会直接盖住正文。 这是原版主题的设计缺陷,不是后加的。
所以这次的改法是:只在桌面宽屏显示,手机 / 平板 / 窄窗口一律不显示。
三、圆角与配色
3.1 圆角
.wb-toc a {
border-radius: 4px; /* 改前:几乎看不出圆角 */
border-radius: 10px; /* 改后:明显的胶囊感 */
}3.2 圆点和竖连线改用主题色
改前的写法是「跟随文字颜色」:
.wb-toc a::before {
background: currentColor; /* 文字是灰的,所以圆点也是灰的 */
opacity: .35;
}
.wb-toc ul ul::before {
background: rgba(0,0,0,.09); /* 竖连线:写死的淡灰 */
}改成直接取主题色变量:
.wb-toc a::before {
background: var(--n-theme);
opacity: .55;
}
.wb-toc ul ul::before {
background: rgba(var(--n-theme-rgb), .35);
}
.wb-toc a:hover {
color: var(--n-theme);
background: rgba(var(--n-theme-rgb), .1);
}
.wb-toc a.active {
color: var(--n-theme);
background: rgba(var(--n-theme-rgb), .16);
}关键前提:主题色变量定义在 :root 上:
<style id="nexmoe-theme-color">
:root {
--n-theme: <?php echo $__nThemeColor; ?>;
--n-theme-rgb: <?php echo $__nThemeRgb; ?>;
}
</style>因为是 :root,固定定位(position: fixed)的元素也能继承到,所以目录可以直接用主题色。用户以后改主题色,目录会自动跟着变。
实测确认:
目录项 border-radius : 10px
圆点 background-color : rgb(255, 78, 106)
竖连线 background-color : rgba(255, 78, 106, 0.35)四、压到正文 + 笔记本看不到:同一个根因
4.1 先量,不要猜
用 Chrome DevTools Protocol 把文章容器整条结构链的盒子信息全部读出来:
var el = document.querySelector('#nexmoe-content .nexmoe-post');
while (el && el.tagName !== 'BODY') {
var r = el.getBoundingClientRect(), cs = getComputedStyle(el);
// 记录 rect / margin / padding / width / position
el = el.parentElement;
}读出来的结果(视口 1280):
< html > width=1265px
< body > width=1100px padding-left=240px ← 病灶在这里
#nexmoe-content width=860px
.nexmoe-primary width=860px
.nexmoe-post width=820px rect: 343→11634.2 根因
主题把 body 硬编码成固定宽度:
body {
width: 1100px; /* 固定,不是 100% */
padding-left: 240px; /* 左侧留给侧栏 */
margin: 0 auto; /* 在视口里居中 */
}所以:视口再宽,正文右侧的留白也只有 (视口 - 1100) / 2。
- 1920 视口 → 右侧 402px,目录放得下
- 1536 视口 → 右侧 245px,勉强
- 1280 视口 → 右侧只有 118px,放不下
1280 是什么概念?Windows 缩放到 150% 的 1920 屏,CSS 视口宽度正好是 1280。这就是笔记本看不到目录的原因。
4.3 第一次尝试(失败):把文章整体左移
思路很自然:左侧那 240px 看起来是空的,把文章左移就能腾出右侧空间。
/* 第一版(错误方案) */
body.nexmoe-single #nexmoe-content {
left: max(-150px, min(0px, calc((100vw - 1580px) / 2)));
}数据上看是成功的:1280 视口下右侧余量从 118px 变成 232px,目录 200px 宽显示正常。
但截图一出来就露馅了:文章左移后,撞上了左侧的「文章分类 / 标签云」侧栏 —— 文章标题和正文左侧被侧栏盖住了一半。
原因:那 240px 并不是空白,它是 .nexmoe-secondary 侧栏的位置,只是在 1024px 以下才会 display: none。
教训:改布局一定要截图看整体,只量「目标元素」的数值会漏掉相邻元素的冲突。
4.4 最终方案:让文章在窄屏下收窄
既然不能左移,就换个方向:把文章本身变窄一点,两侧各让出一部分空间。文章保持居中,右侧就稳定空出一块。
@media screen and (min-width: 1024px) {
body.nexmoe-single .nexmoe-post {
max-width: min(820px, max(640px, calc(100vw - 720px)));
margin-left: auto;
margin-right: auto;
}
}宽度随视口线性变化:
| 视口 | 文章宽度 |
|---|---|
| ≥1540 | 820px(保持原样,大屏完全不受影响) |
| 1440 | 720px |
| 1366 | 646px |
| ≤1280 | 640px(下限) |
只作用于文章页 / 独立页(body.nexmoe-single),首页和归档页不受影响。
4.5 实测结果
用调试协议逐档量(13 档,从 1920 到 390):
| 视口 | 正文位置 | 目录 | 结论 |
|---|---|---|---|
| 1920 | 663→1483 | 1503→1703(宽 200) | 不重叠,间距 20px |
| 1600 | 503→1323 | 1343→1543(宽 200) | 不重叠 |
| 1536 | 473→1289 | 1309→1509(宽 200) | 不重叠 |
| 1440 | 473→1193 | 1213→1413(宽 200) | 不重叠 |
| 1366 | 473→1119 | 1139→1339(宽 200) | 不重叠 |
| 1280(150% 缩放笔记本) | 433→1073 | 1093→1271(宽 178) | 不重叠 |
| 1200 及以下 | — | 不显示 | 已隐藏 |
| 手机 390 | — | 不显示 | 已隐藏 |
另外还校验了一条硬约束:左侧常驻的抽屉图标条占视口 0~80px,正文左边缘必须大于 82px —— 全部档位最小是 305px,安全。
五、显示门槛的最终参数
var MIN_W = 130, MAX_W = 200, GAP = 20, EDGE = 10;
if (window.innerWidth < 1152) { wrap.style.display = 'none'; return; }
var avail = window.innerWidth - postRect.right - GAP - EDGE;
if (avail < MIN_W) { wrap.style.display = 'none'; return; }
wrap.style.width = Math.round(Math.min(MAX_W, avail)) + 'px';
wrap.style.left = Math.round(postRect.right + GAP) + 'px';
wrap.style.display = 'block'; // 必须显式写 block配合 CSS 的媒体查询(两份样式表都要写,因为暗色模式是替换样式表、不换 body 类):
@media screen and (max-width: 1279px) {
.wb-toc-wrap { display: none !important; }
}改完后的完整效果:
- ≥1280px 视口:显示目录,宽度 178~200px 自适应
- ≤1200px:不显示
- 圆点、连线、悬停底色全部跟随主题色
- 暗色模式单独一套(文字浅白 + 主题色点缀)
六、经验总结
- 「元素异常」先量再改。用调试协议读
getBoundingClientRect()和getComputedStyle(),比反复改代码让用户上传试错快得多。 - 量一个元素不够,要看整条结构链。这次的根因在
<body>上,只看.nexmoe-post永远找不到。 - 改完必须截图看整体。第一次的「左移」方案数据全对,但视觉上撞了侧栏 —— 数据对不等于效果对。
- 别再踩
style.display = ''这个坑:它只会清掉内联样式,反而回落到 CSS 里的display: none。 - 主题色变量定义在
:root时,position: fixed的元素也能继承,不用重复注入。 - 响应式阈值要对着真实场景定。Windows 常见缩放下:1920@150% = 1280、1920@125% = 1536、1440@125% = 1152 —— 定断点时要按这些实际值算,而不是按屏幕分辨率。
0 评论