修复: 回到顶部按钮和进度条不显示的bug
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"updatedAt": "2026-09-21T01:32:16.851Z",
|
||||
"updatedAt": "2026-09-21T01:46:31.327Z",
|
||||
"source": "weread",
|
||||
"books": [
|
||||
{
|
||||
|
||||
@@ -7,16 +7,31 @@ import { onPage } from "./lifecycle"
|
||||
* 淡入,不需要任何 scroll 监听(见 global.css 的 .back-to-top)。
|
||||
* 这里只负责两件事:
|
||||
* 1. 点击后平滑回到顶部;
|
||||
* 2. 给不支持滚动驱动动画的浏览器(Firefox < 144 / Safari < 26)做降级。
|
||||
* 2. 兜住「CSS 那条动画没生效」的所有情况 —— 既包括不支持滚动驱动动画的浏览器
|
||||
* (Firefox < 144 / Safari < 26),也包括规则被构建压缩弄坏的情况(见下)。
|
||||
*/
|
||||
|
||||
/** 与 global.css 里 animation-range 的起点保持一致 */
|
||||
/** 与 global.css 里 animation-range 的起点呼应 */
|
||||
const REVEAL_AFTER_PX = 480
|
||||
|
||||
const supportsScrollTimeline = () =>
|
||||
typeof CSS !== "undefined" &&
|
||||
typeof CSS.supports === "function" &&
|
||||
CSS.supports("animation-timeline: scroll()")
|
||||
/** global.css 中 @keyframes 的名字,用来实测动画有没有真的挂上 */
|
||||
const ANIMATION_NAME = "back-to-top-reveal"
|
||||
|
||||
/**
|
||||
* 「CSS 那条滚动驱动动画到底有没有生效」——直接读计算样式,而不是做特性检测。
|
||||
*
|
||||
* 为什么不用 CSS.supports("animation-timeline: scroll()"):它只回答「这个语法浏览器认不认」,
|
||||
* 回答不了「这条规则有没有在构建压缩中活下来」。实际的坑是:Lightning CSS 会把
|
||||
* animation-timeline 合并进 animation 简写,而 WebKit 不认简写里的 timeline 分量,
|
||||
* 整条声明被丢弃 —— 此时 CSS.supports 仍然返回 true,于是降级分支永远不执行,
|
||||
* 按钮就永远停在 opacity:0。改读 animationName 之后,CSS 那边无论因为什么原因没生效,
|
||||
* 这里都能立刻发现并接管(详见 global.css 里 .back-to-top 的注释)。
|
||||
*/
|
||||
const cssDrivesVisibility = (button: HTMLElement) =>
|
||||
window
|
||||
.getComputedStyle(button)
|
||||
.animationName.split(",")
|
||||
.some((part) => part.trim() === ANIMATION_NAME)
|
||||
|
||||
onPage("back-to-top", () => {
|
||||
const button = document.querySelector<HTMLElement>("[data-back-to-top]")
|
||||
@@ -28,7 +43,7 @@ onPage("back-to-top", () => {
|
||||
}
|
||||
button.addEventListener("click", onClick)
|
||||
|
||||
if (supportsScrollTimeline()) {
|
||||
if (cssDrivesVisibility(button)) {
|
||||
return () => button.removeEventListener("click", onClick)
|
||||
}
|
||||
|
||||
|
||||
+33
-1
@@ -1142,6 +1142,18 @@ a.card-github:hover .github-logo {
|
||||
@supports (animation-timeline: scroll()) {
|
||||
.reading-progress-bar {
|
||||
animation: reading-progress-grow linear both;
|
||||
}
|
||||
/*
|
||||
* ⚠️ 这条规则的选择器故意比上面多一层 `.reading-progress >`,不是笔误。
|
||||
*
|
||||
* Lightning CSS 会合并「相邻且选择器完全相同」的规则:把 animation-timeline 并进
|
||||
* 上面那条的 animation 简写,产物变成 `animation: … reading-progress-grow scroll(root)`,
|
||||
* 而 WebKit 不认简写里的 timeline 分量,整条声明被丢弃 → 进度条永远 scaleX(0)。
|
||||
* 选择器不同就没法合并。这里用后代选择器而不是 `:where()`,是为了让特异性**不低于**
|
||||
* 上面那条 —— animation 简写会把 animation-timeline 重置回 auto,特异性更低会被重置压掉。
|
||||
* 完整背景见下面 .back-to-top 段的长注释,以及 scripts/verify-build-css.mjs。
|
||||
*/
|
||||
.reading-progress > .reading-progress-bar {
|
||||
animation-timeline: scroll(root block);
|
||||
}
|
||||
}
|
||||
@@ -1229,8 +1241,28 @@ a.card-github:hover .github-logo {
|
||||
/* 显隐交给滚动时间线,这里只留下颜色类过渡 */
|
||||
transition: color 160ms ease, background-color 160ms ease, border-color 160ms ease;
|
||||
animation: back-to-top-reveal linear both;
|
||||
}
|
||||
/*
|
||||
* ⚠️⚠️ animation-timeline / animation-range 必须写在**独立的规则块**里,
|
||||
* 不能和上面的 animation 简写放在同一组声明中。
|
||||
*
|
||||
* Lightning CSS(Tailwind v4 用的 CSS 压缩器)会把同一组声明里的 animation-timeline
|
||||
* 合并进 animation 简写,构建产物变成:
|
||||
* animation: linear both back-to-top-reveal scroll(root)
|
||||
* 而 WebKit 目前不接受简写里的 <single-animation-timeline> 分量(webkit#293276),
|
||||
* 于是**整条 animation 声明被判无效并丢弃** —— 按钮永远停在 opacity:0 /
|
||||
* visibility:hidden。更坑的是 CSS.supports("animation-timeline: scroll()") 依然返回
|
||||
* true,纯特性检测完全看不出问题;dev 模式不做这个压缩,所以只有构建产物会踩到。
|
||||
* 参考 lightningcss#815。scripts/verify-build-css.mjs 会在构建后拦截这种合并回退。
|
||||
*
|
||||
* ⚠️ 所以这条规则的选择器故意写成 `.back-to-top[data-back-to-top]`(多一个属性选择器)
|
||||
* —— 与上面那条选择器不同,压缩器就无法把它们合并。刻意用属性选择器而不是 :where(),
|
||||
* 是为了让特异性**高于**上面那条:animation 简写会把 animation-timeline 重置回 auto,
|
||||
* 特异性持平或更低都会被那个重置压掉。
|
||||
*/
|
||||
.back-to-top[data-back-to-top] {
|
||||
animation-timeline: scroll(root block);
|
||||
/* 滚过 320px 开始淡入,620px 完全就位(与 back-to-top.ts 的 480px 阈值呼应) */
|
||||
/* 滚过 320px 开始淡入,620px 完全就位(与 back-to-top.ts 的降级阈值呼应) */
|
||||
animation-range: 320px 620px;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user