fix(single): fill slide and video cover media like the image cover

Slide-mode images rendered at intrinsic ratio, top-aligned inside the
swiper chain (--pc-height:auto left .swiper-wrapper content-sized), so
the taller box showed a gap at the bottom and never center-cropped like
the image cover. The video cover had the same problem through
video-player.js (height:auto, capped at 70vh).

- aksrt_render_slider scale mode emits --pc-height/--m-height 100% so
  the wrapper/slide/img chain fills the ratio box and object-fit: cover
  center-crops inside it (same pattern as the .scale-height widgets)
- video-player.js renders the video at height:100% + object-fit:cover;
  with an undimensioned container height:100% degrades to auto,
  matching the previous behavior
- drop the dead .single-cover padding-bottom rules (every producer owns
  its height inline, and the rule squeezed the absolutely positioned
  slide inner) and the orphaned --single-cover-scale var in
  tokens.css/compat-vars.css/main.css/InlineStyleBuilder
- rebuild public bundles; extend the single-cover-height contract
This commit is contained in:
2026-09-05 18:53:45 +08:00
parent 9fa7190232
commit d86147f406
11 changed files with 67 additions and 19 deletions
@@ -68,14 +68,66 @@ test('single cover: the dead static slide fallback is gone', () => {
);
});
test('slider scale mode: inner swiper carries no dead inline height styles', () => {
test('slider scale mode: completes the definite height chain for cover cropping', () => {
assert.doesNotMatch(
sliderHelper,
/--scale-ratio/,
'--scale-ratio 无任何 CSS 消费方,禁止输出'
);
const scaleMode = sliderHelper.split("if ($args['scale_height']) {")[1] || '';
assert.ok(scaleMode.includes("position:absolute;inset:0;width:100%;height:100%;"));
// wrapper 决定盒子高度;pc/m-height 100% 让 .swiper-wrapper/.swiper-slide
// 铺满比例盒,使 object-fit: cover 在确定的盒内居中裁切(对齐单图封面)。
assert.match(
sliderHelper,
/\$height_style = '--pc-height:100%;--m-height:100%;';/
);
assert.match(
sliderHelper,
/esc_attr\(\$height_style \. \(\$args\['scale_height'\] \? 'position:absolute;inset:0;width:100%;height:100%;' : ''\)\)/,
'内层 .new-swiper 必须绝对定位铺满 wrapper'
);
});
test('video cover: the player video fills and center-crops like the image cover', () => {
const player = read('assets/js/video-player.js');
assert.match(
player,
/\.aksrt-video video\{display:block;width:100%;height:100%;object-fit:cover;\}/,
'视频必须铺满封面比例盒并居中裁切'
);
assert.doesNotMatch(
player,
/max-height:70vh/,
'封面盒高度由比例盒决定,不得再套 70vh 截断'
);
});
test('single cover css owns no fallback padding and the scale var is gone', () => {
for (const file of [
'assets/css/frontend/single-post/cover.css',
'assets/css/main.css',
'assets/css/main.min.css',
'assets/css/core/tokens.css',
'assets/css/frontend/compat-vars.css',
'assets/css/build/public.css',
'assets/css/build/public.min.css',
]) {
const css = read(file);
assert.doesNotMatch(
css,
/\.single-cover\s*\{[^}]*padding-bottom/,
`${file} 的 .single-cover 不得声明 padding-bottom(高度归内联样式)`
);
assert.doesNotMatch(
css,
/--single-cover-scale/,
`${file} 不得再包含孤儿变量 --single-cover-scale`
);
}
assert.doesNotMatch(
read('src/Frontend/InlineStyleBuilder.php'),
/--single-cover-scale/,
'运行时 CSS 变量不得再输出孤儿 --single-cover-scale'
);
});
test('dead cover css is removed from every stylesheet surface', () => {