v3.2.14 哀悼提示条改到整页最上方正中,只在纪念日当天出现
用户要求:哀悼说明「放在最上方的最中间,只在纪念日、哀悼模式开启时才显示,
其他时间不显示」。
改的过程中量出三个真问题:
1. 提示条与站点标题重叠 32px。提示条从 y=0 开始、高 40px,而导航栏
.k-nav 是 position:absolute; top:0、z-index 1030;提示条 z-index 9990
⇒ 直接盖在 Logo 上。CSS 每个字都没写错,就是叠在一起。
2. 内容偏左 38px。为了给右侧关闭按钮让位写了 padding-right:46px、
左侧只有 18px ⇒ 文字中心 602 vs 视口中心 640。"最中间"没做到。
3. 页脚有常驻的「纪念日哀悼说明」链接,一年 365 天都显示。平时打开
站点的人既没看到黑白也不知在哀悼什么,这个入口本身就是困惑源。
修法:
- 提示条占文档流第一行、width:100%,内容交给内层 .ymb-inner 居中,
左右 padding 等宽、关闭按钮 absolute 不占内部流 ⇒ 几何中心 = 视口中心。
- .k-nav 是绝对定位,body 的 padding 推不动它(这个原因单看代码想不到,
是量几何量出来的)⇒ 单独补一条 body.has-yang-mourning-bar .k-nav{top:var(--ymb-h)}。
偏移量由脚本读真实高度写入,窄屏换行后也准。
- 不用 fixed:那会滚动时顶部永远压一条深色带,内容从它下面穿过去。
- 移除页脚常驻入口与 wp_footer 注册,说明页入口只在提示条里。
非哀悼日输出 0 字节。
验证:
- run_tests2 163 条(新增 9 条位置契约)
- _check_hidden.php 19 条(非哀悼日 0 字节、每个纪念日都能触发)
- mourning_bar_geometry.py 28 条(线上真实页面实测 4 种视口:
顶部贴边、横跨整宽、居中误差 ≤1px、与标题和导航栏零重叠)
- falsify 44 条注入全被抓住(新增 9 条)
两个假绿当场被反面验证抓出并修掉:
- 判据照着 fixed 方案写,实现改成 relative 后 4 条断言集体假红
(教训:设计前提变了,判据必须跟着改)。
- 页脚断言用 ob_start 取输出,但函数是 return 不是 echo ⇒ $fl 恒空
⇒ 注入"返回一个链接"仍全绿(教训:否定式断言在空输出上恒真)。
This commit is contained in:
+88
-25
@@ -258,17 +258,50 @@ function yang_mourning_status_text()
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 哀悼期间在页面顶部显示一条提示,链接到说明页
|
* 哀悼期间在页面**最顶部正中**显示一条提示,链接到说明页
|
||||||
*
|
*
|
||||||
* ── 为什么必须放在顶部 ────────────────────────────────────────
|
* ── 为什么必须放在最顶部 ──────────────────────────────────────
|
||||||
* 用户的原话是「别人都不知道咋回事,为啥变黑白」。只把入口藏在页脚,
|
* 用户的原话是「别人都不知道咋回事,为啥变黑白」。只把入口藏在页脚,
|
||||||
* 绝大多数人根本不会看到 —— 他们看到一片灰就关掉了。
|
* 绝大多数人根本不会看到 —— 他们看到一片灰就关掉了。
|
||||||
* 所以提示条要出现在**首屏就能看到**的位置。
|
* 所以提示条必须出现在**首屏第一眼就看到**的位置:整页最上方、水平居中。
|
||||||
|
*
|
||||||
|
* ── 只在哀悼日出现 ────────────────────────────────────────────
|
||||||
|
* 平时打开站点的人不应该看到任何"哀悼说明"的入口 —— 他既没看到黑白,
|
||||||
|
* 也不知道在对什么致哀,那个入口本身就是困惑源。所以页脚的常驻链接
|
||||||
|
* 已经移除,说明页的入口就只在这条提示里。
|
||||||
*
|
*
|
||||||
* ── 为什么不做成弹窗 ──────────────────────────────────────────
|
* ── 为什么不做成弹窗 ──────────────────────────────────────────
|
||||||
* 弹窗会挡住内容,纪念日当天每个访客每次访问都被弹一次,是骚扰。
|
* 弹窗会挡住内容,纪念日当天每个访客每次访问都被弹一次,是骚扰。
|
||||||
* 一条可以关闭的细横条才是合适的强度,且关闭状态记在 sessionStorage
|
* 一条可以关闭的细横条才是合适的强度,且关闭状态记在 sessionStorage
|
||||||
* (用 session 而不是 localStorage:当天关闭后,第二天不应该还记着)。
|
* (用 session 而不是 localStorage:当天关闭后,第二天不应该还记着)。
|
||||||
|
*
|
||||||
|
* ── 定位方式:占文档流第一行 + 同步下移导航栏 ─────────────────
|
||||||
|
* 目标是「整页最上方、水平居中」。实现时连撞两次,都靠真实几何测出来:
|
||||||
|
*
|
||||||
|
* 第一版:`position:relative`,排进文档流。左右 padding 是
|
||||||
|
* `9px 46px 9px 18px`(左 18、右 46,为了给关闭按钮让位),
|
||||||
|
* 内容整体偏左(实测文字中心 602、视口中心 640,偏 38px)——
|
||||||
|
* "最中间"根本没做到。同时它从 y=0 开始、高 40px,而导航栏
|
||||||
|
* `.k-nav` 是 `absolute; top:0`、z-index 1030,提示条 z-index 9990
|
||||||
|
* ⇒ **压在站点标题上方**(与 `.navbar-brand` 实测重叠 32px),把 Logo 遮住。
|
||||||
|
*
|
||||||
|
* 第二版:改成 `position:fixed; top:0; left:0; right:0`,并给 body 加
|
||||||
|
* `padding-top`。居中问题解决了(中心精确等于视口中心),但**重叠仍在 31px**。
|
||||||
|
* 原因很隐蔽:`.k-nav` 是 `position:absolute`,它的包含块是初始包含块
|
||||||
|
* (视口),**body 的 padding 推不动它**。
|
||||||
|
*
|
||||||
|
* 现在的做法(两件事配合):
|
||||||
|
* 1. 提示条本身 `position:relative` 占文档流第一行、横跨整宽,
|
||||||
|
* 内容交给内层 `.ymb-inner` 居中,左右 padding 等宽,
|
||||||
|
* 关闭按钮 absolute 不占内部流 ⇒ 几何中心 = 视口中心。
|
||||||
|
* 它占位后,`.k-header` 会被自然推下去,正文不受影响。
|
||||||
|
* 2. 唯独 `.k-nav` 是 absolute,必须单独补一条
|
||||||
|
* `body.has-yang-mourning-bar .k-nav{top:var(--ymb-h)}` 把它挪到提示条下方。
|
||||||
|
* 没有提示条时该变量不存在、偏移为 0,行为与改动前完全一致。
|
||||||
|
*
|
||||||
|
* 不用 fixed 的理由:fixed 会一直悬浮,滚动看文章时顶部永远压一条深色带,
|
||||||
|
* 内容从它下面穿过去;而且它不占位,必须靠 padding 补偿,补偿量还算不准
|
||||||
|
* (窄屏换行后高度会变)。占文档流第一行没有这些问题。
|
||||||
*/
|
*/
|
||||||
function yang_mourning_notice_bar()
|
function yang_mourning_notice_bar()
|
||||||
{
|
{
|
||||||
@@ -287,36 +320,67 @@ function yang_mourning_notice_bar()
|
|||||||
: __('今天是纪念日,本站以黑白致哀。', 'kratos');
|
: __('今天是纪念日,本站以黑白致哀。', 'kratos');
|
||||||
?>
|
?>
|
||||||
<div id="yang-mourning-bar" class="yang-mourning-bar" role="region" aria-label="<?php esc_attr_e('哀悼提示', 'kratos'); ?>">
|
<div id="yang-mourning-bar" class="yang-mourning-bar" role="region" aria-label="<?php esc_attr_e('哀悼提示', 'kratos'); ?>">
|
||||||
|
<span class="ymb-inner">
|
||||||
<span class="ymb-dot" aria-hidden="true"></span>
|
<span class="ymb-dot" aria-hidden="true"></span>
|
||||||
<span class="ymb-text"><?php echo esc_html($text); ?></span>
|
<span class="ymb-text"><?php echo esc_html($text); ?></span>
|
||||||
<a class="ymb-link" href="<?php echo esc_url($url); ?>"><?php _e('了解详情', 'kratos'); ?></a>
|
<a class="ymb-link" href="<?php echo esc_url($url); ?>"><?php _e('了解详情', 'kratos'); ?></a>
|
||||||
|
</span>
|
||||||
<button type="button" class="ymb-close" aria-label="<?php esc_attr_e('关闭提示', 'kratos'); ?>">×</button>
|
<button type="button" class="ymb-close" aria-label="<?php esc_attr_e('关闭提示', 'kratos'); ?>">×</button>
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style id="yang-mourning-bar-css">
|
||||||
.yang-mourning-bar{position:relative;z-index:9990;display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:10px;padding:9px 46px 9px 18px;background:#2b2f36;color:#e8eaed;font-size:13.5px;line-height:1.6;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei",sans-serif;letter-spacing:.2px}
|
.yang-mourning-bar{position:relative;z-index:9995;display:flex;align-items:center;justify-content:center;min-height:38px;padding:8px 44px;background:#2b2f36;color:#e8eaed;font-size:13.5px;line-height:1.55;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei",sans-serif;letter-spacing:.2px;box-sizing:border-box;width:100%}
|
||||||
|
.yang-mourning-bar .ymb-inner{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:8px;max-width:100%}
|
||||||
.yang-mourning-bar .ymb-dot{width:6px;height:6px;border-radius:50%;background:#b0b7c0;flex:0 0 auto}
|
.yang-mourning-bar .ymb-dot{width:6px;height:6px;border-radius:50%;background:#b0b7c0;flex:0 0 auto}
|
||||||
.yang-mourning-bar .ymb-text{opacity:.92}
|
.yang-mourning-bar .ymb-text{opacity:.92}
|
||||||
.yang-mourning-bar .ymb-link{color:#fff;text-decoration:none;border-bottom:1px solid rgba(255,255,255,.42);padding-bottom:1px;transition:border-color .18s ease}
|
.yang-mourning-bar .ymb-link{color:#fff;text-decoration:none;border-bottom:1px solid rgba(255,255,255,.42);padding-bottom:1px;white-space:nowrap;transition:border-color .18s ease}
|
||||||
.yang-mourning-bar .ymb-link:hover{border-bottom-color:#fff}
|
.yang-mourning-bar .ymb-link:hover{border-bottom-color:#fff}
|
||||||
.yang-mourning-bar .ymb-close{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:0;color:#9aa3ad;font-size:19px;line-height:1;cursor:pointer;padding:2px 7px;border-radius:4px}
|
.yang-mourning-bar .ymb-close{position:absolute;right:10px;top:50%;transform:translateY(-50%);background:none;border:0;color:#9aa3ad;font-size:19px;line-height:1;cursor:pointer;padding:2px 8px;border-radius:4px}
|
||||||
.yang-mourning-bar .ymb-close:hover{color:#fff;background:rgba(255,255,255,.1)}
|
.yang-mourning-bar .ymb-close:hover{color:#fff;background:rgba(255,255,255,.1)}
|
||||||
.yang-mourning-bar.is-hidden{display:none}
|
.yang-mourning-bar.is-hidden{display:none}
|
||||||
|
/* 导航栏是 absolute;top:0,相对视口定位 —— body 的 padding 推不动它。
|
||||||
|
不同步下移的话,它会和提示条叠在一起、把站点标题遮住(实测重叠 31px)。
|
||||||
|
这里只用一条 top 偏移把它挪到提示条下方;没有提示条时 --ymb-h 为 0。 */
|
||||||
|
body.has-yang-mourning-bar .k-nav{top:var(--ymb-h,0px)}
|
||||||
@media (max-width:560px){
|
@media (max-width:560px){
|
||||||
.yang-mourning-bar{font-size:12.5px;padding:8px 42px 8px 12px;gap:7px;justify-content:flex-start}
|
.yang-mourning-bar{font-size:12.5px;padding:7px 40px 7px 12px;letter-spacing:0}
|
||||||
|
.yang-mourning-bar .ymb-inner{gap:6px}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
var bar = document.getElementById('yang-mourning-bar');
|
var bar = document.getElementById('yang-mourning-bar');
|
||||||
if (!bar) return;
|
if (!bar) return;
|
||||||
|
var body = document.body;
|
||||||
|
|
||||||
|
// 让正文让出提示条的高度。必须读真实高度:
|
||||||
|
// 窄屏下文字换行,高度不是常数,写死像素必然在某些宽度下失准。
|
||||||
|
function syncOffset() {
|
||||||
|
if (bar.className.indexOf('is-hidden') > -1) {
|
||||||
|
body.classList.remove('has-yang-mourning-bar');
|
||||||
|
body.style.removeProperty('--ymb-h');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
body.classList.add('has-yang-mourning-bar');
|
||||||
|
body.style.setProperty('--ymb-h', bar.offsetHeight + 'px');
|
||||||
|
}
|
||||||
|
// 提示条本身在文档流里,会把 .k-header 自然推下去;
|
||||||
|
// 但 .k-nav 是 absolute,必须靠上面的 CSS 变量把它也挪下来。
|
||||||
|
syncOffset();
|
||||||
|
window.addEventListener('resize', syncOffset);
|
||||||
|
window.addEventListener('load', syncOffset);
|
||||||
|
|
||||||
// 当天关闭过就不再显示。用 sessionStorage 而非 localStorage:
|
// 当天关闭过就不再显示。用 sessionStorage 而非 localStorage:
|
||||||
// 明天是另一天,不该还记着昨天的关闭操作。
|
// 明天是另一天,不该还记着昨天的关闭操作。
|
||||||
var KEY = 'yangMournBarClosed:' + <?php echo wp_json_encode(current_time('Ymd')); ?>;
|
var KEY = 'yangMournBarClosed:' + <?php echo wp_json_encode(current_time('Ymd')); ?>;
|
||||||
try { if (sessionStorage.getItem(KEY) === '1') { bar.className += ' is-hidden'; return; } } catch (e) {}
|
var closed = false;
|
||||||
|
try { closed = sessionStorage.getItem(KEY) === '1'; } catch (e) {}
|
||||||
|
if (closed) { bar.className += ' is-hidden'; syncOffset(); return; }
|
||||||
|
|
||||||
var btn = bar.querySelector('.ymb-close');
|
var btn = bar.querySelector('.ymb-close');
|
||||||
if (btn) {
|
if (btn) {
|
||||||
btn.addEventListener('click', function () {
|
btn.addEventListener('click', function () {
|
||||||
bar.className += ' is-hidden';
|
bar.className += ' is-hidden';
|
||||||
|
syncOffset();
|
||||||
try { sessionStorage.setItem(KEY, '1'); } catch (e) {}
|
try { sessionStorage.setItem(KEY, '1'); } catch (e) {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -327,27 +391,26 @@ function yang_mourning_notice_bar()
|
|||||||
add_action('wp_body_open', 'yang_mourning_notice_bar', 5);
|
add_action('wp_body_open', 'yang_mourning_notice_bar', 5);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 页脚常驻入口
|
* 说明页的入口只存在于哀悼提示条里,不做页脚常驻链接
|
||||||
*
|
*
|
||||||
* 提示条只在哀悼日出现,但说明页应该随时可达 ——
|
* ── 为什么删掉页脚那个入口 ────────────────────────────────────
|
||||||
* 有人可能事后才知道,想去看看是怎么回事。
|
* 之前的实现除了提示条,还在页脚挂了一个常驻的「纪念日哀悼说明」链接,
|
||||||
|
* 意图是"事后也能找到"。但用户看得很准:这个链接**一年 365 天都在**,
|
||||||
|
* 平时打开站点的人会莫名其妙看到一个"哀悼说明"——他既没看到黑白,
|
||||||
|
* 也不知道哀悼什么,这个入口本身就是个困惑源。
|
||||||
|
*
|
||||||
|
* 正确的产品逻辑是:**哀悼是当天才发生的事,说明入口就只该在那天出现**。
|
||||||
|
* 提示条本身就是那个入口(带「了解详情」链接)。
|
||||||
|
* 非哀悼日不显示任何入口,说明页仍然可以被直接访问(知道地址的人能打开),
|
||||||
|
* 只是不再到处劝人去看。
|
||||||
|
*
|
||||||
|
* 因此这里刻意**不再注册 wp_footer 钩子**。保留这个函数名是为了让
|
||||||
|
* 老版本的子主题/缓存里对它的调用不会 Fatal,行为是空输出。
|
||||||
*/
|
*/
|
||||||
function yang_mourning_footer_link()
|
function yang_mourning_footer_link()
|
||||||
{
|
{
|
||||||
ob_start();
|
return '';
|
||||||
?>
|
|
||||||
<p class="yang-mourning-footer">
|
|
||||||
<a href="<?php echo esc_url(yang_mourning_page_url()); ?>"><?php _e('纪念日哀悼说明', 'kratos'); ?></a>
|
|
||||||
</p>
|
|
||||||
<style>
|
|
||||||
.yang-mourning-footer{margin:6px 0 0}
|
|
||||||
.yang-mourning-footer a{color:inherit;opacity:.75;text-decoration:none;border-bottom:1px dotted currentColor;font-size:13px;transition:opacity .18s ease}
|
|
||||||
.yang-mourning-footer a:hover{opacity:1}
|
|
||||||
</style>
|
|
||||||
<?php
|
|
||||||
echo ob_get_clean();
|
|
||||||
}
|
}
|
||||||
add_action('wp_footer', 'yang_mourning_footer_link', 20);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前请求是不是说明页自己
|
* 当前请求是不是说明页自己
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Theme Name: Kratos_Yang
|
Theme Name: Kratos_Yang
|
||||||
Text Domain: kratos_Yang
|
Text Domain: kratos_Yang
|
||||||
Version: 3.2.13
|
Version: 3.2.14
|
||||||
Requires PHP: 7.0
|
Requires PHP: 7.0
|
||||||
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
|
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
|
||||||
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好
|
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好
|
||||||
|
|||||||
Reference in New Issue
Block a user