From ac1575fbbbcc3e7585f0e4058439dcd71939bdec Mon Sep 17 00:00:00 2001 From: laoyang Date: Wed, 28 Oct 2026 09:28:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(theme):=20=E5=86=85=E5=AE=B9=E5=9D=97?= =?UTF-8?q?=E5=AE=BD=E5=BA=A6=E6=94=B9=E4=B8=BA=E6=B5=81=E5=BC=8F=E5=8F=96?= =?UTF-8?q?=E5=80=BC=20+=201440px=20=E5=B0=81=E9=A1=B6=EF=BC=8C=E6=B6=88?= =?UTF-8?q?=E9=99=A4=E6=A1=A3=E4=BD=8D=E8=B7=B3=E5=8F=98=EF=BC=88#31?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象:窗口从宽拖窄时,中间内容块宽度离散跳档(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 --- assets/css/site.css | 134 ++++++++++++++++++++++++++++++++++++++++++++ style.css | 2 +- 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/assets/css/site.css b/assets/css/site.css index 29a7986..af5723e 100644 --- a/assets/css/site.css +++ b/assets/css/site.css @@ -338,3 +338,137 @@ ol > li { 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; +} diff --git a/style.css b/style.css index 419bfa0..49b4677 100644 --- a/style.css +++ b/style.css @@ -1,7 +1,7 @@ /* Theme Name: Kratos_Yang Text Domain: kratos_Yang -Version: 3.2.63 +Version: 3.2.64 Requires PHP: 7.0 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好