代码高亮整套自研:10 浅 + 10 深配色、语言标签、评论区贴代码 (#11)
不再依赖第三方高亮插件,全部由主题自己实现。
主题配色(20 套)
- 浅色 10:github / vs / atom-one-light / idea / xcode /
stackoverflow-light / intellij-light / googlecode / magula / color-brewer
- 深色 10:github-dark / atom-one-dark / monokai / github-dark-dimmed /
a11y-dark / stackoverflow-dark / night-owl / srcery /
panda-syntax-dark / tomorrow-night-blue
- 深色卡片带 data-kind="dark",顶栏跟着换深色底
- 只加载当前选中的一套(20 套全加载会让后出现的规则压前面的,
切换配色容易"看起来没变")
代码语言标签(用户要求:防止复制错语言)
- 作者标了 language-xxx → 实线边框、正体
- 自动识别猜出来的 → 虚线边框、斜体
- 认不出来 → 显示 "—",仍保持虚线斜体(不冒充作者标注)
行号
- 默认关;行号槽在 <pre> 外面,复制天然不带行号
- 改掉原主题的 word-break:break-all(任意字符断行,代码像乱码)
- 归零 hljs 主题自带的 pre code.hljs{padding:1em},
否则代码被压低 1em、与行号槽错位 15.5px
复制
- 默认开;安全上下文判断 + execCommand 退路(HTTP 下 clipboard 是 undefined)
- 取 textContent 而非 innerHTML
- 默认 opacity:0、hover 显示、触屏覆盖回 1
(旧写法只在 @media(hover:none) 里写 1,等于空操作)
自动识别
- 做成选项,默认开
- 只对没标语言的块生效;站内实测长块准确率 22%,不能覆盖作者标注
评论区贴代码
- 评论工具条加"代码"按钮 + 29 种语言面板
- kses 放行 pre 并给 pre/code 放开 class
(WP 默认 pre 整条剥掉、code 属性全清,此前根本贴不了代码)
- 放行 pre 之后 wpautop/wptexturize/make_clickable 自动让路,
代码里的连续空行、引号、URL 都不会被改写
- comments.js 用占位符保护代码块,避免 walk() 的 /\n{3,}/ 压缩
其它
- 资源版本号改为读主题头,不再写死(写死会导致以后升级后
浏览器一直用旧缓存,改了 CSS/JS 完全不生效)
- 删除 footer.php 里旧的 Prism 兜底(两套高亮器同页会互相打架)
验收
- 用线上 284 个真实代码块跑产品代码:284/284 全部变卡片,内容丢字 0、双转义 0
- 47 个 text 标记全部映射到 plaintext(hljs 无 text 语言,不映射会静默不上色)
- 80 个裸 <pre>(无 code 子元素)全部覆盖
- 核心纯函数 65/65;核心反向 10/10 变红
- 浏览器端到端 32/32;行号几何逐行对齐偏差 0.00px,几何反向 4/4 变红
- 端到端反向 7/7 变红;语言标签反向 2/2 变红
- 全量 PHP 语法 95 文件 0 错误
发布:走 theme-update 通道(zip + readme + update.json),
未覆盖服务器主题目录;线上主题目录仍是 3.2.41,待后台升级。
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* 代码块样式(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; }
|
||||
|
||||
.cb pre code {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
font-family: 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; }
|
||||
}
|
||||
Reference in New Issue
Block a user