Files
wordpress-theme-aksrt/assets/css/frontend/post-card.css
T
kate522andClaude Fable 5 20fde1d652 fix(skeleton): put the widget gutter relief on the skeleton's inner item
小工具(首页挂载的 / 侧栏的)骨架加载占位比真实卡片窄一截:card 布局下
每侧窄 8px,视觉上就是「骨架小了一些」。

小工具的卡片走 skip_wrapper=true,直接挂在 .widget-ajaxpager 上
(src/WidgetSystem/PostRenderer.php),不经过 .posts-row,因此只受小工具
这条独立的负边距链作用:

  .widget-ajaxpager            margin: -8px
  .posts-item.card(真实卡片)  margin: 8px   ← 卡片自身自带
  .post_ajax_loader(外层)     margin: 8px   ← f61142ee 加的补偿
  .posts-item.card(骨架内层)  margin: 8px   ← 同一条卡片规则

骨架于是拿到 8px(外层 loader)+ 8px(内层卡片)= 16px,而真实卡片只有
8px,内容区每侧少 8px。list 模式没暴露是因为 .posts-item 的 8px 来自
`.widget-main-post.style-list .posts-item`,该规则只覆盖 style-list、
不作用于骨架,外层的 8px 恰好补上 list 卡片应有的一份,刚好对齐。

修法:把水平补偿从外层 .post_ajax_loader 移到骨架内层的 .posts-item /
.posts-mini —— 与真实卡片同一个元素、同一条选择器,于是两者逐像素同宽,
也顺带回答了「补偿链的拥有者是谁」这个一直在打补丁的问题。

- assets/css/main.css、assets/css/frontend/post-card.css:.posts-row 与
  .widget-ajaxpager 两条链、桌面 8px 与移动 5px 两组,共 8 处规则改为
  内层选择器。
- assets/css/routes/user-home.css:面板归零规则同步改到内层,否则它归零
  的是已经失效的外层,旧补偿会重新显形。
- tests/widget-system/asset-ledger-contract.test.cjs:把守卫断言改成内层
  选择器,并修正规则匹配以支持选择器组(.posts-item, .posts-mini)。
  注释说明为何不能补偿外层。

参考主题 zibll 完全没有 .post_ajax_loader 的 margin 规则;AKSRT 需要它,
是因为骨架多包了一层。定位在内层是与参考主题等价的正确解。

Verification:
- node tests/widget-system/asset-ledger-contract.test.cjs  16/16
- node tests/widget-system/post-visual-contract.test.cjs   22/22
- node tests/widget-system/zibll-modern-widgets-contract.test.cjs 10/10
- node tests/widget-system/lazyload-contract.test.cjs      7/7
- node tests/widget-system/frontend-lifecycle-contract.test.cjs 13/13
- node tests/widget-system/page-display-contract.test.cjs  18/18
- node tests/widget-system/message-center-contract.test.cjs 8/8
- php tools/audit-admin-contracts.php  errors=0
- build:public 已重建;旧外层规则在源与产物中均已归零

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-04 04:07:19 +08:00

657 lines
13 KiB
CSS

/**
* legacy 9.0 article list/card contract.
* Source baseline: css/main.css (SHA-256 recorded in tests/visual).
*/
.posts-row {
margin-right: -8px;
margin-bottom: 15px;
margin-left: -8px;
}
.posts-row > *:not(.post_ajax_loader) {
margin-right: 8px !important;
margin-left: 8px !important;
}
/* 骨架与真实卡片同宽:.posts-row 以 -8px 抵消卡片边距,loader 被上面的
:not() 排除在补偿外,会宽出 16px;这里补上等同的水平边距。
补偿落在骨架内层的 .posts-item 上(与真实卡片同一元素),不落外层
.post_ajax_loader —— 否则内层 .posts-item.card 的 margin:8px 会与外层
补偿叠成 16px,小工具 card 骨架因此窄出 8px。 */
.posts-row > .post_ajax_loader .posts-item,
.posts-row > .post_ajax_loader .posts-mini {
margin-right: 8px;
margin-left: 8px;
}
.posts-item {
margin: 15px 0;
padding: 20px;
overflow: hidden;
background: var(--main-bg-color, #fff);
border-radius: var(--main-radius, 8px);
box-shadow: 0 0 10px var(--main-shadow, rgba(116, 116, 116, 0.08));
transition: 0.2s;
}
.posts-item.flex,
.posts-item .flex,
.posts-mini .flex {
display: flex;
}
.posts-item .flex.xx,
.posts-mini .flex.xx {
flex-direction: column;
}
.posts-item .flex.ac,
.posts-mini .flex.ac {
align-items: center;
}
.posts-item .flex.jsb,
.posts-mini .flex.jsb {
justify-content: space-between;
}
.posts-item .flex1,
.posts-mini .flex1 {
flex: 1;
overflow: hidden;
}
.posts-item .post-graphic:not(.order1) {
margin-right: 20px;
}
.posts-item .order1.post-graphic {
margin-right: 0;
margin-left: 20px;
}
.posts-item .item-thumbnail {
position: relative;
display: block;
width: 190px;
height: 0;
padding-bottom: var(--posts-list-scale, 70%);
overflow: hidden;
border-radius: var(--main-radius, 8px);
}
.item-thumbnail.contain img {
object-fit: contain;
}
.swiper-slide.gradient-bg .dplayer-poster img,
.swiper-slide.gradient-bg > * > img {
object-fit: contain !important;
border-radius: 0 !important;
}
.item-thumbnail .swiper-wrapper {
height: 100% !important;
}
.list .item-thumbnail .aksrt-slider,
.list .item-thumbnail.new-swiper {
position: absolute;
width: 100%;
height: 100%;
margin: 0 !important;
}
.item-thumbnail .dplayer.dplayer-thumb {
position: absolute;
inset: 0;
z-index: 1;
padding-bottom: var(--posts-list-scale, 70%);
background: #000;
opacity: 0;
transition: opacity 0.3s;
}
.card .item-thumbnail .dplayer.dplayer-thumb {
padding-bottom: var(--posts-card-scale, 70%);
}
.item-thumbnail .dplayer-thumb video,
.item-thumbnail .swiper-wrapper,
.item-thumbnail img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.item-thumbnail .swiper-pagination {
right: 0 !important;
bottom: 0 !important;
left: 0 !important;
padding: 0 2px !important;
text-align: center !important;
}
.posts-item.thumb-dplayer-playing .dplayer-thumb {
opacity: 1;
}
.posts-item.thumb-dplayer-playing .abs-center {
opacity: 0;
}
.posts-item .item-heading {
display: -webkit-box;
max-height: 2.8em;
margin-top: 0;
margin-bottom: 5px;
overflow: hidden;
font-size: 18px;
line-height: 1.4em;
white-space: normal;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.font-bold {
font-weight: 700;
}
.list.style2 .item-thumbnail {
width: 130px;
}
.list.style2 .item-heading {
display: unset;
max-height: 1.4em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.posts-item .item-heading > a {
color: var(--key-color, #333);
}
.posts-item .item-heading > a:hover {
color: var(--focus-color, #f04494);
}
.posts-item .item-excerpt {
margin: 0 0 6px;
overflow: hidden;
color: var(--muted-color, #777);
text-overflow: ellipsis;
white-space: nowrap;
}
.posts-item .item-meta item {
margin-right: 8px;
font-size: 13px;
}
.posts-item .item-meta svg.icon,
.posts-mini .item-meta svg.icon {
display: inline-block;
width: 1em;
height: 1em;
margin-right: 2px;
fill: currentColor;
overflow: hidden;
vertical-align: -0.15em;
}
.posts-item .meta-right item:last-child {
margin-right: 0;
}
.item-meta .avatar-mini {
width: 20px;
height: 20px;
border-radius: 50%;
transform: translateY(-1px);
}
.item-meta .meta-pay {
padding: 0 4px;
}
.item-meta .meta-pay img {
width: 1em;
height: 1em;
object-fit: contain;
vertical-align: -0.15em;
}
.posts-item .item-meta a,
.posts-mini .item-meta a {
color: inherit;
}
.posts-item .item-tags a {
margin-right: 5px;
padding: 2px 5px;
font-size: 11px;
}
.posts-item .item-tags a .fa {
font-size: 1em;
}
.posts-item.card {
display: inline-block;
width: calc(33.333% - 16px);
margin: 8px;
padding: 10px;
vertical-align: top;
transition: 0.3s;
}
.posts-item.card:last-child {
margin-bottom: 20px;
}
.posts-item.card .item-body {
width: 100%;
margin: 10px 0 0;
padding: 0;
}
.posts-item.card .item-meta item {
font-size: 12px;
}
.posts-mini-con .item-heading,
.posts-item.card .item-heading {
font-size: 14px;
}
.posts-item.card .item-heading {
min-height: 2.8em;
}
.posts-item.card .item-tags {
min-height: 23px;
}
.posts-item.card .item-thumbnail {
width: 100%;
padding-bottom: var(--posts-card-scale, 70%);
}
.posts-item.card.style2 {
background: transparent;
box-shadow: none;
}
.posts-item.card.style2:hover {
background: var(--main-bg-color, #fff);
box-shadow: 0 0 10px var(--main-shadow, rgba(116, 116, 116, 0.08));
}
.posts-item.card.style3 {
padding: 0;
}
.posts-item.card.style3 .item-thumbnail,
.posts-item.card.style3 .item-thumbnail img {
border-radius: var(--main-radius, 8px) var(--main-radius, 8px) 0 0;
}
.posts-item.card.style3 .item-body {
margin: 0;
padding: 10px;
}
.posts-item.mult-thumb .thumb-items {
margin: 0 -3px 6px;
}
.posts-item.mult-thumb .thumb-items > span {
position: relative;
display: inline-block;
width: calc(25% - 6px);
height: 0;
margin: 0 3px;
padding-bottom: calc(var(--posts-list-scale, 70%) / 4);
}
.posts-item.mult-thumb .thumb-items > span > img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.posts-item.mult-thumb .thumb-items.contain > span {
overflow: hidden;
background: var(--main-border-color, rgba(50, 50, 50, 0.06));
border-radius: var(--main-radius, 8px);
}
.posts-item.mult-thumb .thumb-items.contain > span > img {
object-fit: contain;
border-radius: 0;
}
.posts-item.no_margin {
margin: 0;
border-radius: 0;
box-shadow: none;
}
.posts-item.no-thumb .item-excerpt {
height: auto;
}
.posts-item.no-thumb .item-body {
width: 100%;
}
.posts-item + .pagenav {
margin-top: -15px;
}
.posts-item.card + .pagenav {
margin-top: -10px;
}
.no_margin:first-of-type {
margin-top: 10px;
border-radius: var(--main-radius, 8px) var(--main-radius, 8px) 0 0;
}
.no_margin:last-of-type {
margin-bottom: 15px;
border-radius: 0 0 var(--main-radius, 8px) var(--main-radius, 8px);
}
.posts-mini {
padding: 10px;
display: inline-flex;
width: 50%;
vertical-align: top;
}
.posts-mini-con {
flex: auto;
overflow: hidden;
}
.posts-mini .item-thumbnail {
width: 96px;
height: 0;
padding-bottom: var(--posts-list-scale, 70%);
position: relative;
overflow: hidden;
border-radius: var(--main-radius, 8px);
}
.posts-mini .item-thumbnail img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.posts-mini .item-heading {
margin: 0;
}
.posts-mini .item-heading.icon-circle {
margin-left: -5px;
}
.posts-mini .item-meta {
font-size: 12px;
}
.posts-mini-con .badg {
min-width: 18px;
}
.sidebar .posts-mini,
.mobile-nav-widget .posts-mini {
width: 100% !important;
}
.mobile-nav-widget .posts-mini {
padding-right: 0;
padding-left: 0;
}
.posts-mini:last-of-type {
margin-bottom: 0;
}
.posts-mini-lists {
padding: 5px;
}
.posts-mini-lists .tab-nav-theme {
padding: 0 5px 2px;
}
.mobile-nav-widget .posts-mini-lists .tab-nav-theme {
margin: 0 -5px;
padding: 0;
}
.widget-main-post.style-list .widget-ajaxpager,
.widget-main-post.style-card .widget-ajaxpager,
.widget-tab-post.index-tab .tab-content > .tab-pane {
margin: -8px -8px 15px;
}
.widget-tab-post.style-list .tab-content > .tab-pane {
margin-bottom: 25px;
}
.widget-main-post.style-list .posts-item,
.widget-tab-post.style-list .posts-item {
margin-right: 8px;
margin-left: 8px;
}
/* 骨架与卡片同宽同轴:.widget-ajaxpager / .tab-pane 用负边距抵消卡片的水平
边距。补偿同样落在骨架内层的 .posts-item 上(与真实卡片同一元素),
不落外层 .post_ajax_loader —— 否则内层 .posts-item.card 自带的 margin:8px
会与外层补偿叠成 16px,card 骨架因此窄出 8px。 */
.widget-main-post.style-list .widget-ajaxpager > .post_ajax_loader .posts-item,
.widget-main-post.style-card .widget-ajaxpager > .post_ajax_loader .posts-item,
.widget-tab-post .tab-content > .tab-pane > .widget-ajaxpager > .post_ajax_loader .posts-item {
margin-right: 8px;
margin-left: 8px;
}
.posts-mini:hover img,
.posts-item:hover .item-thumbnail img,
.posts-item.mult-thumb .thumb-items > span > img:hover {
transform: scale(1.02);
}
.swiper-scroll .posts-item {
flex-shrink: 0;
margin: 0 16px 0 0 !important;
}
.swiper-scroll .posts-item.list {
width: calc(50% - 8px) !important;
min-width: 520px !important;
}
.swiper-scroll .posts-item.posts-mini {
width: 360px !important;
}
.swiper-scroll .posts-item.card {
width: calc(33.333% - 11px) !important;
}
/* img-badge 定位由 main.css 的参考主题规则拥有(.img-badge top:.6em /
* .img-badge.left left:0 / .hot-posts .img-badge left:-15px)。
* 此前这里存在 top:8px/left:8px 的全局覆盖,导致热榜 TOP 徽章与参考主题错位。 */
@media (min-width: 992px) {
.fluid-widget-wrap .posts-item.card,
.site-layout-1 .posts-item.card {
width: calc(25% - 16px);
}
.fluid-widget-wrap .posts-item:not(.card),
.site-layout-1 .posts-item:not(.card) {
display: inline-flex;
width: calc(50% - 16px);
margin: 8px;
}
.fluid-widget-wrap .posts-item.no_margin,
.site-layout-1 .posts-item.no_margin {
border-radius: var(--main-radius, 8px);
}
.fluid-widget-wrap .posts-mini,
.site-layout-1 .posts-mini {
width: 33.333%;
}
.sidebar .posts-item.card,
.sidebar .posts-item.list {
width: 100% !important;
min-width: 0 !important;
margin: 0;
}
}
@media (max-width: 767px) {
.posts-row {
margin-right: -5px;
margin-left: -5px;
}
.posts-row > *:not(.post_ajax_loader) {
margin-right: 5px !important;
margin-left: 5px !important;
}
.posts-row > .post_ajax_loader .posts-item,
.posts-row > .post_ajax_loader .posts-mini {
margin-right: 5px;
margin-left: 5px;
}
.posts-item .item-thumbnail {
width: 138px;
}
.posts-mini .item-thumbnail,
.list.style2 .item-thumbnail {
width: 90px;
}
.posts-item .post-graphic:not(.order1) {
margin-right: 15px;
}
.posts-item .order1.post-graphic {
margin-left: 15px;
}
.posts-item .item-heading {
font-size: 15px;
}
.posts-item:not(.no-thumb) .item-excerpt {
display: none;
}
.posts-item.card {
width: calc(50% - 10px);
margin: 5px;
}
.widget-main-post.style-list .widget-ajaxpager,
.widget-main-post.style-card .widget-ajaxpager,
.widget-tab-post.index-tab .tab-content > .tab-pane {
margin: -5px -5px 20px;
}
.widget-tab-post.style-list .tab-content > .tab-pane,
.widget-main-post.style-list .widget-ajaxpager {
margin-top: -15px;
}
.widget-tab-post.style-list .posts-item {
margin-right: 5px;
margin-left: 5px;
}
.widget-main-post.style-list .widget-ajaxpager > .post_ajax_loader .posts-item,
.widget-main-post.style-card .widget-ajaxpager > .post_ajax_loader .posts-item,
.widget-tab-post .tab-content > .tab-pane > .widget-ajaxpager > .post_ajax_loader .posts-item {
margin-right: 5px;
margin-left: 5px;
}
.swiper-scroll .posts-item {
margin-right: 10px !important;
}
.posts-item.card:nth-child(odd) {
margin-right: 5px;
}
.posts-item.card:nth-child(even) {
margin-left: 5px;
}
.posts-item.mult-thumb .thumb-items > span {
width: calc(33.333% - 6px);
padding-bottom: calc(var(--posts-list-scale, 70%) / 3);
}
.posts-item.mult-thumb .thumb-items > span:nth-child(4) {
display: none;
}
.swiper-scroll .posts-item.card {
width: calc(50% - 5px) !important;
}
.swiper-scroll .posts-item.list {
width: 100% !important;
min-width: auto !important;
}
}
@media (max-width: 640px) {
.posts-item:not(.no-thumb) .meta-right item {
display: none;
}
.posts-mini {
width: 100%;
}
.posts-item {
margin: 10px 0;
padding: 10px;
}
.aksrt-panel .posts-item.no_margin {
padding: 10px 0;
}
}
@media (prefers-reduced-motion: reduce) {
.posts-item,
.posts-item img {
transition: none;
}
}