Files

671 lines
35 KiB
CSS
Raw Permalink Normal View History

@charset "UTF-8";
/**
* 站点级公共样式(3.2.29 起)
*
* 这些规则原来是站长手填在「主题设置 → 自定义代码 → 自定义 CSS」里的,
* 3.2.29 把它们并入主题公共样式,配置项因此留空。
*
* ⚠️ 选择器与声明**必须与原来的自定义 CSS 逐字一致**:
* 自定义 CSS 是以 `<style>` 形式紧跟在 kratos.min.css 之后输出的,
* 所以「排在最后 + 同选择器」才等价于原来的层叠结果。
* 本文件的加载顺序同样是 kratos.min.css 之后(enqueue 依赖 'kratos'),
* 改选择器范围(例如把 ul 收窄到 .article .content ul)会改变实际渲染。
*
* @author Yongquan Yang <yangyq.net>
* @license MIT License
*/
/* 正文段落首行缩进两字 */
.article .content p {
text-indent: 2em;
}
/* ── 正文插图:不吃段落的首行缩进,自成一行、左右都不缩进(3.2.60 / 工单 #28)
*
* 🔴 为什么必须有这一段:`text-indent` 是**可继承属性**。
*
* WP 把图片插进段落时,DOM 是 `<p><img></p>` 或 `<p><a><img></a></p>`。
* 图片(或包着它的 <a>)作为**行内级盒子**落在段落首行
* ⇒ 继承 32px 缩进,整体右移。
* 而 `max-width: 100%` 里的 100% 是**包含块(p)的内容宽度**,
* 不是"缩进之后剩下的宽度" ⇒ 图片仍按全宽铺开。
*
* 结果:左边缩进多少,右边就溢出多少,**二者永远相等**。
* 线上实测(2022/05/set-font-in-latex):左缩进 32px、右溢出 32px,
* 正文可绘制区 111~902.33,图片却是 143~934.33。
*
* ── ⚠️ 只给 img 清零 text-indent 是**不够**的(第一版就这么错)────────
*
* 实测:`.article .content img{ text-indent:0; display:block }` 之后,
* 图片自己的 computed text-indent 确实是 0px、display 也是 block,
* 但几何仍停在 143(照样偏 32px)。
*
* CDP `CSS.getMatchedStylesForNode` 抓到的真相:
* WP 会把图片包进 `<a class="yang-lb-item">`(灯箱),
* 而 lightbox.css 给它设了 `display: inline-block`。
* **inline-block 盒子的起点同样受父级 text-indent 影响** ——
* 它继承了 p 的 32px,于是整个「链接 + 图片」盒子被推进去 32px。
* 图片在盒子内部再怎么清零,也改不了盒子自己的起点。
*
* ⇒ 缩进必须清在**真正参与父级行内排版的那个盒子**上,
* 也就是 a.yang-lb-item / 裸 img 两者都要清。
*
* 修法:
* ① `text-indent: 0` 切断继承(不改 p 上的规则本身 ——
* 段落首行缩进是站长期望的效果,去掉会改变全站观感);
* ② `display: block` 自成一行,不参与首行的行内排版;
* ③ 图片用 `margin: … auto` 居中。
*
* ⚠️ 只看 `.content img`(后代)而不是 `> img`:图片外面常套一层
* `<a class="yang-lb-item">`(灯箱),直接子元素选择器量不到。
*
* ⚠️ 对齐类图片用 `:where()` 把特异性降到 0,让 kratos 的
* `.alignright{float:right}` / `.aligncenter` 等**照常生效**:
* 浮动的图本来就不该吃缩进,也不该被强制成块级居中。
* `:where()` 是 CSS4,Chrome 88+ / Safari 14+ / Firefox 78+ 支持;
* 更老的浏览器会整条规则失效 —— 退化成"维持现状",不会更坏。 */
.article .content img {
text-indent: 0;
display: block;
margin-left: auto;
margin-right: auto;
}
/* 🔴 灯箱链接:必须一起清零。它是 inline-block,本身就是参与父级
* 行内排版的盒子 —— 只清 img 无论用,位置由它决定。
* 见上面实测说明。 */
.article .content a.yang-lb-item {
text-indent: 0;
display: block;
line-height: 0;
margin-left: auto;
margin-right: auto;
}
/* 表情图必须保持行内:正文里它是夹在文字中的小图,
* 变 block 会换行、把句子拆断。特异性 (0,2,1) 压过上面那条。 */
.article .content img.wp-smiley,
.article .content img.emoji {
display: inline;
margin: 0;
vertical-align: middle;
text-indent: 0;
}
/* 对齐类图片交还给 kratos 的浮动/居中语义(特异性 0,不参与竞争)。
* 连包裹它的灯箱链接一起处理 —— 否则链接是 block、图片却 float,
* 会空出一整行。 */
:where(.article .content) img.alignright {
display: inline;
float: right;
margin: 0 0 8px 16px;
}
:where(.article .content) img.alignleft {
display: inline;
float: left;
margin: 0 16px 8px 0;
}
:where(.article .content) img.aligncenter {
display: block;
margin-left: auto;
margin-right: auto;
}
:where(.article .content) a.yang-lb-item:has(img.alignright) {
display: inline;
float: right;
margin: 0;
}
:where(.article .content) a.yang-lb-item:has(img.alignleft) {
display: inline;
float: left;
margin: 0;
}
/* 正文二级标题:左侧蓝条 + 浅灰底,横向铺满(负 margin 吃掉正文的 16px 内距)
*
* 3.2.61(工单 #29 追加):字号 20→24、字重 500→700。
* 🔴 这是 3.2.60 留下的层级倒挂的修复:3.2.60 把 h3 提到 20px/600,
* 而 h2 一直是 20px/500 —— 结果 h2 和 h3 同字号、h3 还更粗 100,
* 三级标题比二级标题更抢眼。用户一眼就看出"h3 比 h2 还大"。
* 根因是当时只动了 h3,没把 h2 一起拉起来,而且判据里
* **没有任何一条断言 h2 > h3**,所以 52 条全绿也照样漏了。
* ⇒ 往后调任一标题级别,必须同时断言相邻两级的**字号 + 字重**
* 都单调递减(见 _geom361_route.js 的 G 组)。
*
* 行高 41→46:24px 字配 41px 行高,上下各只剩 8.5px,灰底看着发扁;
* 46px 让上下各留 11px。这个 11px 是**算出来的**:
* 24px 字的实际墨迹高约 24×0.88 ≈ 21px(中文黑体 ascent+descent 之内),
* 行框 46px 减 21px 再除以 2 ≈ 12.5px,与 3.2.60 的 20px/41px
* (20×0.88=17.6,41-17.6=23.4,/2≈11.7px)基本持平。 */
.k-main .details .article .content h2 {
margin: 16px -16px;
padding: 0 10px;
border-left: 5px solid #00a2ff;
background-color: rgba(243, 243, 243, 0.7);
font-size: 24px;
font-weight: 700;
line-height: 46px;
}
/* ── 正文三级标题:左侧细竖线 + 底部细线(3.2.60 / 工单 #29)
*
* 3.2.60 之前 h3 只有 `font-size:18px; font-weight:500`,没有任何装饰,
* 而正文是 16px/350 —— **只差 2px 字号、150 字重**,放在长文里根本分不出来。
*
* 层级梯度(3.2.61 定稿,三级 + 四级同步调整):
* h2 24px / 700 / 左 5px 蓝条 + 浅灰底 ← 最重,分节
* h3 20px / 600 / 左 3px 蓝条 + 底 1px 细线,无底色
* h4 17px / 500 / 纯文字,无装饰
* p 16px / 350
*
* 🔴 两条铁律(3.2.60 违反第 1 条,导致 h3 比 h2 还抢眼):
* ① 字号与字重**同时**严格递减:24>20>17>16、700>600>500>350;
* ② 装饰强度也递减:蓝条+灰底 > 蓝条+细线 > 无 > 无。
* 任一级调了,必须回头核对相邻两级的下行关系,别只盯自己那一级。
*
* 为什么 h3 竖线用 3px 而不是 h2 的 5px:同族但更轻,一眼能看出次一级。
* 为什么 h3 不加底色:h2 已经有灰底,h3 再铺一层整篇会碎成一块块。
* 为什么 h4 用 500 而不是 600:600 与 h3 同字重,就只剩字号 3px 的差别,
* 视觉上"像同一个级别被缩了一点"。降到 500 后,字重也参与分层。
* 500 仍然明显重于正文的 350(差 150),不会糊回正文里去。
*
* ⚠️ 特异性必须是 (0,4,1) 起步、并把字号/字重一起写死:
* kratos 的 `.k-main .details .article .content h3` 是 (0,4,1),
* 只写 `.article .content h3`(0,2,1)会被它压掉 —— 这在本项目
* 踩过一次(archives.css 里 22px/700 写了两版都没生效,实际一直是 18px/500)。
* 所以这里与 h2 用同一套前缀,并且 font-size / font-weight 都显式声明。 */
.k-main .details .article .content h3 {
margin: 24px 0 16px;
padding: 2px 0 2px 10px;
border-left: 3px solid #00a2ff;
border-bottom: 1px solid #eaedf2;
font-size: 20px;
font-weight: 600;
line-height: 32px;
}
/* ── 正文四级标题:17px / 500(3.2.61 定稿)
*
* 字号 17px 保持不动(h3 20px 之下、正文 16px 之上的唯一合理档位,
* 再往下压到 16px 就与正文同大、层级直接断层)。
* 字重 600 → 500:600 与 h3 完全同重,等于只有 3px 字号差,
* 看着像"同一级被缩小",不像下一级。降到 500 让字重也参与分层。
*
* 不加任何装饰 —— 到第四级再加线就满屏都是线了。 */
.k-main .details .article .content h4 {
margin: 20px 0 12px;
font-size: 17px;
font-weight: 500;
line-height: 30px;
}
/* 🔴 归档页的年份标题也是 `<h3 class="ar-year">`,而且它就在
* `.article .content` 里面([Archives] 是正文短代码)。
* 上面那条 h3 会命中它 —— 于是年份会多出一条左竖线和一条底细线,
* 而 archives.css 里 `.ar-head` 已经有自己的底边线,会变成**两条线**。
*
* 这不是"顺手加个补丁",是必须的:archives.css 的 `.ar-year`
* 靠 (0,5,0) 才压过 kratos,本文件若也用 (0,5,0) 且排在它后面,
* 谁赢就变成"看入队顺序",非常脆。
*
* 这里主动让路:把 ar-year 的装饰清零,尺寸仍交给 archives.css 管
* (它写 26px/700,本规则不碰字号,避免两边抢)。 */
.k-main .details .article .content h3.ar-year {
padding: 0;
border-left: 0;
border-bottom: 0;
margin: 0;
}
/* ── 正文标题的自动编号(3.2.62 / 工单 #30)
*
* 结构由 PHP 插入:<h2 id="x"><span class="yang-h-num">1.1</span>标题</h2>
* 编号是**独立 span**,不是改标题文本 —— 所以不进编辑器、不进 RSS、
* 不进搜索结果、不进摘要。作者手写编号时压根不插这个 span。
*
* ── 为什么用灰色(用户选定的方案)──────────────────────────────
* 标题的核心是**文字本身**,编号只是索引辅助。若与标题同色同粗,
* 视觉上"1.1"会和标题正文抢注意力,长文章里满屏都是数字。
* 灰色 + 字重 400 让编号退到背景,眼睛扫标题时能忽略它、需要定位时
* 又能看见 —— 这也与目录里 `.yang-toc-num` 的处理一致,
* 正文和目录的编号看起来是同一套东西。
*
* ── 字号是 1em(与标题完全同大,3.2.63 起)────────────────────
* 🔴 0.62em 那一版**用户否掉了**:「字体不能太小,要不然很不协调,看着难受」。
* 实测 0.62em 在 h2 上是 14.88px、而标题 24px —— 差 9px,比例失衡,
* 编号像"贴在标题边上的小注脚",不像标题的一部分。
* 改成 1em 之后:h2 编号 24px、h3 20px、h4 17px,与标题逐级同大。
* 弱化只靠**颜色 + 字重**(灰 #a8abb2 / 400),不靠缩字号。
*
* ⚠️ 换成 1em 有个连带项:`margin-right` 原来是 0.35em,
* 而 em 是相对**编号自身**字号的。字号从 14.88 → 24 后,
* 同一个 0.35em 会从 5.2px 变成 8.4px,间距明显偏大。
* 所以同步收到 **0.25em**(24px ⇒ 6.0px、20 ⇒ 5.0px、17 ⇒ 4.25px),
* 与原来 5.2px 的观感基本一致。
*
* ── font-weight / font-style 必须显式重置 ────────────────────
* span 会继承标题的 font-weight(700/600)和可能的斜体。
* 不重置的话"灰色但加粗"仍然很重,弱化就白做了。
*
* ── 🔴 为什么仍保留 `display: inline-block` ────────────────────
* 这一条最初是为了修「小字号撑高行盒」,字号改成 1em 之后
* **同字号本身已经不撑高了**(实测 inline + inherit 也是 46px)。
* 但仍然保留,两个理由:
* ① 防回归 —— 以后谁把字号改回小号,不会立刻复发 3px;
* ② 编号成为原子盒,永远不跨行断开,始终贴在标题第一行开头。
*
* 下面是当时那个 3px 问题的完整记录,留着是因为**修法不直观**:
* 小字号的行内元素会把行盒**撑高**,实测 h2 46 → **49px**、h3 37 → **40px**,
* 每级都多 3px。3px 不起眼,但它出现在**每一个**标题上:长文 10 个二级标题
* 就多出 30px,h2 的灰底跟着变高,整篇标题的节奏全变;更麻烦的是它**只在
* 该标题有编号时出现**,于是「有编号的文章」和「没编号的文章」行距不一致,
* 极难归因。
*
* ⚠️ 我先试过 `line-height: inherit`(以及写死 46px)—— **完全无效**,
* 仍 49px。原因值得记下来,因为直觉是反的:
*
* 同行高下,行内盒的上下边界由「半行距」决定,而半行距
* 把 content-area **居中**塞进 line-height:
*
* 盒底 = baseline + desc×fs + (L − fs) / 2
* h2 (fs=24, L=46): 0.25×24 + (46−24)/2 = 17.00
* span(fs=14.88,L=46): 0.25×14.88+ (46−14.88)/2 = 19.28 ← 多探 2.28
*
* **字号越小,半行距越大**,盒底反而越往下走。所以「让两者共用行高」
* 不是解药,恰恰就是病根 —— line-height 怎么调都救不回来。
*
* ⚠️ `vertical-align` 也试过:`baseline` 仍 49px;`middle` 48.52px。
*
* ✅ 真解:把编号变成**原子行内盒**(inline-block),它就只按自身内容
* 高度参与行盒,不再受半行距拉扯。配 `line-height: 1` 让盒高正好
* 等于字号(14.88px),基线落在 asc 处 —— 上下都远在 strut 之内,
* 实测 h2 46→**46**、h3 37→**37**,一分不多。
* (八组隔离试验的完整数据见 `_tooling/yang_theme_test/_diag362b.js`。)
*
* 副作用检查:inline-block 不会跨行断开 ⇒ 编号永远留在标题第一行开头,
* 正是想要的;`white-space: nowrap` 随之只作用于这个原子盒,不会影响标题文字。
*
* ⚠️ 归档页 `h3.ar-year` 同样不会带编号 —— 编号是在 the_content
* 过滤器里按「目录条目」插的,而归档短代码的年份标题不在
* yang_toc_scan() 的结果里(它们是 [Archives] 渲染时才产生的),
* 所以天然不受影响。评论区 h3 同理(不在 .content 内)。 */
.k-main .details .article .content .yang-h-num {
/* 🔴 原子行内盒:不参与行盒的半行距计算,标题高度才不会被撑高(见上)
*
* 3.2.63:字号改成 1em(与标题同大)。用户反馈 0.62em 太小、"很不协调"。
* 实测同字号之后,inline / inherit 也不会撑高了(撑高本来就是小字号的
* 半行距造成的,字号一致时半行距也一致)。但 display 仍保留 inline-block:
* ① 防回归 —— 以后若有人把字号改回小号,不会立刻复发 3px 问题;
* ② 编号变成原子盒,永远不会跨行断开,始终贴着标题第一行开头。 */
display: inline-block;
line-height: 1;
/* 🔴 margin-right 是相对**编号自身**字号的(0.35em 在 14.88px 时是 5.2px)。
* 字号改成 1em 后同一个 0.35em 会变成 8.4px,间距明显偏大 ⇒ 同步收到 0.25em
* (24px 标题 ⇒ 6.0px,20px ⇒ 5.0px,17px ⇒ 4.25px,与原来的观感接近)。 */
margin-right: 0.25em;
color: #a8abb2;
font-size: 1em;
font-weight: 400;
font-style: normal;
/* 数字等宽,1.1 和 3.10 宽度一致,多行标题才不会看着参差 */
font-variant-numeric: tabular-nums;
/* 编号自身不换行(inline-block 本来也不拆,写上是为了并列时也不拆) */
white-space: nowrap;
}
/* 暗色站点:跟目录序号同一个灰,否则 #a8abb2 在深色底上过亮 */
html.yang-dark .k-main .details .article .content .yang-h-num {
color: #767d88;
}
/* 列表缩进与行距 */
ul {
margin-left: 2em;
}
ol {
margin-left: 2em;
}
ol > li {
line-height: 1.8;
}
ul > li {
line-height: 1.8;
}
/* ══════════════════════════════════════════════════════════════════
* 容器宽度:改为流式(工单 #31)
*
* ── 改之前是什么样(线上实测,Playwright 逐 1px 扫 320~1920)──────
* Bootstrap 的 `.container` 只有 **4 个固定 max-width 档位**:
*
* 视口 576~767 → 容器 540px 单边留白 18~113.5px
* 视口 768~991 → 容器 720px 单边留白 24~135.5px
* 视口 992~1309 → 容器 960px 单边留白 16~174.5px
* 视口 1312~1920 → 容器 1280px 单边留白 16~320px
*
* 每个档位内宽度**完全不变**,于是窗口越宽、两侧空白越宽;跨过断点
* 宽度瞬间跳一格,留白突变 89.5 / 119.5 / 158.5px —— 这就是用户说的
* 「一蹦一蹦」「某些固定宽度下两边有两个非常宽的空白」。
*
* 根本问题不是"断点太少",而是**容器宽度本身只有 4 个取值**。
* 加密断点只是让台阶小一点,仍然是台阶。
*
* ── 现在怎么算 ─────────────────────────────────────────────────
* 用 **min()** 让宽度连续跟随视口、到上限后居中:
*
* width: min(1440px, 100% - 2×边距)
*
* · 视口窄时 → `100% - 边距` 生效,宽度随窗口连续变化,两侧永远只有
* 固定边距(不留大空白);
* · 视口宽到某个点 → `1440px` 生效,超出部分居中留白,正文不会无限拉长。
*
* 两个分支在交界处**数值相等**(1440 + 2×边距),所以过渡是**连续的**,
* 没有台阶、没有突变。这是 min() 相比 media query 的本质优势:
* media query 是**离散判断**,min() 是**连续取值**。
*
* ⚠️ 上限 1440px 是用户选定的(工单 #31)。原来 Bootstrap 最高到 1280,
* 1920 屏上单边空 320px;改 1440 后 1920 屏单边空 240px,同时正文
* 依然有足够的宽度可读性。
*
* ⚠️ 边距用 `max(16px, 2.5vw)` 而不是定值:窄屏保证 16px 不被吃掉
* (手机上贴边很难看),宽屏略微增加,与视口更协调。2.5vw 在 1440
* 视口时 = 36px,正好让上限分支的边距看起来不突兀。
*
* 🔴 三条规则都要,缺一条就前功尽弃:
* ① `.container` 基础规则 —— 覆盖 Bootstrap 的 `width:100%` 与 4 个
* `max-width` 档位(后者全在 `@media (min-width:…)` 里,优先级
* (0,1,0) 与基础规则相同,靠**后加载**取胜,见下方说明);
* ② 页面上有 **3 个** `.container`(导航 / 主内容 / 页脚),
* 必须同一条规则覆盖,否则导航和页脚会跟正文错位;
* ③ `max-width` 必须显式设成 `none`,否则 Bootstrap 的
* `@media (min-width:576px){.container{max-width:540px}}` 依然生效
* —— 它和我们的基础规则同优先级,而 media query 里那条**更晚**
* 出现在 bootstrap.min.css 里;我们虽然在 site.css(更晚加载),
* 但 `max-width` 那条属性必须被我们**显式声明**才能压住。
*
* 加载顺序(inc/theme-core.php):bootstrap → kratos.min → **site.css**,
* 所以同优先级下 site.css 胜出。
* ⚠️ 不要用 `!important`:Bootstrap 里 `@media print` 有一条
* `.container{min-width:992px!important}` 是打印用的,我们改的是
* `width`/`max-width`,不冲突;一旦上 `!important` 反而会与打印样式
* 打架。 */
.container {
/* 宽度 = min(上限, 视口 - 两侧边距)。连续取值,无台阶。 */
width: min(1440px, 100% - 2 * max(16px, 2.5vw));
/* 🔴 必须显式覆盖 Bootstrap 的 4 个 max-width 档位(540/720/960/1280) */
max-width: none;
/* 左右 auto 居中:窄屏时 width 已经等于可用宽度,auto 不产生额外偏移;
宽屏时 width 封顶 1440,auto 把剩余空间均分到两侧。 */
margin-right: auto;
margin-left: auto;
/* Bootstrap 原来是 15px;这里改由 width 的边距项承担,
否则会**双重扣减**(padding 15 + width 里再扣一次边距),
窄屏上内容被吃掉 30px。 */
padding-right: 0;
padding-left: 0;
}
/* 栅格行原本用 margin:-15px 抵消 container 的 15px padding。
现在 container 的 padding 已经是 0,这 -15px 会把内容**往外顶** 15px、
直接溢出容器右侧。所以同步归零。
(`.row` 只出现在 .k-main 里,导航/页脚没有 .row,不必担心误伤。) */
.k-main .row {
margin-right: 0;
margin-left: 0;
}
/* 列自身的 15px padding 保留:它是"两列之间的间隙"来源,
归零会让正文和侧栏贴在一起。这里显式声明是为了说明意图 ——
不管 Bootstrap 以后怎么改,这一条的语义是明确的。 */
.k-main .row > [class*="col-"] {
padding-right: 15px;
padding-left: 15px;
}
/* 🔴 导航里的 container 要单独补偿(实测才发现)
*
* `.k-nav` 同时带着 Bootstrap 的 `.navbar` 类,而 `.navbar` 有
* `padding-right/left: 16px`。所以导航里的 container 是嵌在**已经内缩
* 16px** 的盒子里的:
*
* 视口 1440:正文 container 宽 1368 左 36
* 导航 container 宽 1336 左 52 ← 比正文窄 32、右移 16
*
* 改之前两者都是 Bootstrap 的 1280px 固定档位、都被居中,宽度一致,
* 这个 16px 内缩只表现为"导航比正文稍微靠里一点",不明显。
* 改成流式后上限提高、位置随视口走,16px 的相对偏差就突出了,
* 导航栏的 logo/菜单会与正文左边缘对不齐。
*
* 解法见下方规则体内注释(用同一套 width 公式 + **margin:auto 居中**;
* 我最初的两版负 margin 方案都是错的,原因记在下面)。
* ⚠️ 不能给 `.k-nav` 直接 `padding:0` —— 那是 Bootstrap 给所有 navbar 的
* 统一内边距,小屏折叠态下菜单面板依赖它,去掉会贴边。 */
.k-nav > .container,
.k-nav .navbar > .container {
/* 导航里的 container 要和正文**逐像素对齐**。
*
* 难点:`.k-nav` 同时带 Bootstrap 的 `.navbar`,而它左右各有 16px padding。
* 直接用 `width: min(1440px, 100vw - 边距)` 会得到正确**宽度**,但
* 位置差 16px(父级内缩没被算进去)。
*
* 正确做法:用**与正文完全相同**的公式算宽度,然后**不要**加负 margin,
* 让 `margin: auto` 在这 16px 内缩的盒子里居中。数学上刚好抵消:
*
* 视口 1440:navbar 内容框 1408,容器 1368,auto ⇒ 左 = 16+(1408-1368)/2 = 36 ✅
* 视口 1920:navbar 内容框 1888,容器 1440,auto ⇒ 左 = 16+(1888-1440)/2 = 240 ✅
*
* 🔴 前两版都错在这里,值得记下:
* ① 用 `100%` + `calc(… + 32px)` + 负 margin ⇒ `100%` 在绝对定位的
* `.k-nav` 里解析成**视口宽**,结果满宽 320@0;
* ② 用 `100vw` 公式 + `margin-left/right: -16px` ⇒ 宽度对了,但负 margin
* 把容器顶到父级 padding **之外**,左 = 0 而不是 36。
* 负 margin 是"抵消父级内缩"的思路,但抵消之后就不再居中;
* 真正要的是"在已内缩的盒子里按比例居中"。 */
width: min(1440px, 100vw - 2 * max(16px, 2.5vw));
margin-right: 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;
}