Files
wordpress-kratos-yang/assets/css/highlight.css
T
laoyang 8f8cffd69e 3.2.43: 修代码块重影与语言识别,含 4 个静默 bug (#12)
排查结论:不是插件冲突,对手是主题自己的 kratos.css。

现象一「重影/阴影」的真实成因是 CSS 优先级 + 行高错位:
kratos.css 的 .content code(0,4,1) / .content pre code(0,4,2) 抢走了
border-radius:4px、color:#333、font-size:13px。字号被顶到 13px 后
行高算成 21.06px,而行号槽是 12.5px/20.25px,每行错开 0.81px,
30 行累计 24px —— 视觉上就是「两层东西叠在一起」。

现象二「多一个 copy 按钮」未能复现:2 个页面实测每张卡恰好 1 个
.cb-copy;Prism.plugins 只有 autoloader,copy-to-clipboard 未注册;
Enlighter 插件目录不存在。已请用户指认页面。

修复:
- highlight.css 的选择器提到与原主题同级 (0,4,2),靠出现更晚取胜,
  不用 !important。
- 顺带修掉 4 个静默 bug(都不报错、页面看着正常):
  1. header.php 从未调 body_class(),裸 <body> ⇒ 所有挂 body_class
     过滤器的类全部静默失效,包括行号开关 opt-ln(选项已开却不显示)。
  2. 79 个代码块的语言写在 <pre lang=> 或 data-enlighter-language 上,
     只读 <code> class 必然读不到 ⇒ 标签显示「—」。
  3. 白名单 4 项指向未打包语言(powershell/dos/dockerfile/nginx)。
     hljs 遇到不认识的语言不抛错,只 warn 一句就退回不高亮 ⇒
     整块白板。站内这 4 种用量均为 0,属潜伏 bug。
  4. hljs 把 plaintext 块改写成 language-undefined;highlightAuto
     对纯文本返回字符串 'undefined',if (r.language) 会误当真值。

顺带收敛:yang_hl_languages() 原本手写第二份清单,与 yang_hl_norm_lang()
里的表互相漂移,改为从 yang_hl_known_map() 单一来源派生。

验证:
- 单测 44 + 24 断言全通过
- 反向验证 10 组注入全部变红(含专门注入「恢复手写清单」验证新判据)
- 全站 284 块直连数据库校验:568 通过 / 0 失败,
  语言覆盖率 71.8% → 98.6%,残留与污染全 0
- 剩余 4 块显示「—」是正确降级(jsp×2、latex×2 未打包进 hljs)
- 夹具对照:新版 0 失败 vs 全旧版 10 失败
2026-10-26 11:00:47 +08:00

238 lines
8.0 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 代码块样式(highlight.js 自研接管后的卡片外观)
*
* 与 kratos.css 里原有那段的关系:
* 原有 `.k-main .details .article .content pre { … }` 里有
* `background-color:#f8f8f8`、`font-size:11px`、**`word-break:break-all`**。
* 最后这条会在任意字符处断行,代码看起来像乱码 —— 必须压掉。
* 本文件加载在 kratos.css 之后,用更高的特异性覆盖。
*/
/* ── 卡片外壳 ── */
.k-main .details .article .content .cb,
.comment-body .cb,
.cb {
position: relative;
margin: 14px 0;
border: 1px solid #d0d7de;
border-radius: 8px;
overflow: hidden;
background: #fff;
}
/* ── 顶部条:语言标签 + 复制按钮 ── */
.k-main .details .article .content .cb .cb-bar,
.cb .cb-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 10px;
background: #f6f8fa;
border-bottom: 1px solid #d0d7de;
font-size: 12px;
line-height: 1.5;
}
/* 语言标签:让人一眼看到"这是 Java",防止把 Python 和 Java 的实现贴反。
站内实测有 19 篇文章含 ≥2 种语言、38 处相邻代码块语言不同 —— 确有实用价值。 */
.cb .cb-lang {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 11px;
font-weight: 600;
letter-spacing: .02em;
color: #656d76;
padding: 1px 6px;
border-radius: 4px;
border: 1px solid #d0d7de;
background: #fff;
text-transform: none;
}
/* 🔴 自动识别出来的标签要**看得出来是猜的**:虚线边框 + 斜体。
站内 18 个 ≥4 行的未标注代码块实测自动识别只对了 4 个(22%)——
如果把它画得和作者标的一模一样,等于把 78% 的错误结果伪装成确定事实。 */
.cb .cb-lang[data-guess="1"] {
border-style: dashed;
font-style: italic;
opacity: .8;
}
.cb .cb-actions {
display: flex;
gap: 6px;
}
.cb .cb-copy {
font: inherit;
font-size: 11px;
padding: 3px 9px;
cursor: pointer;
color: #656d76;
background: #fff;
border: 1px solid #d0d7de;
border-radius: 5px;
transition: color .12s, border-color .12s, opacity .12s;
opacity: 0;
}
.cb:hover .cb-copy,
.cb .cb-copy:focus-visible { opacity: 1; }
.cb .cb-copy:hover { color: #0969da; border-color: #0969da; }
.cb .cb-copy.done { color: #1a7f37; border-color: #1a7f37; }
.cb .cb-copy.err { color: #cf222e; border-color: #cf222e; }
/* 🔴 触屏兜底:没有 hover 的设备上按钮必须常驻,否则永远点不到。
注意这里必须是「默认隐藏 + 触屏覆盖回 1」的写法。
如果默认是 1、只在 @media(hover:none) 里再写 1,那条规则等于空操作 ——
因为 1 本来就是默认值,删掉也不会变,故障测不出来。 */
@media (hover: none) {
.cb .cb-copy { opacity: 1; }
}
/* ── 代码区:左行号槽 + 右可滚动 pre ── */
.cb .cb-body {
display: flex;
align-items: stretch;
}
/* 行号槽。
🔴 它在 <pre> **外面**,所以行号文字永远不会进 code.textContent ⇒
"复制不带行号"是结构保证的,不靠 JS 删、也不靠正则过滤。
🔴 除了用户要求,这里还有一层现实原因:hljs 输出的是 token span,
没有行结构,想在 span 上挂 ::before 计数是挂不住的(没有 span.line 这种元素)。
原型阶段就是这么写的,结果 CSS 规则齐全、画面上零行号。 */
.cb .cb-ln {
display: none;
flex: 0 0 auto;
padding: 12px 0 12px 10px;
text-align: right;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 12.5px;
line-height: 1.62;
color: #9aa0a6;
background: #f6f8fa;
border-right: 1px solid #eaecef;
user-select: none;
-webkit-user-select: none;
overflow: hidden;
}
.cb .cb-ln > span { display: block; }
/* 行号开关(body 上带 opt-ln 类时显示)*/
.opt-ln .cb .cb-ln { display: block; }
/* 🔴 这里必须把 padding 显式写成 12px,和 .cb-ln 的 padding-top 对齐。
每套 hljs 官方主题都自带 `pre code.hljs{padding:1em}`,会把代码整体
往下压 1em。行号槽没有这个 padding,于是第一行代码的 top 比行号低 15.5px,
屏幕上就是"第 1 行代码旁边写着 2",往下每行错一位。
实测(原型页):修前逐行偏差 15.5px,修后 0.00px。 */
.k-main .details .article .content .cb pre,
.cb pre {
margin: 0;
padding: 12px 14px;
overflow-x: auto;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 12.5px;
line-height: 1.62;
/* 🔴 原有主题写的是 word-break:break-all,会在任意字符断行,代码像乱码。
长行必须横向滚动,不能折断。 */
word-break: normal;
overflow-wrap: normal;
white-space: pre;
tab-size: 4;
border: 0;
border-radius: 0;
background: transparent;
}
/* 主题自带的 code padding 必须归零,否则与行号槽错位(见上) */
.cb .cb-body > pre > code.hljs {
padding: 0;
overflow-x: visible;
}
.cb .cb-body > pre { flex: 1 1 auto; min-width: 0; }
/* 🔴 卡片里的 code 必须彻底摆脱原主题 `.content code` 的影响。
*
* 原主题 kratos.css 有两条规则(实测优先级):
* `.k-main .details .article .content code` → (0,4,1)
* margin:0 3px; padding:2px 4px; border-radius:4px;
* background-color:#eff0f1; color:#333; font-size:13px
* `.k-main .details .article .content pre code` → (0,4,2)
* margin:0; padding:0; background-color:transparent
*
* 后者只救了 margin/padding/background。**border-radius、color、font-size
* 全都漏了**,于是:
* · border-radius:4px → 代码区里嵌一块 4px 圆角,和卡片 8px 圆角打架,
* 视觉上就是用户说的「有阴影/重影」
* · font-size:13px → 代码字号被顶大,行高跟着从 20.25px 变 21.06px,
* 而行号槽用的是 12.5px/20.25px ⇒ 每行错开 0.81px,
* 30 行累计错 24px,行号与代码彻底对不上
* · color:#333 → 把 hljs 主题给 <pre> 的基色(.hljs{color:#000})
* 覆盖成固定的深灰。深色配色下就是深灰压深底,看不清
*
* 修法:选择器强度提到与 `.content pre code` 同级的 (0,4,2) ——
* 靠**出现更晚**取胜,不靠 !important(!important 会让用户/插件再也没法覆盖)。
* 显式写 border-radius:0 而不是依赖"没声明就继承",因为 border-radius
* 不继承、初始值是 0,但原主题那条规则会直接命中 code。 */
.k-main .details .article .content .cb pre code,
.comment-body .cb pre code,
.cb pre code {
display: block;
margin: 0;
padding: 0;
border: 0;
border-radius: 0;
background: transparent;
font-size: inherit;
line-height: inherit;
color: inherit;
font-family: inherit;
/* 原主题给了 word-break:inherit,pre 上是 normal,这里跟住 */
word-break: inherit;
overflow-wrap: inherit;
}
/* 深色配色必须让卡片自带深色底与深色顶条。
站点正文是浅色,若只在浅底上印深色配色,
token 与背景对比不足(现有 Prism 出问题的地方正在这里)。 */
.cb[data-kind="dark"] {
border-color: #30363d;
background: #0d1117;
}
.cb[data-kind="dark"] .cb-bar {
background: #21262d;
border-bottom-color: #30363d;
}
.cb[data-kind="dark"] .cb-lang {
background: #21262d;
border-color: #30363d;
color: #8b949e;
}
.cb[data-kind="dark"] .cb-copy {
background: #21262d;
border-color: #30363d;
color: #8b949e;
}
.cb[data-kind="dark"] .cb-copy:hover {
color: #58a6ff;
border-color: #58a6ff;
}
.cb[data-kind="dark"] .cb-ln {
background: #161b22;
border-right-color: #30363d;
color: #6e7681;
}
/* 窄屏:行号槽收窄,避免挤占代码宽度 */
@media (max-width: 560px) {
.cb .cb-ln { padding: 12px 0 12px 6px; font-size: 11px; }
.cb .cb-ln > span { padding-right: 4px; }
.cb pre { padding: 12px 10px; font-size: 12px; }
}
/* 打印:行号与复制按钮都不需要 */
@media print {
.cb .cb-ln, .cb .cb-actions { display: none !important; }
.cb { break-inside: avoid; }
}