fix(theme): 内容块宽度改为流式取值 + 1440px 封顶,消除档位跳变(#31)

现象:窗口从宽拖窄时,中间内容块宽度离散跳档(540/720/960/1280 四档),
档内两侧留白极宽 —— 1920 视口每边白 320px,占整个窗口约 1/3。

根因:bootstrap.min.css 的 .container 只有 4 个固定 max-width 档位,
档内宽度恒定不变,跨断点瞬间跳一格。不是"断点太少",而是宽度只有 4 个取值。

改法(assets/css/site.css +134 行):

1) .container 宽度改成连续函数
     width: min(1440px, 100% - 2 * max(16px, 2.5vw))
   min() 是连续取值,@media 是离散判断 —— 这是两者的本质区别。
   上限 1440 由用户选定;边距 max(16px, 2.5vw) 做窄屏保底 + 宽屏按比例。
   同时 max-width: none 显式压掉 Bootstrap 的 4 个档位(缺它宽屏仍被
   1280 卡住,等于没改)。

2) padding 归零 + .row 负 margin 同步归零
   Bootstrap 原本靠 container 的 15px padding 与 .row 的 -15px margin 相互
   抵消。现在边距由 width 公式承担,padding 必须归零(否则双重扣减,
   窄屏吃 30px);.row 的 -15px 也必须归零(否则内容外顶 15px、贴到容器边)。
   列自身的 15px padding 保留,它是两列间隙的来源。

3) 导航容器单独对齐(三版才修对)
   .k-nav 同时带 Bootstrap 的 .navbar,左右各有 16px padding,容器嵌在
   已内缩的盒子里。直接用正文公式会得到正确宽度但差 16px 位置。
   正确解是同公式 + margin:auto 在已内缩的盒子里居中。
   两个失败版本记在注释里:① calc(100% + 32px) 因 100% 在绝对定位盒里
   解析成视口宽 ⇒ 满宽 320@0;② 负 margin 把容器顶到父级 padding 之外
   ⇒ 左边缘变 0 而非 36。

验证(_tooling/yang_theme_test/,均为线上真实页面 + 拦截替换待发布 CSS):

- _diag_width3.js 改前定量:4 档平台 540×192 / 720×224 / 960×318 / 1280×609,
  跳变 89.5/119.5/158.5px,1920 视口 521 个宽度留白 ≥60px
- _geom31.js 16/0:逐 1px 扫 320~1920 共 1601 档,W1 无固定档位(唯一平台
  1440 封顶段)、W2 单步 ≤2px(实测 1px)、W3 单调、W4 封顶 1440 且对称、
  W5 留白 ≤40px、W6 无横向溢出、W7 三容器一致、W8 正文占比 66.7%、
  W9 正文缩进 15px;四条反证全部红在预期条目
- _shot31.js 33/0:7 档截图 + 表格/代码/图片不溢出、页脚同宽、目录块不越界、
  暗色模式,另含 V4b 防空靶子守卫
- _align31.js 5/0:导航/正文/页脚容器左边缘逐像素一致,logo 与首段偏移
  -31px 跨 7 档零漂移
- _mkzip364.py 43/0 + _mkzip364_falsify.py 11/0(10 条注入全部命中)

侧栏行为按用户要求保持现状(992px 以下隐藏、正文整行),该处宽度变化
是侧栏出现/消失导致,非台阶,不在本版范围。

Refs #31
This commit is contained in:
2026-10-28 09:28:06 +08:00
parent 0c8cee9094
commit ac1575fbbb
2 changed files with 135 additions and 1 deletions
+134
View File
@@ -338,3 +338,137 @@ ol > li {
ul > li { ul > li {
line-height: 1.8; 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;
}
+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.63 Version: 3.2.64
Requires PHP: 7.0 Requires PHP: 7.0
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好