diff --git a/src/content/posts/how-i-made-my-own-songs-with-suno-ai.md b/src/content/posts/how-i-made-my-own-songs-with-suno-ai.md
index 248fc7c..ed54315 100644
--- a/src/content/posts/how-i-made-my-own-songs-with-suno-ai.md
+++ b/src/content/posts/how-i-made-my-own-songs-with-suno-ai.md
@@ -88,7 +88,7 @@ Publitio) and embedded with plain HTML5 audio. Press play:
@@ -297,8 +297,11 @@ document.querySelectorAll('audio[data-lrc]').forEach((audio) => {
if (cur >= 0) {
const p = box.children[cur];
p.classList.add('on');
- // scroll the lyric box only (scrollIntoView would drag the whole page)
- box.scrollTo({ top: p.offsetTop - box.clientHeight / 2 + p.offsetHeight / 2, behavior: 'smooth' });
+ // centre the active line inside the box. Use rect deltas, NOT offsetTop:
+ // offsetTop is measured from the nearest *positioned* ancestor, so without
+ // position:relative on the box it is huge and scrollTop clamps to the bottom.
+ const br = box.getBoundingClientRect(), pr = p.getBoundingClientRect();
+ box.scrollTop += (pr.top - br.top) - (box.clientHeight - pr.height) / 2;
} else {
box.scrollTop = 0; // back to the top before the first line
}
diff --git a/src/content/posts/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md b/src/content/posts/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
index 283025f..cc4b1e4 100644
--- a/src/content/posts/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
+++ b/src/content/posts/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
@@ -227,7 +227,7 @@ against the written lyrics, since the model emits no timestamps.
@@ -961,8 +961,11 @@ document.querySelectorAll('audio[data-lrc]').forEach((audio) => {
if (cur >= 0) {
const p = box.children[cur];
p.classList.add('on');
- // scroll the lyric box only (scrollIntoView would drag the whole page)
- box.scrollTo({ top: p.offsetTop - box.clientHeight / 2 + p.offsetHeight / 2, behavior: 'smooth' });
+ // centre the active line inside the box. Use rect deltas, NOT offsetTop:
+ // offsetTop is measured from the nearest *positioned* ancestor, so without
+ // position:relative on the box it is huge and scrollTop clamps to the bottom.
+ const br = box.getBoundingClientRect(), pr = p.getBoundingClientRect();
+ box.scrollTop += (pr.top - br.top) - (box.clientHeight - pr.height) / 2;
} else {
box.scrollTop = 0; // back to the top before the first line
}
diff --git a/src/content/posts/zh/how-i-made-my-own-songs-with-suno-ai.md b/src/content/posts/zh/how-i-made-my-own-songs-with-suno-ai.md
index 2d8e987..b43e670 100644
--- a/src/content/posts/zh/how-i-made-my-own-songs-with-suno-ai.md
+++ b/src/content/posts/zh/how-i-made-my-own-songs-with-suno-ai.md
@@ -74,7 +74,7 @@ v6 家族新增的控制功能,直接改变了我做事的方式:
@@ -276,8 +276,11 @@ document.querySelectorAll('audio[data-lrc]').forEach((audio) => {
if (cur >= 0) {
const p = box.children[cur];
p.classList.add('on');
- // scroll the lyric box only (scrollIntoView would drag the whole page)
- box.scrollTo({ top: p.offsetTop - box.clientHeight / 2 + p.offsetHeight / 2, behavior: 'smooth' });
+ // centre the active line inside the box. Use rect deltas, NOT offsetTop:
+ // offsetTop is measured from the nearest *positioned* ancestor, so without
+ // position:relative on the box it is huge and scrollTop clamps to the bottom.
+ const br = box.getBoundingClientRect(), pr = p.getBoundingClientRect();
+ box.scrollTop += (pr.top - br.top) - (box.clientHeight - pr.height) / 2;
} else {
box.scrollTop = 0; // back to the top before the first line
}
diff --git a/src/content/posts/zh/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md b/src/content/posts/zh/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
index 8367626..1ab694f 100644
--- a/src/content/posts/zh/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
+++ b/src/content/posts/zh/yue2-on-a-12gb-gpu-songs-that-lost-their-endings.md
@@ -172,7 +172,7 @@ clean = "\n".join(l for l in raw.split("\n")
@@ -906,8 +906,11 @@ document.querySelectorAll('audio[data-lrc]').forEach((audio) => {
if (cur >= 0) {
const p = box.children[cur];
p.classList.add('on');
- // scroll the lyric box only (scrollIntoView would drag the whole page)
- box.scrollTo({ top: p.offsetTop - box.clientHeight / 2 + p.offsetHeight / 2, behavior: 'smooth' });
+ // centre the active line inside the box. Use rect deltas, NOT offsetTop:
+ // offsetTop is measured from the nearest *positioned* ancestor, so without
+ // position:relative on the box it is huge and scrollTop clamps to the bottom.
+ const br = box.getBoundingClientRect(), pr = p.getBoundingClientRect();
+ box.scrollTop += (pr.top - br.top) - (box.clientHeight - pr.height) / 2;
} else {
box.scrollTop = 0; // back to the top before the first line
}