3.2.18: 清明按节气换算、主题内 [TOC] 目录、重建评论区替代 wpDiscuz
三项功能:
1. 清明不再用固定 04-04
清明是节气,日期在 4/4~4/6 之间浮动。硬编码 04-04 实测 1900-2100
共 201 年里只有 76 年是对的(约 38%)。改为内嵌逐年表换算真实日期,
超出 1900-2100 返回 null 明确放弃,不退化成近似值。
兼容 3.2.17 及以前勾过的 '04-04' 键,升级后勾选不会被静默丢弃。
2. 主题内实现 [TOC]
文章里写 [TOC],该位置输出本文目录,点击跳到对应标题。
在 the_content 优先级 9 处理(早于 wpautop 10 / do_shortcode 11),
保证"补 id"与"扫目录"用的是同一份文本,href 与 id 必然对得上。
嵌套用深度归一化,h1→h3 跳级不会算错层级。
scroll-margin-top 声明式让位,原生锚点/外部 #hash/后退全都生效。
3. 重建评论区
旧实现的问题:列表渲染与 AJAX 渲染各写一份 HTML,已经分叉
(AJAX 返回的新评论没有回复按钮);<li> 被 <div> 包着,嵌套回复错位。
现在统一到 yang_comment_html() 单一渲染函数,列表与 AJAX 只差一个
is-new 类。同时修掉三处真实缺陷:
· 评论项用 flex 会把 <ol class="yang-children"> 当成第三个 flex 项,
子评论跑到父评论右侧、正文被挤到 156px、页面横向溢出 75px —— 改 grid
· 成功提示在 exitReplyMode() 之前设置,被其末尾的 setStatus('','')
擦掉,用户提交成功却看不到反馈 —— 调整顺序
· 窄屏媒体查询打不过深层选择器(媒体查询不增加特异性),
嵌套头像反向变大 —— 补深层覆盖
与 wpDiscuz 解耦:邮件模块不再无条件 return false(那等于永久关掉
notify_postauthor 且不报错);插件在场时不加载主题评论资源,
避免双份表单互抢。
验证:PHP 语法 73/73;_static_qingming 36、_test_toc 53、
_test_comments 62、_test_comments_falsify 17、
_toc_geometry 121、_toc_geometry_falsify 9、
_comments_geometry 98、_comments_geometry_falsify 23,全部 0 失败。
线上端到端 29/0(真实文章渲染目录 + 真实评论数据渲染)。
This commit is contained in:
@@ -0,0 +1,893 @@
|
||||
/*!
|
||||
* 评论区样式
|
||||
* Yongquan Yang <yangyq.net>
|
||||
*
|
||||
* ── 为什么整块重写,而不是在旧样式上改 ──────────────────────
|
||||
* 旧样式的骨架是「头像 float:left + 右侧 margin-left 挤出来」,
|
||||
* 这个结构在三个地方会坏:
|
||||
* · 长昵称/长网址会把头部撑破(float 不定宽容器里没有约束);
|
||||
* · 嵌套回复靠 .children { padding-left:0 } 实现,等于**没有缩进**,
|
||||
* 三层以后完全看不出谁回谁;
|
||||
* · 头像 50px 写死在 img 上,但没有 flex 居中,头像和第一行文字
|
||||
* 基线对不齐(看起来"文字比头像低一点")。
|
||||
*
|
||||
* 所以改用 flex 两列布局:头像固定宽、主体 flex:1,
|
||||
* 并把嵌套缩进做成明确的层级视觉(左侧引导线)。
|
||||
*/
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
1. 区块与标题
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
.k-main .details .comments {
|
||||
margin-top: 16px;
|
||||
padding: 20px 22px 22px;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.k-main .details .post-2 .comments {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.comments-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding-bottom: 14px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.comments-head .title {
|
||||
margin: 0;
|
||||
color: #1f2328;
|
||||
font-weight: 600;
|
||||
font-size: 19px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.comments-jump-form {
|
||||
flex: 0 0 auto;
|
||||
padding: 5px 13px;
|
||||
border: 1px solid #d9e4f5;
|
||||
border-radius: 3px;
|
||||
background-color: #f4f8ff;
|
||||
color: #0b74d1;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
transition: background-color 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.comments-jump-form:hover {
|
||||
border-color: #0b74d1;
|
||||
background-color: #e8f1ff;
|
||||
color: #0b74d1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.comments-closed,
|
||||
.comments-empty {
|
||||
margin: 20px 0 4px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 3px;
|
||||
background-color: #fafbfc;
|
||||
color: #8a9099;
|
||||
font-size: 13.5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
2. 评论列表
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
.yang-comment-list,
|
||||
.yang-children {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.yang-comment-list {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* 顶层评论之间用细分隔线;嵌套评论之间不用,靠缩进区分 */
|
||||
.yang-comment-list > .yang-comment {
|
||||
border-bottom: 1px solid #f5f6f8;
|
||||
}
|
||||
|
||||
.yang-comment-list > .yang-comment:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
3. 单条评论
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
/* 单条评论的布局:头像列 + 主体列
|
||||
*
|
||||
* ⚠️ 这里**必须是 grid,不能是 flex**。
|
||||
* 原因:wp_list_comments 输出的是
|
||||
* <li class="yang-comment">
|
||||
* <div class="yang-comment-avatar">…</div>
|
||||
* <div class="yang-comment-main">…</div>
|
||||
* <ol class="yang-children">…子评论…</ol> ← 也是 li 的直接子元素
|
||||
* </li>
|
||||
* 若 li 用 display:flex,那个 <ol> 就成了**第三个 flex 项**,
|
||||
* 被排到主体右边的同一行里 —— 表现为"子评论跑到父评论右侧"、
|
||||
* 父评论正文被挤成一条、页面出现横向溢出。这是真实渲染量出来的,
|
||||
* 光看代码几乎想不到(flex 项的位置不体现在 li 自己的属性上)。
|
||||
*
|
||||
* grid 用两列:第 1 列 auto(由头像定宽),第 2 列 minmax(0,1fr)
|
||||
* (minmax 的下界 0 是关键,否则长英文/长 URL 会把列撑宽)。
|
||||
* 子评论用 grid-column: 1 / -1 独占下一整行。 */
|
||||
.yang-comment {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
column-gap: 12px;
|
||||
align-items: start;
|
||||
padding: 16px 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* 子评论容器独占整行,排在头像与主体下方 */
|
||||
.yang-comment > .yang-children {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
/* 头像列:固定宽度,不参与伸缩 —— 否则长评论把它挤扁 */
|
||||
.yang-comment-avatar {
|
||||
flex: 0 0 auto;
|
||||
width: 42px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.yang-comment-avatar img,
|
||||
.yang-comment-avatar-img {
|
||||
display: block;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 没有头像时的首字占位 */
|
||||
.yang-comment-avatar-ph {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
background-color: #eef2f7;
|
||||
color: #7c8794;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* 主体列 */
|
||||
.yang-comment-main {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0; /* 关键:让内部的 text-overflow / 换行能生效 */
|
||||
}
|
||||
|
||||
.yang-comment-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.yang-comment-author {
|
||||
color: #252525;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
/* 超长昵称截断,别把时间挤到下一行去 */
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.yang-comment-author a {
|
||||
color: #252525;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.yang-comment-author a:hover {
|
||||
color: #00a2ff;
|
||||
}
|
||||
|
||||
.yang-comment-time {
|
||||
flex: 0 0 auto;
|
||||
color: #a4abb5;
|
||||
font-size: 12.5px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 徽标:作者 / 待审核 */
|
||||
.yang-comment-badge {
|
||||
flex: 0 0 auto;
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
background-color: #eaf3ff;
|
||||
color: #0b74d1;
|
||||
font-size: 11.5px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.yang-comment-badge.is-pending {
|
||||
background-color: #fff6e5;
|
||||
color: #b27412;
|
||||
}
|
||||
|
||||
/* 待审核的整条评论淡化,一眼区分 */
|
||||
.yang-comment.is-pending .yang-comment-content {
|
||||
opacity: 0.72;
|
||||
}
|
||||
|
||||
/* 评论正文 */
|
||||
.yang-comment-content {
|
||||
color: #3c414a;
|
||||
font-size: 14px;
|
||||
line-height: 1.78;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.yang-comment-content > p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.yang-comment-content > p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.yang-comment-content p {
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
/* @某人 的提及高亮(由 comment_add_at 过滤器插入的 <span>) */
|
||||
.yang-comment-content > span:first-child {
|
||||
color: #0b74d1;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 评论里的图片:限制最大宽度,别撑破容器 */
|
||||
.yang-comment-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* 引用块 */
|
||||
.yang-comment-content blockquote {
|
||||
margin: 8px 0;
|
||||
padding: 6px 12px;
|
||||
border-left: 3px solid #e2e6ee;
|
||||
background-color: #fafbfc;
|
||||
color: #6b7280;
|
||||
font-size: 13.5px;
|
||||
}
|
||||
|
||||
.yang-comment-content code {
|
||||
padding: 1px 5px;
|
||||
border-radius: 3px;
|
||||
background-color: #f4f5f7;
|
||||
color: #c7254e;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.yang-comment-content pre {
|
||||
overflow-x: auto;
|
||||
padding: 10px 12px;
|
||||
border-radius: 3px;
|
||||
background-color: #f6f7f9;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* 表情图片与正文基线对齐 */
|
||||
.yang-comment-content img.wp-smiley {
|
||||
display: inline-block;
|
||||
margin: 0 1px;
|
||||
width: auto;
|
||||
max-height: 1.4em;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
4. 操作按钮
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
.yang-comment-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.yang-comment-reply,
|
||||
.yang-comment-edit {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
color: #8a9099;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.yang-comment-reply:hover,
|
||||
.yang-comment-edit:hover {
|
||||
color: #00a2ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.yang-comment-reply .kicon {
|
||||
margin-right: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 已进入"回复这条"状态时,按钮藏起来(由 JS 加 class) */
|
||||
.yang-comment-reply.is-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
5. 嵌套回复
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
.yang-children {
|
||||
margin-top: 2px;
|
||||
padding-left: 20px;
|
||||
/* 左侧引导线:让"谁回谁"在视觉上有明确归属 */
|
||||
border-left: 2px solid #f0f2f5;
|
||||
}
|
||||
|
||||
.yang-children > .yang-comment {
|
||||
padding: 11px 0;
|
||||
}
|
||||
|
||||
/* 深层的头像小一号,靠尺寸建立层级感 */
|
||||
.yang-children .yang-children .yang-comment-avatar,
|
||||
.yang-children .yang-children .yang-comment-avatar img,
|
||||
.yang-children .yang-children .yang-comment-avatar-ph {
|
||||
width: 34px;
|
||||
}
|
||||
|
||||
.yang-children .yang-children .yang-comment-avatar {
|
||||
width: 34px;
|
||||
}
|
||||
|
||||
.yang-children .yang-children .yang-comment-avatar img {
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.yang-children .yang-children .yang-comment-avatar-ph {
|
||||
height: 34px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 第三层以后不再继续缩进 —— 否则窄屏上正文只剩一条竖线 */
|
||||
.yang-children .yang-children .yang-children {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
/* 新提交的评论:淡入 + 短暂底色,让用户看到自己刚发的那条 */
|
||||
@keyframes yang-comment-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.yang-comment.is-new {
|
||||
animation: yang-comment-in 0.28s ease;
|
||||
background-color: #fffdf5;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
6. 加载更多
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
.comments-more {
|
||||
padding: 16px 0 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.comments-more[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.comments-more-btn {
|
||||
padding: 8px 26px;
|
||||
border: 1px solid #e2e6ee;
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
color: #5a616b;
|
||||
font-size: 13.5px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.comments-more-btn:hover:not(:disabled) {
|
||||
border-color: #00a2ff;
|
||||
background-color: #f5fbff;
|
||||
color: #00a2ff;
|
||||
}
|
||||
|
||||
.comments-more-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
7. 评论表单
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
.comment-respond {
|
||||
margin-top: 22px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
/* 表单被"搬"进某条评论时,去掉那条顶部分隔线,视觉上更连贯 */
|
||||
.yang-children > #respond {
|
||||
margin-top: 10px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px dashed #e8ebf0;
|
||||
}
|
||||
|
||||
.comment-reply-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin: 0 0 14px;
|
||||
color: #1f2328;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.comment-cancel-reply {
|
||||
padding: 3px 10px;
|
||||
border: 1px solid #e4e8ee;
|
||||
border-radius: 3px;
|
||||
background-color: #f7f8fa;
|
||||
color: #6b7280;
|
||||
font-weight: 400;
|
||||
font-size: 12.5px;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.comment-cancel-reply[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.comment-cancel-reply:hover {
|
||||
border-color: #f0b4b4;
|
||||
background-color: #fff5f5;
|
||||
color: #d9534f;
|
||||
}
|
||||
|
||||
/* 「正在回复 @某人」提示条 */
|
||||
.comment-reply-hint {
|
||||
margin: 0 0 12px;
|
||||
padding: 7px 12px;
|
||||
border-left: 3px solid #00a2ff;
|
||||
border-radius: 2px;
|
||||
background-color: #f2f8ff;
|
||||
color: #4a6b8a;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.comment-reply-hint[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 昵称/邮箱/网址:三列,窄屏自动堆叠 */
|
||||
.comment-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.comment-field {
|
||||
position: relative;
|
||||
flex: 1 1 180px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.comment-field-icon {
|
||||
position: absolute;
|
||||
left: 9px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #b6bcc6;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.comment-input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 9px 12px;
|
||||
border: 1px solid #e6e9ef;
|
||||
border-radius: 3px;
|
||||
background-color: #fcfcfd;
|
||||
color: #303133;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.comment-field .comment-input {
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.comment-input::placeholder {
|
||||
color: #b0b6bf;
|
||||
}
|
||||
|
||||
.comment-input:focus {
|
||||
outline: none;
|
||||
border-color: #00a2ff;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 0 3px rgba(0, 162, 255, 0.1);
|
||||
}
|
||||
|
||||
.comment-input:disabled,
|
||||
.comment-input[readonly] {
|
||||
background-color: #f7f8fa;
|
||||
color: #8a9099;
|
||||
}
|
||||
|
||||
/* textarea 容器 */
|
||||
.comment-textarea {
|
||||
position: relative;
|
||||
border: 1px solid #e6e9ef;
|
||||
border-radius: 3px;
|
||||
background-color: #fcfcfd;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.comment-textarea:focus-within {
|
||||
border-color: #00a2ff;
|
||||
box-shadow: 0 0 0 3px rgba(0, 162, 255, 0.1);
|
||||
}
|
||||
|
||||
.comment-textarea .comment-input {
|
||||
min-height: 132px;
|
||||
padding: 11px 13px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: none;
|
||||
resize: vertical;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.comment-textarea .comment-input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* 工具条 */
|
||||
.comment-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 7px 10px;
|
||||
border-top: 1px solid #f0f2f6;
|
||||
background-color: #fafbfc;
|
||||
}
|
||||
|
||||
.comment-bar-left,
|
||||
.comment-bar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.comment-bar-left {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.comment-smile-btn {
|
||||
padding: 4px 7px;
|
||||
border: 0;
|
||||
border-radius: 3px;
|
||||
background: none;
|
||||
color: #8a9099;
|
||||
font-size: 17px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
transition: color 0.15s ease, background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.comment-smile-btn:hover {
|
||||
background-color: #eef2f7;
|
||||
color: #00a2ff;
|
||||
}
|
||||
|
||||
/* 表情面板:3 行 8 列 */
|
||||
.comment-smile-panel {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 8px);
|
||||
left: 0;
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 264px;
|
||||
padding: 8px;
|
||||
border: 1px solid #e6e9ef;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.comment-smile-panel[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.comment-smile-panel a {
|
||||
float: none;
|
||||
display: block;
|
||||
margin: 2px;
|
||||
padding: 3px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
background-color: #f7f8fa;
|
||||
transition: background-color 0.12s ease, border-color 0.12s ease;
|
||||
}
|
||||
|
||||
.comment-smile-panel a:hover {
|
||||
border-color: #b9dcff;
|
||||
background-color: #eaf4ff;
|
||||
}
|
||||
|
||||
.comment-smile-panel img {
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/* 状态提示 */
|
||||
.comment-status {
|
||||
color: #8a9099;
|
||||
font-size: 12.5px;
|
||||
line-height: 1.6;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.comment-status.is-ok {
|
||||
color: #2f9e44;
|
||||
}
|
||||
|
||||
.comment-status.is-err {
|
||||
color: #d9534f;
|
||||
}
|
||||
|
||||
/* 提交按钮 */
|
||||
.comment-submit {
|
||||
padding: 8px 22px;
|
||||
border: 0;
|
||||
border-radius: 3px;
|
||||
background-color: #00a2ff;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: background-color 0.15s ease, opacity 0.15s ease;
|
||||
}
|
||||
|
||||
.comment-submit:hover:not(:disabled) {
|
||||
background-color: #0090e6;
|
||||
}
|
||||
|
||||
.comment-submit:disabled,
|
||||
.comment-submit.is-loading {
|
||||
opacity: 0.62;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* honeypot:移出视口而不是 display:none(display:none 的字段部分爬虫不填) */
|
||||
.comment-hp {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 只需登录才能评论的提示 */
|
||||
.comments-login-required {
|
||||
margin: 0;
|
||||
padding: 18px;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 4px;
|
||||
background-color: #fafbfc;
|
||||
color: #6b7280;
|
||||
font-size: 13.5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.comments-login-required a {
|
||||
color: #00a2ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
8. 无障碍:屏幕阅读器专用文本
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
.k-main .details .comments .sr-only {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: -1px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
9. 响应式
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.k-main .details .comments {
|
||||
padding: 16px 14px 18px;
|
||||
}
|
||||
|
||||
.comments-head {
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.comments-head .title {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.yang-comment {
|
||||
/* 只收窄列间距;写 gap 会同时给 grid 的 row-gap 赋值,
|
||||
导致"主体"与"子评论"之间多出一道空隙 */
|
||||
column-gap: 10px;
|
||||
padding: 13px 0;
|
||||
}
|
||||
|
||||
.yang-comment-avatar,
|
||||
.yang-comment-avatar img,
|
||||
.yang-comment-avatar-img,
|
||||
.yang-comment-avatar-ph {
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.yang-comment-avatar img,
|
||||
.yang-comment-avatar-img,
|
||||
.yang-comment-avatar-ph {
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
/* 窄屏缩进收窄:原来 20px 在三层后正文只剩很窄一条 */
|
||||
.yang-children {
|
||||
padding-left: 11px;
|
||||
}
|
||||
|
||||
.yang-children .yang-children {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.yang-children .yang-children .yang-children {
|
||||
padding-left: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.comment-info {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.comment-field {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.comment-bar {
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.comment-bar-right {
|
||||
flex: 1 1 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.comment-status {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.comment-smile-panel {
|
||||
width: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
.yang-comment-avatar,
|
||||
.yang-comment-avatar img,
|
||||
.yang-comment-avatar-img,
|
||||
.yang-comment-avatar-ph {
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.yang-comment-avatar img,
|
||||
.yang-comment-avatar-img,
|
||||
.yang-comment-avatar-ph {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
/* ⚠️ 必须一并覆盖深层头像。
|
||||
上面的基础规则里有 `.yang-children .yang-children .yang-comment-avatar
|
||||
{ width: 34px }`,它选择器特异性 (0,3,0) 高于这里的 `.yang-comment-avatar`
|
||||
(0,1,0) —— 媒体查询**不增加**特异性。所以只写这一条的话,窄屏下
|
||||
深层头像仍是 34px,反而比顶层的 32px 更大,层级关系是反的。 */
|
||||
.yang-children .yang-children .yang-comment-avatar,
|
||||
.yang-children .yang-children .yang-comment-avatar img,
|
||||
.yang-children .yang-children .yang-comment-avatar-ph {
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.yang-children .yang-children .yang-comment-avatar img,
|
||||
.yang-children .yang-children .yang-comment-avatar-ph {
|
||||
height: 26px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.comment-smile-panel {
|
||||
width: 216px;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
10. 打印:评论不需要按钮
|
||||
--------------------------------------------------------------*/
|
||||
|
||||
@media print {
|
||||
.comments-jump-form,
|
||||
.yang-comment-actions,
|
||||
.comments-more,
|
||||
.comment-respond {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.yang-comment-content {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
/*!
|
||||
* 文章目录(TOC)样式
|
||||
* Yongquan Yang <yangyq.net>
|
||||
*
|
||||
* ── 设计原则 ────────────────────────────────────────────────
|
||||
* 1. **不抢正文的视觉**:目录是辅助导航,不是内容。所以用浅灰背景、
|
||||
* 细边框、小字号,让它在页面上"退后一步"。
|
||||
* 2. **用主题主色**:强调色统一为 #00a2ff,与主题其他强调元素一致。
|
||||
* 注意主题**没有**定义 CSS 变量(主色是各处硬编码的),所以这里
|
||||
* 直接写字面值,不要臆造 var(--kratos-primary) 之类的变量 —— 那会
|
||||
* 静默失效,目录永远是默认灰色,且看不出是哪里错了。
|
||||
* 3. **移动端友好**:窄屏下缩进减小、字号略小,但不折叠成下拉 ——
|
||||
* 目录本来就是给长文用的,手机上更需要它。
|
||||
*/
|
||||
|
||||
.yang-toc {
|
||||
margin: 24px 0;
|
||||
border: 1px solid #ebeef5;
|
||||
border-left: 3px solid #00a2ff;
|
||||
border-radius: 3px;
|
||||
background-color: #fafbfc;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* <details> 的默认三角标记去掉,用自己的图标 */
|
||||
.yang-toc > summary {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.yang-toc > summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.yang-toc > summary::marker {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.yang-toc-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 11px 16px;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.yang-toc-head:hover {
|
||||
color: #00a2ff;
|
||||
}
|
||||
|
||||
/* 折叠箭头:用 CSS 画的三角,不依赖图标字体或 SVG 文件 */
|
||||
.yang-toc > summary .yang-toc-title::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-right: 8px;
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-left: 6px solid currentColor;
|
||||
vertical-align: middle;
|
||||
transition: transform 0.18s ease;
|
||||
}
|
||||
|
||||
/* 展开时箭头朝下(旋转 90°) */
|
||||
.yang-toc[open] > summary .yang-toc-title::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* 不可折叠时(toggle=0)不显示箭头 */
|
||||
.yang-toc:not(details) .yang-toc-head .yang-toc-title::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.yang-toc-title {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/* 条目数徽标 */
|
||||
.yang-toc-count {
|
||||
flex: 0 0 auto;
|
||||
margin-left: 8px;
|
||||
padding: 1px 7px;
|
||||
border-radius: 9px;
|
||||
background-color: #eef1f6;
|
||||
color: #909399;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.yang-toc-body {
|
||||
padding: 0 16px 12px;
|
||||
}
|
||||
|
||||
.yang-toc-list {
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* 二级以上的列表缩进,并加一条引导线 */
|
||||
.yang-toc-list .yang-toc-list {
|
||||
margin-left: 9px;
|
||||
padding-left: 14px;
|
||||
border-left: 1px dashed #e2e6ee;
|
||||
}
|
||||
|
||||
.yang-toc-item {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.yang-toc-link {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
padding: 4px 6px;
|
||||
border-radius: 3px;
|
||||
color: #4a4f57;
|
||||
text-decoration: none;
|
||||
transition: color 0.15s ease, background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.yang-toc-link:hover,
|
||||
.yang-toc-link:focus {
|
||||
background-color: #eef4ff;
|
||||
color: #00a2ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* 序号 */
|
||||
.yang-toc-num {
|
||||
flex: 0 0 auto;
|
||||
min-width: 1.9em;
|
||||
margin-right: 5px;
|
||||
color: #a8abb2;
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.yang-toc-text {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* 层级视觉差异:越深越淡、字号越小 */
|
||||
.yang-toc-lv3 > .yang-toc-link {
|
||||
color: #6b7280;
|
||||
font-size: 13.5px;
|
||||
}
|
||||
|
||||
.yang-toc-lv4 > .yang-toc-link,
|
||||
.yang-toc-lv5 > .yang-toc-link,
|
||||
.yang-toc-lv6 > .yang-toc-link {
|
||||
color: #8b9099;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* 当前阅读位置的条目高亮(JS 加 .is-active) */
|
||||
.yang-toc-link.is-active {
|
||||
background-color: #eef4ff;
|
||||
color: #00a2ff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ── 标题锚点:点击跳转后被固定导航栏挡住的问题 ────────────────
|
||||
* 主题的 .k-nav 是 fixed-top,滚动后固定约 67px 高。
|
||||
* 纯 CSS 方案是给目标元素加 scroll-margin-top —— 浏览器原生支持,
|
||||
* 且不依赖 JS(用 #anchor 直接访问、前进后退、外部链接进来都生效)。
|
||||
*
|
||||
* 为什么不用 JS 算偏移:JS 方案只在"点了目录"的情况下有效,
|
||||
* 从外部带 #hash 进来、或按浏览器后退回到锚点时都不会触发。
|
||||
* scroll-margin-top 是声明式的,所有情况自动生效。
|
||||
*
|
||||
* 67px 是导航栏高度;再加 16px 呼吸空间。管理工具栏(admin bar)
|
||||
* 存在时再往上加,否则锚点会被工具栏盖住。
|
||||
*/
|
||||
.yang-toc-target,
|
||||
.k-main .details .content h1[id],
|
||||
.k-main .details .content h2[id],
|
||||
.k-main .details .content h3[id],
|
||||
.k-main .details .content h4[id],
|
||||
.k-main .details .content h5[id],
|
||||
.k-main .details .content h6[id] {
|
||||
scroll-margin-top: 84px;
|
||||
}
|
||||
|
||||
body.admin-bar .k-main .details .content h1[id],
|
||||
body.admin-bar .k-main .details .content h2[id],
|
||||
body.admin-bar .k-main .details .content h3[id],
|
||||
body.admin-bar .k-main .details .content h4[id],
|
||||
body.admin-bar .k-main .details .content h5[id],
|
||||
body.admin-bar .k-main .details .content h6[id] {
|
||||
scroll-margin-top: 116px;
|
||||
}
|
||||
|
||||
/* 滚动到锚点时轻微闪一下,让用户确认"跳到这里了" */
|
||||
@keyframes yang-toc-flash {
|
||||
0%,
|
||||
100% {
|
||||
background-color: transparent;
|
||||
}
|
||||
30% {
|
||||
background-color: #fffbe6;
|
||||
}
|
||||
}
|
||||
|
||||
.yang-toc-flash {
|
||||
animation: yang-toc-flash 1.1s ease;
|
||||
}
|
||||
|
||||
/* ── 窄屏 ── */
|
||||
@media screen and (max-width: 768px) {
|
||||
.yang-toc {
|
||||
margin: 18px 0;
|
||||
font-size: 13.5px;
|
||||
}
|
||||
|
||||
.yang-toc-head {
|
||||
padding: 10px 13px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.yang-toc-body {
|
||||
padding: 0 10px 10px;
|
||||
}
|
||||
|
||||
.yang-toc-list .yang-toc-list {
|
||||
margin-left: 4px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.yang-toc-link {
|
||||
padding: 5px 5px;
|
||||
}
|
||||
|
||||
.yang-toc-lv3 > .yang-toc-link {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 打印:目录展开、去背景、不折行 ────────────────────────── */
|
||||
@media print {
|
||||
.yang-toc {
|
||||
border: 1px solid #ccc;
|
||||
background: none;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.yang-toc-count {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.yang-toc-link {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 暗色主题适配 ──────────────────────────────────────────
|
||||
* 主题没有内置暗色模式,但用户可能在「自定义 CSS」里加
|
||||
* prefers-color-scheme。这里跟随同一个媒体查询,避免目录
|
||||
* 在暗色下变成一块刺眼的白板。
|
||||
*/
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html.yang-dark .yang-toc {
|
||||
border-color: #303640;
|
||||
border-left-color: #00a2ff;
|
||||
background-color: #1d2026;
|
||||
}
|
||||
|
||||
html.yang-dark .yang-toc-head {
|
||||
color: #d5d9e0;
|
||||
}
|
||||
|
||||
html.yang-dark .yang-toc-count {
|
||||
background-color: #2a2f38;
|
||||
color: #8b929d;
|
||||
}
|
||||
|
||||
html.yang-dark .yang-toc-link {
|
||||
color: #b6bcc6;
|
||||
}
|
||||
|
||||
html.yang-dark .yang-toc-link:hover,
|
||||
html.yang-dark .yang-toc-link.is-active {
|
||||
background-color: #252b34;
|
||||
color: #00a2ff;
|
||||
}
|
||||
|
||||
html.yang-dark .yang-toc-list .yang-toc-list {
|
||||
border-left-color: #333944;
|
||||
}
|
||||
|
||||
html.yang-dark .yang-toc-num {
|
||||
color: #767d88;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user