首页「更多栏目」tab 与「排序方式」切换的骨架占位与参考主题 zibll 有实质差异,
根因不是几何宽度,而是三处结构/契约错位:
1. 骨架块自身结构与参考主题不同。card 分支用了 `<posts>` 元素 + `.post-graphic`
包裹层(列表变体,带 margin-right:20px),而参考主题 card 骨架是
`<div class="posts-item card">` 且 `.item-thumbnail` 是直接子元素。
→ card 骨架右侧多出一条真实卡片没有的 20px 沟槽。
2. 骨架块被错误地打上 `ajax-item`。参考主题的占位块没有该类。它会让
`find('.ajax-item')` / ajax-list 的 `inject()` 把骨架当成真实条目。
3. 排序切换的骨架被预渲染节点顶替。aksrt_render_pagination() 在 .ajax-pag 内
渲染了一个写死 2 条、写死 list 形状的 .post_ajax_loader;runtime post_ajax()
会先在容器内 find('.post_ajax_loader'),找到就复用并丢弃调用方按视口动态
拼出的骨架 → 切排序永远是 2 条 list 骨架,card 布局下也是、与视口宽度无关。
参考主题 zib_paging() 根本没有 loader 兄弟节点。
改动:
- inc/helpers/posts-renderer/markup.php:aksrt_render_placeholder() 的
card/list 分支改为与 zib_get_post_placeholder() 逐字等价的结构;去掉
ajax-item 类、card 分支的 .post-graphic 包裹层,元素改用 <div>。
- inc/helpers/template-tags/pagination-permissions.php:删除预渲染 loader,
与参考主题 zib_paging() 一致 —— 只渲染翻页控件。
- assets/js/core/pagination.js:找不到骨架节点时构造与 runtime/main.js 同款
的文章骨架(卡片 8/6/4 条、列表 4/3 条,按视口与参考主题同阈值),
不再退化为「转圈 + 文案」这个第二套加载语言;仅评论等非文章面保留该兜底。
- assets/js/core/pagination.js:为排序菜单(.ajax-option)与 tab 触发器
(.post_ajax_trigger)增加避让 —— 它们归 legacy runtime 管线,
否则一次点击发两个请求(与 ajax-list.js 的既有避让对称)。
- assets/js/runtime/main.js:post_ajax 的显隐由 fadeIn()/hide() 改为
.is-loading 类切换。前者写 inline display,优先级高于类规则,一旦残留
骨架永远打不开,正是骨架契约明令禁止的失败模式。
归档/分类筛选面原本另有一套独立加载语言(spinner 遮罩 + opacity 淡出),
本次一并统一到同一条 .post_ajax_loader + .is-loading 契约:
- inc/helpers/aksrt-archive.php:删除 show_loading 标记位与遮罩 DOM,
改为在分页之后渲染文章骨架。
- assets/js/core/archive.js:showLoading/hideLoading 只切 .is-loading;
fetchPosts() 清空内容时保留骨架与分页节点(与参考主题 success 只 hide
不删的生命周期一致),原先会连带删掉骨架。
- assets/css/frontend/layout.css:删除 .archive__ajax-wrap.is-loading
的 opacity 淡出与 spinner 遮罩规则。
- category.php / tag.php:删除已失效的 show_loading 实参。
验证:php -l 全部通过;php tools/audit-admin-contracts.php errors=0;
契约测试 post-visual(22) / asset-ledger(16) / message-center(8) /
lazyload(7) / frontend-lifecycle(13) / zibll-modern-widgets(10) /
page-display(18) / a11y 全绿;已重跑 build:public 刷新产物。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
590 lines
13 KiB
CSS
590 lines
13 KiB
CSS
/* Breadcrumb chrome lives in breadcrumb.css (single source). */
|
|
|
|
/* ========== 主布局 ========== */
|
|
.content-main {
|
|
width: 100%;
|
|
}
|
|
|
|
.content-main--single {
|
|
max-width: 100%;
|
|
}
|
|
|
|
.content-shell {
|
|
width: 100%;
|
|
margin: 0 auto;
|
|
padding: 32px 16px 48px;
|
|
max-width: var(--container);
|
|
}
|
|
|
|
/* 用户中心(双栏)铺满视口:左栏 320 + 间距 20 + 右栏需要横向空间,被
|
|
* 阅读宽度收窄会在左右两侧留下大片空白。只有 page-profile.php 的 main 带
|
|
* .aksrt-profile(公开主页的该类只打在 body 上),因此不会误伤其它路由。 */
|
|
.site-main.content-shell.aksrt-profile {
|
|
max-width: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* 公开主页是单栏,继续沿用后台「内容最大宽度」。顶部多功能组件位于
|
|
* main 之前;main 的通用 32/40px 上内边距会把资料卡与组件人为拉开,
|
|
* 这里仅对公开主页清除该段重复空白。 */
|
|
.site-main.content-shell.aksrt-user-home {
|
|
max-width: var(--container, 1440px);
|
|
padding-top: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.content-shell {
|
|
padding: 40px 24px 56px;
|
|
}
|
|
}
|
|
|
|
/* page.php 专用:阅读宽度收窄 */
|
|
.content-shell--page {
|
|
max-width: var(--container-page, 860px);
|
|
}
|
|
|
|
.content-shell--cms {
|
|
max-width: 100%;
|
|
padding: 0;
|
|
}
|
|
|
|
/* page.php 内的元素 */
|
|
.entry-page .entry-thumb {
|
|
margin: 0 0 var(--space-6, 24px);
|
|
border-radius: var(--radius-lg, 12px);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.entry-page .page-links {
|
|
margin-top: var(--space-6, 24px);
|
|
font-size: var(--text-sm, 0.875rem);
|
|
color: var(--color-ink-3, var(--color-ink-3));
|
|
}
|
|
|
|
.entry-page .page-links-title {
|
|
margin-right: 8px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* ============================================================
|
|
* Site shell — site-layout-1/2/3 dual-column
|
|
* DOM: main.container > .content-wrap + .sidebar (siblings)
|
|
* body.site-layout-1 = no sidebar
|
|
* body.site-layout-2 = sidebar right
|
|
* body.site-layout-3 = sidebar left
|
|
*
|
|
* This intentionally uses legacy's float/negative-margin ownership model.
|
|
* Below 992px the sidebar is hidden and the content margins collapse.
|
|
* ============================================================ */
|
|
|
|
main.container,
|
|
main.content-shell,
|
|
.site-main.container {
|
|
position: relative;
|
|
}
|
|
|
|
/* content-shell is a padding shell for non-dual pages; when it also hosts
|
|
* the float dual-column, kill horizontal padding so negative-margin math matches legacy. */
|
|
main.container.content-shell,
|
|
main.content-shell.container,
|
|
.site-main.container.content-shell {
|
|
padding-left: 0;
|
|
padding-right: 0;
|
|
max-width: var(--container, var(--mian-max-width, 1200px));
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
main.container::after,
|
|
main.content-shell::after,
|
|
.site-main.container::after {
|
|
content: "";
|
|
display: table;
|
|
clear: both;
|
|
}
|
|
|
|
/* Float/negative-margin compatibility fallback.
|
|
*
|
|
* Critical: .content-layout must NOT set width:100%. Under box-sizing:border-box
|
|
* a 100% width + margin-right gutter keeps the border-box at full container
|
|
* width, so the gutter never shrinks the content box and .sidebar (margin-left:-311px)
|
|
* sits under the main column (overlap). legacy only sets margin on .content-layout;
|
|
* width stays auto so margin carves out the column. */
|
|
.content-wrap {
|
|
float: left;
|
|
width: 100%;
|
|
min-width: 0;
|
|
display: block;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.content-layout {
|
|
display: block;
|
|
/* width:auto — never 100%; margin must shrink the used width */
|
|
width: auto;
|
|
min-width: 0;
|
|
max-width: none;
|
|
margin-right: 0;
|
|
margin-left: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.content-layout__primary {
|
|
min-width: 0;
|
|
max-width: 100%;
|
|
}
|
|
|
|
/* Base sidebar column (legacy .sidebar defaults) — layout variants override below */
|
|
.sidebar {
|
|
float: left;
|
|
width: 311px; /* legacy hard 311px; --sidebar-width kept in sync via runtime vars */
|
|
width: var(--sidebar-width, 311px);
|
|
min-width: 0;
|
|
position: relative;
|
|
box-sizing: border-box;
|
|
display: block;
|
|
}
|
|
|
|
.content-layout__aside {
|
|
min-width: 0;
|
|
}
|
|
|
|
/* No sidebar */
|
|
body.site-layout-1 .sidebar,
|
|
.site-layout-1 .sidebar {
|
|
display: none;
|
|
}
|
|
|
|
body.site-layout-1 .content-layout,
|
|
body.site-layout-1 .content-layout--no-sidebar,
|
|
.site-layout-1 .content-layout {
|
|
margin-left: 0;
|
|
margin-right: 0;
|
|
}
|
|
|
|
/* Compat: templates may still stamp content-layout--no-sidebar */
|
|
.content-layout--no-sidebar {
|
|
margin-left: 0 !important;
|
|
margin-right: 0 !important;
|
|
}
|
|
|
|
/* Sidebar RIGHT (layout 2) — legacy: margin-right: calc(311px + 15px) only */
|
|
body.site-layout-2 .content-layout,
|
|
.site-layout-2 .content-layout {
|
|
margin-right: calc(311px + 15px);
|
|
margin-right: calc(var(--sidebar-width, 311px) + 15px);
|
|
margin-left: 0;
|
|
width: auto;
|
|
}
|
|
|
|
body.site-layout-2 .sidebar,
|
|
.site-layout-2 .sidebar {
|
|
float: left;
|
|
width: 311px;
|
|
width: var(--sidebar-width, 311px);
|
|
margin-left: -311px;
|
|
margin-left: calc(0px - var(--sidebar-width, 311px));
|
|
position: unset;
|
|
}
|
|
|
|
/* Sidebar LEFT (layout 3) */
|
|
body.site-layout-3 .content-layout,
|
|
.site-layout-3 .content-layout {
|
|
margin-left: calc(311px + 15px);
|
|
margin-left: calc(var(--sidebar-width, 311px) + 15px);
|
|
margin-right: unset;
|
|
width: auto;
|
|
}
|
|
|
|
body.site-layout-3 .sidebar,
|
|
.site-layout-3 .sidebar {
|
|
float: left;
|
|
width: 311px;
|
|
width: var(--sidebar-width, 311px);
|
|
margin-left: -100%;
|
|
position: unset;
|
|
}
|
|
|
|
/* Sticky widgets inside sidebar */
|
|
@media (min-width: 992px) {
|
|
.sidebar .content-layout__aside,
|
|
.content-layout__aside {
|
|
position: sticky;
|
|
top: calc(var(--nav-height, 60px) + 16px);
|
|
}
|
|
|
|
.has-static-nav .content-layout__aside {
|
|
top: 16px;
|
|
}
|
|
}
|
|
|
|
/* Mobile collapse (legacy max-width: 991px) */
|
|
@media (max-width: 991.98px) {
|
|
body.site-layout-2 .content-layout,
|
|
body.site-layout-3 .content-layout,
|
|
.site-layout-2 .content-layout,
|
|
.site-layout-3 .content-layout {
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
|
|
body.site-layout-2 .sidebar,
|
|
body.site-layout-3 .sidebar,
|
|
.site-layout-2 .sidebar,
|
|
.site-layout-3 .sidebar,
|
|
.sidebar {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* ========== 页面标题区 ========== */
|
|
.page-header {
|
|
margin-bottom: 28px;
|
|
}
|
|
|
|
.page-header .entry-title {
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.page-header p {
|
|
color: var(--color-ink-3);
|
|
margin: 0;
|
|
max-width: 720px;
|
|
}
|
|
|
|
.term-page-header {
|
|
position: relative;
|
|
overflow: hidden;
|
|
border: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.08));
|
|
border-radius: var(--radius-lg);
|
|
background: var(--surface-1);
|
|
box-shadow: var(--shadow-sm, 0 1px 6px rgba(15, 23, 42, 0.04));
|
|
}
|
|
|
|
.term-page-header__body {
|
|
position: relative;
|
|
z-index: 1;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
padding: 24px;
|
|
}
|
|
|
|
.term-page-header__eyebrow {
|
|
margin: 0 0 8px;
|
|
font-size: 0.8125rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.term-page-header__desc {
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.term-page-header__cover {
|
|
min-height: 140px;
|
|
background-position: center;
|
|
background-size: cover;
|
|
border-top: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.08));
|
|
}
|
|
|
|
.term-page-header--simple .term-page-header__cover {
|
|
display: none;
|
|
}
|
|
|
|
/* Card style: accent top border, slightly more padding */
|
|
.term-page-header--card {
|
|
border-top: 3px solid var(--color-primary, #f04494);
|
|
}
|
|
|
|
.term-page-header--card .term-page-header__body {
|
|
padding: 28px 24px;
|
|
}
|
|
|
|
/* Cover style: full-width hero with background image */
|
|
.term-page-header--cover {
|
|
border: none;
|
|
border-radius: var(--radius-lg);
|
|
background: transparent;
|
|
box-shadow: none;
|
|
min-height: 220px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.term-page-header__cover-bg {
|
|
position: absolute;
|
|
inset: 0;
|
|
background-position: center;
|
|
background-size: cover;
|
|
border-radius: var(--radius-lg);
|
|
}
|
|
|
|
.term-page-header__cover-overlay {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(135deg, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.25) 100%);
|
|
border-radius: var(--radius-lg);
|
|
}
|
|
|
|
.term-page-header--cover .term-page-header__body {
|
|
flex: 1;
|
|
align-items: flex-end;
|
|
z-index: 2;
|
|
}
|
|
|
|
.term-page-header__body--overlay .entry-title,
|
|
.term-page-header__body--overlay .term-page-header__desc,
|
|
.term-page-header__body--overlay .term-page-header__eyebrow {
|
|
color: #fff;
|
|
}
|
|
|
|
.term-page-header__body--overlay .term-page-header__eyebrow {
|
|
color: rgba(255, 255, 255, 0.8);
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.term-page-header--cover {
|
|
min-height: 160px;
|
|
}
|
|
}
|
|
|
|
.aksrt-admin-quicklink {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
min-height: 36px;
|
|
padding: 0 14px;
|
|
border: 1px solid var(--color-line);
|
|
border-radius: var(--radius-pill, 999px);
|
|
background: var(--surface-2);
|
|
color: var(--color-ink-2);
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.aksrt-admin-quicklink:hover {
|
|
color: var(--color-primary);
|
|
border-color: var(--color-primary);
|
|
background: var(--color-primary-soft, rgba(59, 130, 246, 0.08));
|
|
}
|
|
|
|
.archive-filter-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
flex-wrap: wrap;
|
|
margin: -8px 0 24px;
|
|
padding: 16px 18px;
|
|
border-radius: var(--radius-lg);
|
|
background: var(--surface-2);
|
|
border: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.06));
|
|
}
|
|
|
|
.archive-filter-bar__main {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.archive-filter-bar__label {
|
|
color: var(--color-ink-4);
|
|
font-size: 0.8125rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.archive-filter-bar__chips {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
}
|
|
|
|
.archive-filter-bar__chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
min-height: 34px;
|
|
padding: 0 12px;
|
|
border-radius: var(--radius-pill, 999px);
|
|
background: var(--surface-1);
|
|
color: var(--color-ink-2);
|
|
text-decoration: none;
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.archive-filter-bar__chip.is-active,
|
|
.archive-filter-bar__chip:hover {
|
|
background: var(--color-primary);
|
|
color: var(--color-on-primary, #fff);
|
|
}
|
|
|
|
.archive-filter-bar__meta {
|
|
color: var(--color-ink-4);
|
|
font-size: 0.8125rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.archive-filter-bar__sort {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-left: auto;
|
|
}
|
|
|
|
.archive-filter-bar__main--tags {
|
|
border-top: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.06));
|
|
padding-top: 10px;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
/* §3.4 custom_filter dimension rows */
|
|
.archive-filter-bar__main--custom {
|
|
border-top: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.06));
|
|
padding-top: 10px;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
|
|
.content-stream {
|
|
display: grid;
|
|
gap: 20px;
|
|
}
|
|
|
|
.content-main--archive,
|
|
.content-main--tag,
|
|
.content-main--category,
|
|
.content-main--search,
|
|
.content-main--single {
|
|
display: grid;
|
|
gap: 20px;
|
|
}
|
|
|
|
.content-stream__list {
|
|
width: 100%;
|
|
}
|
|
|
|
.content-stream__empty {
|
|
padding: 28px 24px;
|
|
border-radius: var(--radius-lg);
|
|
background: var(--surface-1);
|
|
border: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.08));
|
|
}
|
|
|
|
.article-shell {
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 归档面 AJAX 筛选的加载态与首页共用同一套骨架契约:
|
|
.post_ajax_loader 容器 + .is-loading 开关(见 frontend/modal-runtime.css)。
|
|
原先本文件另有一套独立 spinner 遮罩与 opacity 淡出,已删除 ——
|
|
全站只有一套加载语言。 */
|
|
|
|
@media (max-width: 767px) {
|
|
.term-page-header__body {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
padding: 20px;
|
|
}
|
|
|
|
.aksrt-admin-quicklink {
|
|
width: fit-content;
|
|
}
|
|
}
|
|
|
|
/* ========== AJAX 分页(加载更多 / 无限滚动) ========== */
|
|
.aksrt-pagination-ajax {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 16px;
|
|
margin: 40px 0 8px;
|
|
}
|
|
|
|
.aksrt-load-more-btn {
|
|
min-width: 180px;
|
|
height: 44px;
|
|
padding: 0 32px;
|
|
border-radius: var(--radius-btn);
|
|
border: 1px solid var(--color-line);
|
|
background: var(--surface-page);
|
|
color: var(--color-ink);
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: border-color 0.2s, color 0.2s, background 0.2s;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.aksrt-load-more-btn:hover {
|
|
border-color: var(--color-primary);
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.aksrt-load-more-btn:disabled {
|
|
opacity: 0.5;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.aksrt-loading-indicator {
|
|
display: none;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 14px;
|
|
color: var(--color-ink-4);
|
|
}
|
|
|
|
.aksrt-loading-indicator i {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.aksrt-scroll-sentinel {
|
|
width: 100%;
|
|
height: 1px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* ========== 移动端/平板隐藏侧栏(与 legacy 一致:991px 以下隐藏) ========== */
|
|
@media (max-width: 991px) {
|
|
.content-layout__aside {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.content-layout__primary--cms {
|
|
min-width: 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
* Phase 2 — 侧栏 widget 内链接增强
|
|
* ============================================================ */
|
|
.content-layout__aside .widget a {
|
|
transition: color var(--dur-fast, 0.15s) var(--ease);
|
|
}
|
|
|
|
.content-layout__aside .widget a:hover {
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
/* ============================================================
|
|
* Phase 5 — 文章操作卡片增强
|
|
* ============================================================ */
|
|
|
|
/* ============================================================
|
|
* Phase 6 — 评论卡片容器
|
|
* ============================================================ */
|
|
.comments-card {
|
|
overflow: hidden;
|
|
}
|