From f5fd363dced87271949d16e384b66cdd704c7359 Mon Sep 17 00:00:00 2001 From: laoyang Date: Tue, 27 Oct 2026 13:00:37 +0800 Subject: [PATCH] =?UTF-8?q?fix(widgets):=20=E5=88=86=E7=B1=BB=E6=8C=82?= =?UTF-8?q?=E4=BB=B6=E6=94=B9=E6=88=90=E3=80=8C=E7=82=B9=E5=BC=80=E6=89=8D?= =?UTF-8?q?=E5=8D=A0=E4=B8=80=E8=A1=8C=E3=80=8D=E7=9A=84=E4=B8=8B=E6=8B=89?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=20#24?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 需求改判:3.2.54 做的「父级常显 + 子级折叠树」被否,用户要的是 「不点只有一行,点开把所有一级分类拉出来」的真下拉面板。 ## 改了什么 - widget() 重写:`
` + `` 触发条 + `position:absolute` 浮层面板。收起时整个挂件只占一行(40.5px), 展开时面板盖在下方内容上,不把后面的挂件推走。 - children 兜底值 true → false。线上实例的配置里本来没有这个键, 所以走 pick() 兜底 ⇒ 改兜底就等于改线上行为,用户零操作即变成 「只列一级分类」,不用进后台勾一次。 - 子级不再嵌套
(3.2.54 是嵌套)。现在父级与子级的 DOM 结构完全一致,3.2.54 那个「space-between 推不动、数字右边界差 7.1px」的缺陷从结构上消失了,不需要 flex:1 补丁。 - 补一段渐进增强脚本,只做「点外部收起 / Esc 收起并还焦点」两件事, 不接管开合本身(关掉 JS 仍能正常展开跳转)。 - CSS:.w-cats 区块整块重写。修掉子级 li 右内边距叠加的缺陷 —— 子级 ul 嵌在已 padding:0 12px 的父级 li 里,子级 li 又写了一遍 右内边距 ⇒ 叠加成 24px,导致子级数字比父级多缩进 12px、父子排不成 一列,竖着比大小时会错位。改成 0 后父子数字同列。 - style.css 版本号 3.2.54 → 3.2.55(3.2.54 已落过 update.json, 同号重发会让 WP 的 version_compare 判「没有新版本」)。 ## 验证 - 端到端(线上真实 WordPress,96 项):全通过 - 反证:内容判据 12 组 + 端到端 3 组,全部真红,无一组空跑 - 视觉几何(真实浏览器 50 项):全通过 - 上一版(3.2.53)老代码跑同一套端到端判据:88 项失败 - 包内 PHP lint 96 个全过;zip 无 1980 时间戳(防 OPcache 误判) ## 发布 只写 theme-update/:zip + readme + update.json → 3.2.55。 线上主题目录仍是 3.2.54,等用户在后台点升级(红线)。 --- assets/css/kratos.css | 459 ++++++++++++++++++++------------------ assets/css/kratos.min.css | 2 +- inc/theme-widgets.php | 199 ++++++++++++----- style.css | 2 +- 4 files changed, 388 insertions(+), 274 deletions(-) diff --git a/assets/css/kratos.css b/assets/css/kratos.css index 0f242c0..9b54f6a 100644 --- a/assets/css/kratos.css +++ b/assets/css/kratos.css @@ -2072,7 +2072,7 @@ button:focus { } /* ══════════════════════════════════════════════════════════════════════ - * 「文章分类」挂件(.w-cats)(3.2.54 / 工单 #24) + * 「文章分类」挂件(.w-cats)(3.2.55 / 工单 #24) * * ── 它为什么要重做 ──────────────────────────────────────────────────── * 原来侧栏跑的是 WP 核心 `WP_Widget_Categories`,实例配置 `dropdown = 1`, @@ -2081,237 +2081,263 @@ button:focus { * 更糟的是主题里那套 `.widget_categories ul li` 规则只匹配 `ul`, * 下拉框里没有 `ul` ⇒ **写了也一条不生效**。 * - * 现在改成主题自建的父子折叠树,和 `.w-comments` / `.w-tags` 同一套视觉。 + * 3.2.54 先改成「父级常显 + 子级折叠树」,8 个父级铺开占约 300px 侧栏高度, + * 被用户否决。3.2.55 改成**真下拉面板**:收起一行、点击弹出、默认只列一级。 + * 形态回到"类似原来的 select",但外观是自己画的,能统一到侧栏视觉。 * * ── 一条硬约束(3.2.51 的教训,别再踩)──────────────────────────────── * 🔴 选择器**只依赖 `.w-cats` 自身**,绝不写 `.k-main .sidebar .w-cats`。 * 3.2.51「个人简介撑爆」就是三段祖先选择器造成的:挂件在后台 * 「外观→小工具」的预览里没有 `.k-main .sidebar` 那层,规则全部失效。 * 前台看着正常,恰恰把问题藏死。 - * 🔴 所以这里**不写内边距/白底**:那由外层 `.widget` 提供 + * 🔴 所以这里**不写外边距/白底**:那由外层 `.widget` 提供 * (前台 `.k-main .sidebar .widget`,后台由 WP 自己的挂件容器提供)。 * - * ── 视觉层级 ────────────────────────────────────────────────────────── - * 父分类 15px #333 ← 主体,带折叠箭头 - * 子分类 14px #666 ← 比父级轻一档,靠左侧缩进 + 细线表示从属 - * 计数 12px #bbb ← 最轻,右对齐;父级数字含子级(pad_counts) - * 三层字号必须不同 —— 一样大的话 29 个分类会糊成一片,找不着重点。 + * ── 浮层凭什么不被裁掉(实测过,不是猜的)───────────────────────────── + * `.w-cats` 本身就是那个 `.widget`(类名是 `widget w-cats` 两个)。 + * 它、`.sidebar`、`.k-main` 都**没有** `overflow` 声明; + * `body { overflow-x: hidden }` 只管横向,纵向裁剪不影响面板。 + * ⇒ 面板可以溢出挂件边界往下盖。 + * 🔴 若将来给 `.widget` 加上 `overflow:hidden`,面板会被整块切掉 —— + * 这条写在这里就是给那时候看的。 * ══════════════════════════════════════════════════════════════════════ */ -.w-cats .yang-cat-list { +/* 定位锚点:面板要相对「触发条」定位,所以
必须是 containing block。 + * 🔴 不能省:缺了它,面板的 absolute 会一路往上找到最近的定位祖先, + * 最坏情况直接贴到视口(`position:absolute` 的包含块规则), + * 面板会飘到页面左上角去。 */ +.w-cats .yang-cats-drop { + position: relative; +} + +/* ── 触发条(收起时唯一可见的一行)────────────────────────────────── */ +.w-cats .yang-cats-trigger { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 12px; + border: 1px solid #e7e7e7; + border-radius: 3px; + background-color: #fbfbfb; + color: #333; + font-size: 15px; + line-height: 1.5; + cursor: pointer; + list-style: none; /* 关掉原生三角 marker(Firefox 认这个) */ + -webkit-transition: border-color 0.2s, background-color 0.2s; + transition: border-color 0.2s, background-color 0.2s; + /* 关掉长按选中:手机上点开面板时容易顺手把文字选中,很碍事 */ + -webkit-user-select: none; + user-select: none; +} + +/* Chrome/Safari/Edge 的原生三角 marker 走这个伪元素,不是 list-style */ +.w-cats .yang-cats-trigger::-webkit-details-marker { + display: none; +} + +.w-cats .yang-cats-trigger:hover { + border-color: #00a2ff; + background-color: #fff; +} + +/* 展开时:触发条与面板连成一体(下边圆角收掉、下边框交给面板) */ +.w-cats .yang-cats-drop[open] > .yang-cats-trigger { + border-color: #00a2ff; + border-bottom-color: transparent; + border-radius: 3px 3px 0 0; + background-color: #fff; + color: #00a2ff; +} + +/* 长分类名:允许任意位置换行(中文没有空格),但不许把箭头挤走 */ +.w-cats .yang-cats-label { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + overflow-wrap: break-word; +} + +/* 箭头:CSS 画的三角,展开时翻 180°。 + * + * 🔴 为什么不用字体图标:主题的 kicon 字体只含固定几个字形, + * 加一个要动字体文件;而这个三角用边框就能画, + * 也不会因字体没加载而"箭头消失"。 */ +.w-cats .yang-cats-caret { + flex: 0 0 auto; + width: 0; + height: 0; + margin-left: 8px; + border-top: 5px solid #999; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + -webkit-transition: -webkit-transform 0.2s; + transition: transform 0.2s; +} + +.w-cats .yang-cats-trigger:hover .yang-cats-caret, +.w-cats .yang-cats-drop[open] > .yang-cats-trigger .yang-cats-caret { + border-top-color: #00a2ff; +} + +.w-cats .yang-cats-drop[open] > .yang-cats-trigger .yang-cats-caret { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} + +/* ── 面板 ────────────────────────────────────────────────────────────── + * + * 🔴 `position: absolute` 是「不推开下面挂件」的关键。 + * 若写成 static/relative,展开时整块侧栏往下跳,页面会抖。 + * + * 🔴 必须显式写 `:not([open]) .panel { display:none }`,不能只靠浏览器默认。 + * 实测背景:`
` 收起时浏览器确实不渲染非 summary 子元素, + * 但那属于 UA 样式;一旦面板带 `position:absolute`,某些引擎会把 + * "未渲染"与"不参与布局"混起来处理,历史上出现过收起状态仍能 + * 被 Tab 聚焦到的情况(焦点跑到看不见的链接上)。显式关掉最稳。 + * + * 🔴 `z-index: 20`:主题里更高的只有页脚工具箱的 999(fixed 定位, + * 在页面右下角,与侧栏不重叠)和 banner 的 10。 + * 面板要盖住**后面那些挂件**,所以必须建立自己的堆叠层级。 */ +.w-cats .yang-cats-panel { + position: absolute; + top: 100%; + right: 0; + left: 0; + z-index: 20; + max-height: 320px; + overflow-x: hidden; + overflow-y: auto; + border: 1px solid #00a2ff; + border-top: none; + border-radius: 0 0 3px 3px; + background-color: #fff; + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); + /* iOS 上惯性滚动才顺滑 */ + -webkit-overflow-scrolling: touch; +} + +.w-cats .yang-cats-drop:not([open]) .yang-cats-panel { + display: none; +} + +/* ── 列表与行 ────────────────────────────────────────────────────────── + * + * 🔴🔴 必须重置主题自己的全局 `ul > li`(kratos.css:74): + * + * ul > li { margin-bottom: 6px; padding-left: 2px; + * list-style: circle; line-height: 22px; } + * + * 这一条 3.2.54 是"线上量坐标"才发现的:光看代码很难想到, + * 因为它的特异性 (0,0,2) 看着很弱、而且名字里只是 `ul > li`。 + * 不重置的后果都能量出来: + * ① 每行多 6px 下边距,9 行累积 54px —— 面板虚高、滚动条提前出现; + * ② 每行左边多 2px,名字与触发条的文字**对不齐**(差 2px); + * ③ `list-style: circle` 会让每行前面多个圆点; + * ④ `line-height: 22px` 会顶掉组件的 1.5。 + * + * ⇒ 在这个组件的每一层 `li` 上都重置,不靠 `:not()` 分叉。 + * 3.2.54 正是只在 `:not(.has-children)` 上重置,导致带子级那行漏网。 */ +.w-cats .yang-cats-list, +.w-cats .yang-cats-children { margin: 0; padding: 0; list-style: none; } -/* 首层每一行:让「名字 · 数字」两端对齐。 - * - * 🔴🔴 这里踩过一个真坑,记清楚 —— 两种行的 DOM 结构**不一样**: - * - * 无子级:
  • - * 名字 - * 12 ← a 的**兄弟** - *
  • - * 有子级:
  • - *
    - * - * 名字 ← 都是 summary 的**子项** - * 120 - * ...
    - *
  • - * - * 我第一版把 flex 写在 `.yang-cat-item > .yang-cat-link` 上(也就是 `` 自身), - * 结果无子级那一行里**只有 `` 变成 flex 容器,而它内部只有一个文本节点**, - * 于是 `space-between` 没有第二个子项可推 —— 数字留在原地紧贴文字, - * 实测右侧间隙 299px、行高被撑到 36.5px(数字挤到下一行)。 - * - * ⇒ 正确做法:flex 必须加在**同时包含名字和数字的那一层**, - * 也就是 `
  • `(无子级)与 ``(有子级)。 - * - * 🔴🔴 还要**重置主题自己的全局 `ul > li`**(kratos.css:74)—— - * 这条是 3.2.54 实测抓出来的,光看代码很难想到: - * - * ul > li { margin-bottom: 6px; padding-left: 2px; - * list-style: circle; line-height: 22px; } - * - * 它的特异性是 (0,0,2),而我们 `.w-cats .yang-cat-item` 是 (0,2,0), - * 本来能压过 —— 但 `padding-left` / `margin-bottom` 那几条 - * **只写在了 `:not(.has-children)` 上**,带子级的 `
  • ` 完全没被覆盖: - * - * 实测(线上真实页面注入新 DOM 后 getComputedStyle): - * 无子级 li display:flex pl:0px mb:6px - * 有子级 li display:list-item pl:2px mb:6px ← 没被覆盖 - * - * 后果有两个,都是线上能看出来的: - * ① 每行之间多出 6px 空隙,8 行累积 42px —— 行距看着松散、不齐; - * ② 有子级那行名字被推开 2px,与无子级行**对不齐**(实测 30 vs 45, - * 其中 13px 是箭头按设计占的宽度,剩下 2px 就是这个 padding)。 - * - * ⇒ 改成在 `.yang-cat-item` 上统一重置,不靠 `:not()` 分叉。 - * 这样两种行基线一致,将来加第三层结构也不会漏。 */ -.w-cats .yang-cat-item { - margin-bottom: 0; - padding-left: 0; - list-style: none; - /* `
  • ` 的 line-height 也被全局规则钉成 22px,这里跟上组件字号 */ - line-height: 1.5; -} - -/* 两种行都要成为 flex 容器,名字与数字分居两端。 - * 🔴 用 `display:flex` 覆盖 `list-item` 会**同时**干掉圆点标记 - * (list-item 是唯一能显示 marker 的 display 值), - * 所以这里不再需要额外写 list-style-type:none 去压 circle。 - * 🔴 上下 padding 不在这里给:带子级的行由 自己撑(它也写了 - * 7px),两处都写会变成 14px,行高直接翻倍。分开写在下面。 */ -.w-cats .yang-cat-item { +.w-cats .yang-cats-item { display: flex; align-items: center; justify-content: space-between; + margin-bottom: 0; + padding: 0; + list-style: none; + line-height: 1.5; } -/* 只有「无子级」和「子级」这两种叶子行需要自己撑上下间距 */ -.w-cats .yang-cat-item:not(.has-children) { - padding: 7px 0; -} +/* 🔴 这一版的 DOM 结构**统一了**,这是相对 3.2.54 的一处实质改进: + * + * 父级:
  • 名字数字
  • + * 子级:
  • 名字数字
  • + * + * 两者一字不差,都是「 + 两个直接子项」,flex 加在 li 上 + * 就能两端对齐,不需要区分有没有子级。 + * + * 3.2.54 那版父级行是 `
  • `, + * li 里只有 **一个** flex 子项 `
    `,而 `
    ` 默认宽度 + * auto(按内容收缩)⇒ `space-between` 没有第二个子项可推 ⇒ 数字 + * 右边界比其他行短 7.1px(实测 [220.5,220.5,227.6,227.6,220.5])。 + * 当时的修法是给 `
    ` 加 `flex:1 1 auto; min-width:0`。 + * 现在没有嵌套详情框了,**那个 bug 从结构上就不存在了**。 */ -/* 行内文字(无子级 li 里的 a、有子级 summary 里的 a): - * 只负责字号/颜色/可换行,**不再**做 flex 容器。 */ -.w-cats .yang-cat-item > .yang-cat-link { +.w-cats .yang-cats-list > .yang-cats-item > .yang-cats-link { min-width: 0; color: #333; font-size: 15px; line-height: 1.5; text-decoration: none; - /* 中文长分类名没有空格,必须允许任意位置换行,否则撑破挂件 */ + /* 中文长分类名没有空格,必须允许任意位置换行,否则撑破面板 */ overflow-wrap: break-word; word-wrap: break-word; } -.w-cats .yang-cat-item > .yang-cat-link:hover { - color: #00a2ff; +/* 行内点击热区:把内边距放在
  • 上而不是 上, + * 这样点在行尾空白处也算点中这一行( 只有文字宽度时热区很窄)。 + * 🔴 但 撑不满只剩一半,所以让 吃满左侧空间: + * 数字是固定宽的胶囊, 用 flex:1 占其余全部宽度。 */ +.w-cats .yang-cats-list > .yang-cats-item { + padding: 0 12px; } -/* ── 折叠容器 ────────────────────────────────────────────────────────── */ - -/* 🔴 默认带 display:list-item 与三角形 marker。 - * 我们要自己的箭头(用 CSS 画,不依赖字体图标), - * 所以先关掉原生 marker —— 两个都显示会变成"双箭头"。 */ -.w-cats .yang-cat-summary { - display: flex; - align-items: center; - padding: 7px 0; - color: #333; - font-size: 15px; - line-height: 1.5; - cursor: pointer; - list-style: none; /* Firefox */ - /* 关掉长按选中,避免手机端点开时误选文字 */ - -webkit-user-select: none; - user-select: none; -} - -.w-cats .yang-cat-summary::-webkit-details-marker { - display: none; -} - -.w-cats .yang-cat-summary:hover { - color: #00a2ff; -} - -/* 🔴🔴 `
    ` 必须显式撑满整行宽度,否则**两种行的数字对不齐**。 - * - * 这是 3.2.54 视觉几何实测抓出来的真缺陷(不是量法问题): - * - * 无子级行( 是 li 的直接子项) 数字右边界 220.5 - * 有子级行(
    包着) 数字右边界 227.6 ← 差 7.1px - * - * 原因:无子级行的 `` 与数字是 li 的**两个** flex 子项, - * `space-between` 把它们推到两端,数字贴右沿。 - * 有子级行的 li 里只有 **一个** flex 子项 `
    `, - * `space-between` 没有第二个子项可推 ⇒ 不起作用; - * 而 `
    ` 默认宽度是 auto(按内容收缩), - * 于是整组靠左,数字停在内文字结尾处。 - * - * ⇒ 给 `
    ` 加 `flex: 1 1 auto; min-width: 0`, - * 让它吃满 li 的可用宽度,内部的 summary 才能把数字推到右沿。 - * `min-width: 0` 不能省:它是 flex 项允许收缩到内容宽度以下的前提, - * 长分类名才能按 overflow-wrap 换行而不是撑破容器(3.2.51 的教训)。 - * - * 这条同时解释了为什么 `` 自己写了 width 也没用 —— - * 父级 `
    ` 收缩了,子级撑满的只是那个收缩后的宽度。 */ -.w-cats .yang-cat-group { +.w-cats .yang-cats-list > .yang-cats-item > .yang-cats-link, +.w-cats .yang-cats-children > .yang-cats-item > .yang-cats-link { flex: 1 1 auto; - min-width: 0; + padding: 8px 0; } -/* summary 里的名字链接:占满剩余宽度,让数字被推到最右 */ -.w-cats .yang-cat-summary .yang-cat-link { - flex: 1 1 auto; - min-width: 0; - color: inherit; - text-decoration: none; - overflow-wrap: break-word; - word-wrap: break-word; +.w-cats .yang-cats-list > .yang-cats-item:hover, +.w-cats .yang-cats-children > .yang-cats-item:hover { + background-color: #f5faff; } -.w-cats .yang-cat-summary:hover .yang-cat-link { +.w-cats .yang-cats-list > .yang-cats-item > .yang-cats-link:hover { color: #00a2ff; } -/* 箭头:CSS 画的实心三角,展开时旋转 90°。 +/* ── 子分类(可选,默认关)────────────────────────────────────────────── * - * 🔴 为什么不用字体图标:主题的 kicon 字体只包含固定的几个字形, - * 加一个要动字体文件;而这是个极简三角形,CSS 边框三角形足够, - * 且不会因字体没加载而"箭头消失"。 */ -.w-cats .yang-cat-caret { - flex: 0 0 auto; - width: 0; - height: 0; - margin-right: 8px; - border-top: 4px solid transparent; - border-bottom: 4px solid transparent; - border-left: 5px solid #bbb; - -webkit-transition: -webkit-transform 0.2s; - transition: transform 0.2s; + * 缩进 + 字号轻一档。不加竖线:3.2.54 加过,但那是"常显树"的视觉语言; + * 在浮层面板里加竖线会让本就不宽的面板更挤,缩进已经足够表达层级。 */ +.w-cats .yang-cats-children { + /* 子级整段缩进 12px,与父级名字错开一档 */ + padding: 0 0 6px 12px; + background-color: #fcfcfc; } -.w-cats .yang-cat-summary:hover .yang-cat-caret { - border-left-color: #00a2ff; +/* 🔴 子级 li 的**右侧**内边距必须是 0,不能跟着父级写 12px。 + * + * 这是 3.2.55 几何实测抓出来的真缺陷(不是量法问题): + * + * 父级数字右边界距面板内沿 12px + * 子级数字右边界距面板内沿 24px ← 多出整整 12px + * + * 原因:子级 `