From be12a3d60c928f6d8d07abddce8f23b679387eaa Mon Sep 17 00:00:00 2001 From: wuyupeng Date: Sun, 31 May 2026 22:00:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(hero):=20=E6=B6=88=E9=99=A4=E9=A6=96?= =?UTF-8?q?=E5=B1=8F=20slogan=20=E4=BA=8C=E6=AC=A1=E8=B7=B3=E5=8A=A8?= =?UTF-8?q?=E4=B8=8E=E5=8A=A0=E8=BD=BD=E9=97=AA=E7=83=81=EF=BC=8C=E5=8A=A0?= =?UTF-8?q?=E7=BA=B8=E8=89=B2=E9=81=AE=E7=BD=A9=E6=8A=A4=E5=8F=AF=E8=AF=BB?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i18n.applyTo() 原本对每个 [data-i18n] 元素无条件重写 innerHTML,即使 当前语言与静态内容一致也会重建 .hl-1/.hl-2,重新触发 heroRise 入场动画 (slogan 第二次跳)并引起整页 reflow(加载时闪一下)。新增 normMarkup 归一化比较:内容已一致则跳过重写,真正切换语言时仍照常更新。zh/en 首屏 实测从 128 个元素全部重写降到 0 次写入。 hero 文字与持续运动的 #stage canvas 之间无遮罩,星尘透过文字背后影响 可读性。新增 .hero-content::before 柔和纸色径向遮罩(z-index:-1,夹在 canvas 与文字之间),提升对比度,边缘仍透出星尘,动效完整保留。 Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/githire.css | 16 ++++++++++++++++ docs/i18n.js | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/docs/githire.css b/docs/githire.css index 443c91c..6d4baf9 100644 --- a/docs/githire.css +++ b/docs/githire.css @@ -366,6 +366,22 @@ main, .topnav, .site-foot { position: relative; z-index: 1; } text-align: center; padding: 0 var(--gutter); } +/* Soft paper scrim between the moving canvas and the text. Sits inside the + hero's stacking context (so it's above the z-0 canvas) but behind the copy, + lifting legibility while the starfield still reads through at the edges. */ +.hero-content::before{ + content: ""; + position: absolute; + inset: -10% -8%; + z-index: -1; + pointer-events: none; + background: radial-gradient( + ellipse 76% 66% at 50% 47%, + rgba(246, 241, 232, 0.85) 0%, + rgba(246, 241, 232, 0.66) 40%, + rgba(246, 241, 232, 0) 76% + ); +} .hero-title{ font-family: var(--font-serif); font-weight: 500; diff --git a/docs/i18n.js b/docs/i18n.js index b1331e7..93769b3 100644 --- a/docs/i18n.js +++ b/docs/i18n.js @@ -937,6 +937,14 @@ return 'en'; } + // Normalize markup for comparison only: collapse insignificant whitespace + // and drop the self-closing slash on void elements. The browser serializes + // `
` as `
`, so without this the dictionary source (which writes + // `
`) would never match the DOM and we'd re-render needlessly. + function normMarkup(s) { + return s.replace(/\s+/g, ' ').replace(/\s*\/>/g, '>').trim(); + } + function applyTo(root, lang) { var els = root.querySelectorAll('[data-i18n]'); for (var i = 0; i < els.length; i++) { @@ -944,6 +952,13 @@ var key = el.getAttribute('data-i18n'); var entry = T[key]; if (!entry || typeof entry[lang] !== 'string') continue; + // Skip the swap when the element already renders this exact markup. + // The page ships in its own language, so on first load every value + // already matches — re-setting innerHTML would needlessly reflow the + // page and restart the hero's CSS entrance animation, making the + // slogan visibly "jump" a second time. Comparison only; a mismatch + // (a real language switch) still updates as before. + if (normMarkup(el.innerHTML) === normMarkup(entry[lang])) continue; el.innerHTML = entry[lang]; }