4.0.0 引用块首尾加引号,让引用文字与正文段落对齐 #32

用户诉求(原话):引用块有色块和左侧宽度,导致块内文字比正文段落更靠右,
缩进不一致。方案:色块保留,在引用首尾各加一个引号,用引号占住那段缩进。

改前实测(1440 视口,线上真实文章):
  正文段落 p  文字起点 99
  blockquote  框内沿 89,块内 p 文字起点 121
  ⇒ 引用文字比正文靠右 22px,且块内段落还叠了一层 32px 首行缩进

修法:
  · border-left 6 + padding-left 26 = 32 = 正文 text-indent:2em(16px×2)
  · 块内 > p 的 text-indent 归零,消除「块内缩 + 段首缩进」双层叠加
  · 左引号 position:absolute 悬浮在 padding 区(inline 会被 block 级 p
    挤成匿名块行,跑到段落上方)
  · 右引号挂 > p:last-of-type,display:inline-block + line-height:0
    + height:0 + overflow:visible —— 行盒贡献 0,不撑高(否则块高 89→121)
  · 引号放大到 60/56px,淡色 #c6d2dd 做装饰;暗色降到 #3d4b58

两个踩到的坑(都只有像素级测量能发现):
  ① CJK 全角字形左侧 side bearing ≈ 0.62em。30px 字号下伪元素盒在
     x=12(完全正确),但引号墨迹在 30.5~40,正压在首字 32.5 上 ——
     「盒对了」≠「字形画在那儿」。指定 Georgia 等拉丁衬线字体后
     side bearing 降到 ≈0.03em,再用 left:2px/top:15px/font-size:60px。
  ② 窄屏(≤768px)kratos.css 把 .content p 降到 15px ⇒ 2em=30,
     硬编码的 32 就多 2px。不能写 calc(2em - 6px)(em 基数是 blockquote
     自己的 15px,不随视口变),只能在同一个断点覆盖;且这个 @media
     必须放在 ::before 基础规则之后,否则同特异性被后出现的 left:2px 压掉。

版本号 3.2.64 → 4.0.0(用户要求跳大版本:引用块渲染方式变了,
第三方 CSS 若针对 blockquote 内部做微调会受影响)。

验证:
  _geom32.js          48/0(3 篇 × 5 视口,对齐差全部 0.00px)
  _pix400.py          76/0(像素差分:墨迹落在缩进空白内、不压字、不撑高)
  _mkzip400.py        61/0
  _mkzip400_falsify   20/0(18 组注入全部报红在预期判据)
  _pix400_falsify      8/0
  _readme400.py       36/0(readme 15 节,181195 字节)
  php -l              97 文件 / 0 失败

包 kratos_yang-4.0.0.zip  md5 bc23f478d5f5170524aec3921b10e6ff
已发 /theme-update/,update.json 指向 4.0.0,PUC 实测 getUpdate=4.0.0。
主题目录未覆盖(仍是 3.2.64),等用户在后台点升级。
This commit is contained in:
2026-10-28 12:15:38 +08:00
parent ac1575fbbb
commit 05b4b56bf6
2 changed files with 197 additions and 1 deletions
+196
View File
@@ -472,3 +472,199 @@ ul > li {
margin-right: auto; margin-right: auto;
margin-left: auto; margin-left: auto;
} }
/* ── 引用块:首尾引号替代内缩,让引用文字与正文段落对齐(4.0.0 / 工单 #32)
*
* 【用户原话】"页面如果有引用的文字,会有一个色块,然后这个色块左侧有一定的宽度,
* 这样这个引用块里面的文字、段落也缩进了,这样就和主要段落缩进不同了。需要解决。
* 我的建议是,色块保留,然后在引用的开始和结束,增加两个引号,这两个引号,
* 代替引用文本的缩进,这样让引用文本的缩进和段落缩进基本保持一致。"
*
* ── 改前的实测(1440 视口,线上真实文章)────────────────────────
* 正文段落 p: left=67 text-indent=32px ⇒ 文字起点 99
* blockquote: left=67 border-l=6 padding-l=16 ⇒ 框内沿 89
* 块内 p: left=89 text-indent=32px ⇒ 文字起点 121
* ⇒ 引用文字比正文文字**靠右 22px**,且块内段落又叠了一层 32px 首行缩进。
*
* ── 修法:左侧内缩凑够 2em,块内段落首行不再缩进 ──────────────
* border-left 6 + padding-left 26 = 32 = 正文段落的 text-indent:2em
* ⇒ 引用文字起点 == 正文文字起点(实测 0.00px 差)
* 块内 `> p` 的 text-indent 归零,避免"块内缩 + 段首缩进"双层叠加。
* 右侧 padding 保持 kratos 原有的 16px(右边没有对齐要求)。
*
* 🔴 但"32px"只在宽屏成立 —— 正文段落的首行缩进其实**会随视口变**:
* kratos.css:1268 有 `@media screen and (max-width:768px)` 把
* `.content p` 的 font-size 降到 **15px**,于是 `text-indent: 2em = 30px`。
* 而 border 6 + padding-left 26 是写死的 32px ⇒ 窄屏引用文字比正文
* **靠右 2px**(实测 390 / 768 两档都是 2.00px)。
* 这是 pitfalls #470 同族:em 长度会跟着字号静默变化。
*
* 🔴 为什么不能直接写 `padding-left: calc(2em - 6px)`:
* `em` 的基数是**元素自己的 font-size**,而 blockquote 自己写着
* `font-size: 15px`(kratos.css:972,不跟视口变)。
* ⇒ 宽屏窄屏都会算出 15×2−6 = 24px,宽屏反而差 2px。
* em 基数必须与"正文段落"同步才能联动,而正文段落的字号是靠
* @media 跳变的 —— 所以这里只能**在与源规则同一个断点上覆盖**。
*
* 🔴 为什么不用 `font-size: inherit` 让 blockquote 跟着正文变(那样 em 就自动对齐):
* 那会把引用文字从 15px 抬到 16px,属于用户没要求的视觉改动。
* 本版只解决"缩进对齐",字号/色块/引号一律不动。
*
* ⚠️ 下面那条 `@media (max-width: 768px)` 的断点值必须与
* kratos.css:1253 严格一致。两者一旦脱钩,窄屏会重新错 2px。
* `_geom32.js` 的 B1 逐档断言对齐 ≤1.5px,脱钩会立刻红。
*
* ── 引号:左绝对定位、右 inline-block 零高 ──────────────────────
* 🔴 左引号**不能**用 `blockquote::before` 的 inline 形态:
* blockquote 的第一个子级是 **block 级 `<p>`**,行内伪元素会被挤成一个
* **独立的匿名块行**(实测 `Range.getClientRects()` 多出一条 width=0 的孤立行,
* 引号跑到段落上方单独一行)。所以必须 `position:absolute` 悬浮在
* padding 区,不参与文字流。
* 🔴 右引号若用普通 inline,会把行盒撑高 —— 实测块高 89 → **121px(+32)**。
* 这是 #467 同族的坑(行内盒的 line-height 参与行盒高度计算)。
* 解法:`display:inline-block; line-height:0; height:0; overflow:visible`
* —— 行盒贡献为 0(实测块高严格回到 89px,Δ=0.0000),字形靠 overflow 照常绘制。
* 这样它仍**在文字流里**,天然紧贴末字之后,不会随行宽漂移。
* ⚠️ 右引号挂 `> p:last-of-type` 而不是 `blockquote::after`:后者同样会另起
* 匿名块行;而且挂在 p 上才能贴着**最后一行文字的末尾**。
* ⚠️ 用 `:last-of-type` 而非 `:last-child`:引用块常带 `<cite>`(出处署名),
* `:last-child` 会落到 cite 上。
*
* ── 为什么左引号能"代替缩进" ────────────────────────────────
* 32px 的空白由 `padding-left` 提供,引号**画在这 32px 里**,
* 视觉上就是"引号占住了缩进的位置",而文字起点与正文段落齐平。
*
* 🔴🔴 但这句话一开始**并不成立** —— 差分实测(`_bqdiff.js` + pixel diff):
* `left: 6px`、伪元素盒左沿在元素内 x=12,
* 可引号**墨迹**却在 x=30.5~40,而首字墨迹起点是 32.5。
* ⇒ 引号整个压在正文文字上,缩进空白里空空如也。dir="ltr" 下完全看不出来。
*
* 根因:中文 UI 字体下 U+201C 走的是 **CJK 全角字形**,字身宽 1em,
* **左侧 side bearing ≈ 0.62em**。30px 字号 ⇒ 空白 18.5px,
* 盒左沿 12 + 18.5 = 30.5,正好压到首字。
* 这是"量盒 ≠ 量墨迹"的典型(#419 家族):盒对了,字形没画在那儿。
*
* 解法:给引号指定**拉丁衬线字体**,U+201C/U+201D 改走拉丁字形,
* side bearing 降到 ≈0.03em,left 就能用正常小正值。
* 顺便字形也更像"书刊引号",做装饰更合适。
*
* 最终参数(差分实测标定,见下表),元素内 CSS 坐标:
* | 目标 | 要求 | 实测(font 60px / left 2 / top 15)|
* | 落在缩进空白 (6,32) | 墨迹 x ∈ [8,30] | 10.0 ~ 29.5 ✅ |
* | 不压首字(32.5) | 墨迹右沿 < 31 | 29.5 ✅ |
* | 覆盖首行文字 | y 覆盖 24.5~39.5| 22.0 ~ 37.5 (略高 2.5px,视觉更自然)|
* | 比正文汉字更大 | 墨迹高 > 15 | 16.0 ✅(正文汉字 15.0)|
* 扫过的对照(都落选了,留档免得有人再试):
* · font-size 30 + CJK 字形:墨迹只有 9.5×7 —— 比正文还小,不是"放大"
* · font-size 30 + left -31:墨迹能落进空白,但要写负 left,且字号太小
* · font-size 44/52 + 拉丁字形:墨迹 15×11.5 / 18×13.5,仍小于正文汉字高
*
* ── 颜色/字号(用户选定"放大且淡色,做装饰")────────────────────
* 60px(引用文字 15px 的 4 倍;墨迹实际 20×16,比正文汉字略大,
* 因为是淡色描边感,视觉上不会喧宾夺主)
* #c6d2dd —— 比引用文字 #819198 更淡,且与左侧边框 #dce6f0 同色系,
* 保证"是装饰不是内容"。 */
.k-main .details .article .content blockquote {
/* border 6 + padding 26 = 32 = 正文段落 text-indent:2em(16px×2)
⚠️ 窄屏正文变 15px ⇒ 2em = 30 ⇒ 由**文件末尾**的 @media 改回 24
(必须放末尾!放这里会被后面的 ::before 基础规则压掉,见那条注释) */
padding-left: 26px;
/* 左引号绝对定位的包含块 */
position: relative;
}
/* 块内段落首行不再缩进 —— 否则 "块内缩 32" + "段首缩进 32" 双层叠加 */
.k-main .details .article .content blockquote > p {
text-indent: 0;
}
/* 左引号:悬浮在 padding 区,不参与文字流(原因见上) */
.k-main .details .article .content blockquote::before {
content: "\201C";
position: absolute;
/* 🔴 left/top 是差分标定出来的,不是推算的(推算差 18.5px,见上方长注释) */
left: 2px;
top: 15px;
font-size: 60px;
/* 🔴 必须用拉丁字体:CJK 全角字形左侧空白 0.62em,会把墨迹推到文字上 */
font-family: Georgia, "Times New Roman", serif;
line-height: 1;
color: #c6d2dd;
font-weight: 400;
font-style: normal;
/* 纯装饰,别让它挡住文字选中/点击 */
pointer-events: none;
/* 不被暗色规则里的 color 继承干扰 */
-webkit-user-select: none;
user-select: none;
}
/* 右引号:inline-block 零行盒高度,紧贴末字之后但不撑高 */
.k-main .details .article .content blockquote > p:last-of-type::after {
content: "\201D";
display: inline-block;
/* 🔴 这两行是不撑高的关键:行盒贡献 0,字形靠 overflow 溢出绘制 */
line-height: 0;
height: 0;
overflow: visible;
font-size: 56px;
/* 与左引号同一字体(同一个字形族才对得上) */
font-family: Georgia, "Times New Roman", serif;
color: #c6d2dd;
font-weight: 400;
font-style: normal;
/* 往下压一点,让引号底部与文字基线视觉齐平(实测 y 41~55.5,紧贴末字下沿) */
vertical-align: -0.28em;
margin-left: 0.04em;
pointer-events: none;
-webkit-user-select: none;
user-select: none;
}
/* 引用块里的出处署名(<cite>):不参与引号,也不吃首行缩进 */
.k-main .details .article .content blockquote cite {
text-indent: 0;
display: block;
font-style: normal;
margin-top: 8px;
}
/* ── 窄屏(≤768px)对齐修正 ──────────────────────────────────────
* kratos.css:1253 `@media screen and (max-width:768px)` 把 `.content p`
* 的 font-size 降到 15px ⇒ 正文 text-indent:2em = 30px。
* 这里把 padding-left 从 26 调到 24,凑回 border 6 + 24 = 30。
* 🔴 断点值 768 必须与 kratos.css:1253 严格一致,脱钩就重新错 2px。
*
* 🔴🔴 这个 @media 块**必须放在所有 blockquote 基础规则之后**。
* 第一版放在 `blockquote::before` 基础规则**之前**,两者特异性相同 ⇒
* 后出现的 `left: 2px` 把这里的 `left: 0` 压掉 ⇒
* 窄屏下引号墨迹右沿 30.0 正好顶到首字 30.0,压字。
* CSS 层判据全绿(它只能看到"@media 里确实写了 -2px"),
* 只有像素差分能发现。这是"同名选择器散在多处、后出现的赢"
* (pitfalls #437 / #472 同族)。
*
* 窄屏左侧空白由 32 缩到 30,引号墨迹宽 20,放不下 ⇒ left 再由 2 减 2。 */
@media screen and (max-width: 768px) {
.k-main .details .article .content blockquote {
padding-left: 24px;
}
.k-main .details .article .content blockquote::before {
left: 0;
}
}
/* ── 暗色适配 ─────────────────────────────────────────────────────
* 暗色由 `<html class="yang-dark">` 触发(本文件 321 行、toc.css 512 行等处
* 都是这个写法)。
* 暗底上 #c6d2dd 会偏亮、抢注意力,降到更暗的蓝灰。 */
html.yang-dark .k-main .details .article .content blockquote::before,
html.yang-dark .k-main .details .article .content blockquote > p:last-of-type::after {
color: #3d4b58;
}
/* 暗色下引用块本身的底色也要跟上(原来没有这条,浅蓝底在暗色页上刺眼) */
html.yang-dark .k-main .details .article .content blockquote {
background: #1c2026;
border-left-color: #2f3944;
}
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Theme Name: Kratos_Yang Theme Name: Kratos_Yang
Text Domain: kratos_Yang Text Domain: kratos_Yang
Version: 3.2.64 Version: 4.0.0
Requires PHP: 7.0 Requires PHP: 7.0
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好